文章目录
- 前言
- 一、什么是立方体纹理
- 二、立方体纹理的生成方式
- 1、使用6个面的生成方式
- 2、使用单张图片的生成方式
- 三、Cubemap的采样方式
- 四、在Unity中看一下Cubemap
- 五、在Shader中,对立方体纹理进行采样使用
- 1、我们在属性面板定义一个Cube类型的变量来存放立方体纹理
- 2、使用前在Pass中,声明一下该变量
- 3、在片元着色器中,对其纹理采样
- 4、模拟真实的反射效果 (Cubemap的环境映射)
- 5、计算视线的反射向量
- 六、最终效果
前言
Unity中Shader立方体纹理Cubemap
一、什么是立方体纹理
立方体纹理,也被叫做Cubemap。通常用来做反射效果
在Unity中,如果全都使用实时反射,那么对于设备性能的消耗是比较大的,所以使用一种投机取巧的方式实现的反射效果
二、立方体纹理的生成方式
1、使用6个面的生成方式
一般选择Auto即可,会自动适配
2、使用单张图片的生成方式
一般选择Auto即可,会自动适配
三、Cubemap的采样方式
由模型顶点向Cubemap发射射线,射线经过的Cubemap哪个点,那个点就是采样点
四、在Unity中看一下Cubemap
在纹理的 Inspector,按如下设置,就可以把普通纹理类型修改为立方体纹理
五、在Shader中,对立方体纹理进行采样使用
我们使用上一篇文章的Shader继续测试:
- Unity中Shader纹理的环绕方式
1、我们在属性面板定义一个Cube类型的变量来存放立方体纹理
_CubeMap(“CubeMap”,Cube) = “white” {}
2、使用前在Pass中,声明一下该变量
samplerCUBE _Cubemap;
3、在片元着色器中,对其纹理采样
这里进行纹理采样时,由其原理可知,需要使用顶点的本地坐标。
所以,这里使用 appdata 传入的顶点数据来采样即可。
- 我们先在 v2f 中定义一个变量来存储应用程序阶段传入的数据
我们只需要顶点的 xyz 即可
float3 localPos : TEXCOORD1;
- 然后,在顶点着色器阶段,把 appdata 的顶点 xyz 传给 v2f 中的 localPos
o.localPos = v.vertex.xyz;
- 返回一下采样的结果看看(已经有了采样的结果)
fixed4 cubemap = texCUBE(_CubeMap,i.localPos);
return cubemap;
4、模拟真实的反射效果 (Cubemap的环境映射)
要模拟出真实的反射效果,不能向之前一样,采样眼睛处的Cubemap
而是需要采样视线的反射视线经过Cubemap的点
5、计算视线的反射向量
因为需要计算视线的反射向量,所以需要准备一些数据:
摄像机的世界坐标、模型顶点的世界坐标、法线的世界坐标
- 准备摄像机的世界坐标
_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 100Pass{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_REPEATi.uv = frac(i.uv);#elif _WRAPMODE_CLAMP//法一://i.uv = clamp(i.uv,0,1);//法二:i.uv = saturate(i.uv);#endiffloat4 uvMipmap = fixed4(i.uv,0,_Mipmap);fixed4 col = tex2Dlod(_MainTex, uvMipmap);//Cubefixed4 cubemap = texCUBE(_CubeMap,i.localPos);//V,N,Rfixed3 V = normalize(i.worldPos - _WorldSpaceCameraPos);fixed3 N = normalize(i.worldNormal);fixed3 R = reflect(V,N);cubemap = texCUBE(_CubeMap,R);return cubemap;return col;}ENDCG}}
}