Unity中Shader立方体纹理Cubemap
立方体纹理,也被叫做Cubemap。通常用来做反射效果
在Unity中,如果全都使用实时反射,那么对于设备性能的消耗是比较大的,所以使用一种投机取巧的方式实现的反射效果
由模型顶点向Cubemap发射射线,射线经过的Cubemap哪个点,那个点就是采样点
在纹理的 Inspector,按如下设置,就可以把普通纹理类型修改为立方体纹理
我们使用上一篇文章的Shader继续测试:
_CubeMap(“CubeMap”,Cube) = “white” {}
samplerCUBE _Cubemap;
这里进行纹理采样时,由其原理可知,需要使用顶点的本地坐标。
所以,这里使用 appdata 传入的顶点数据来采样即可。
我们只需要顶点的 xyz 即可
float3 localPos : TEXCOORD1;
o.localPos = v.vertex.xyz;
fixed4 cubemap = texCUBE(_CubeMap,i.localPos);
return cubemap;
要模拟出真实的反射效果,不能向之前一样,采样眼睛处的Cubemap
而是需要采样视线的反射视线经过Cubemap的点
因为需要计算视线的反射向量,所以需要准备一些数据:
摄像机的世界坐标、模型顶点的世界坐标、法线的世界坐标
_WorldSpaceCameraPos
1、在 v2f 中,定义一个变量存储顶点的世界信息
float3 worldPos : TEXCOORD2;
2、在顶点着色器中,进行顶点坐标转化
o.worldPos = mul(unity_ObjectToWorld,v.vertex);
1、在 appdata 中传入法线信息
half3 normal : NORMAL;
2、在 v2f 中,定义一个变量存储法线世界坐标
half3 worldNormal : NORMAL;
3、在顶点着色器中,进行法线坐标转化
o.worldNormal = UnityObjectToWorldNormal(v.normal);
1、计算世界坐标下 视线单位向量 V
fixed3 V = normalize(i.worldPos - _WorldSpaceCameraPos);
2、计算世界坐标下 法线单位向量 N
fixed3 N = normalize(i.worldNormal);
3、计算世界坐标下 反射向量R
fixed3 R = reflect(V,N);
4、用 R 对Cubemap进行纹理采样
fixed4 cubemap = texCUBE(_CubeMap,R);
最终代码:
//纹理的多级渐远 Mipmap
//纹理的环绕方式
Shader "MyShader/P2_1_5"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
[KeywordEnum (Repeat,Clamp)]_WrapMode("WrapMode",int) = 0
[IntRange]_Mipmap ("Mipmap",Range(0,10)) = 0
//在属性面板定义立方体纹理
_CubeMap("CubeMap",Cube) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma shader_feature _WRAPMODE_REPEAT _WRAPMODE_CLAMP
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
half3 normal : NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 localPos : TEXCOORD1;
float3 worldPos : TEXCOORD2;
half3 worldNormal : NORMAL;
};
sampler2D _MainTex;
float4 _MainTex_ST;
half _Mipmap;
samplerCUBE _CubeMap;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.localPos = v.vertex.xyz;
o.worldPos = mul(unity_ObjectToWorld,v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
//WrapMode
#if _WRAPMODE_REPEAT
i.uv = frac(i.uv);
#elif _WRAPMODE_CLAMP
//法一:
//i.uv = clamp(i.uv,0,1);
//法二:
i.uv = saturate(i.uv);
#endif
float4 uvMipmap = fixed4(i.uv,0,_Mipmap);
fixed4 col = tex2Dlod(_MainTex, uvMipmap);
//Cube
fixed4 cubemap = texCUBE(_CubeMap,i.localPos);
//V,N,R
fixed3 V = normalize(i.worldPos - _WorldSpaceCameraPos);
fixed3 N = normalize(i.worldNormal);
fixed3 R = reflect(V,N);
cubemap = texCUBE(_CubeMap,R);
return cubemap;
return col;
}
ENDCG
}
}
}