文章目录
- 前言
- 一、什么是立方体纹理
- 二、立方体纹理的生成方式
- 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 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
}
}
}