法线贴图在之前学习过了,我们使用法线贴图在低分辨率的模型上模拟高分辨率的效果。Unity中通过 UnpackNormal 函数来使用法线贴图。这一篇就给大家介绍下在Cubemap上使用法线贴图,模拟凹凸效果。
最终效果如图:

一起来做吧。
首先搭建好场景,和上一节一样。
导入法线贴图
创建材质 、Shader 。
复制上一节的 Shader 就行。然后修改成下面的内容。
Shader "CookBookShaders/Chapt4-4/Cubemap_NormalMap"
{
Properties
{
_MainTint("Diffuse Color",Color)=(1,1,1,1)
_MainTex ("Base (RGB)", 2D) = "white" {}
_NormalMap("Normal Map",2D) = "bump"{}
_Cubemap("Cubemap",CUBE)=""{}
_ReflAmount("Reflection Amount",Range(0,1))=0.5
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
float4 _MainTint;
sampler2D _MainTex;
sampler2D _NormalMap;
samplerCUBE _Cubemap;
float _ReflAmount;
struct Input
{
float2 uv_MainTex;
float2 uv_NormalMap;
float3 worldRefl;
INTERNAL_DATA
};
void surf (Input IN, inout SurfaceOutput o)
{
half4 c = tex2D (_MainTex, IN.uv_MainTex);
//从法线贴图中提取法线信息,UnpackNormal这个函数在 CGInclude 文件夹中的Lighting中。
float3 normals=UnpackNormal(tex2D(_NormalMap,IN.uv_NormalMap));
o.Normal=normals;
//上面使用法线贴图中的法线数据 替代了 原来的法线数据。
//法线被修改了,就不能 直接用原来的 内置属性 worldRefl 这个反射向量,而是要通过 WorldReflectionVector(IN,o.Normal)来获取。
//使用WorldReflectionVector 获得 基于法线贴图中的反射向量的 世界反射向量
o.Emission = texCUBE(_Cubemap,WorldReflectionVector(IN,o.Normal)).rgb * _ReflAmount;
o.Albedo = c.rgb * _MainTint;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
和上一节的Shader 相比,修改了如下几处:1、在 Properties 属性块中添加了法线贴图
_NormalMap("Normal Map",2D) = "bump"{}
然后在 SubShader 中添加对应的变量sampler2D _NormalMap;
2、在 Input 中 添加了 法线贴图的UV,以及一个奇怪的字段 INTERNAL_DATA
struct Input
{
float2 uv_MainTex;
float2 uv_NormalMap;
float3 worldRefl;
INTERNAL_DATA
};
uv_NormalMap 是用来读取 法线贴图数据的。
INTERNAL_DATA
书上有两点解释
A:通过在Input 中添加 INTERNAL_DATA ,我们就可以访问由法线贴图修改后的表面法线。
这个很奇怪,为什么要添加 INTERNAL_DATA,才可以访问由法线贴图修改后的表面法线?上次学习法线贴图的时候可没有这个东西。
习惯性到 CGIncludes 里面去查找,发现并没有 INTERNAL_DATA 。
在官方文档:http://docs.unity3d.com/Manual/SL-SurfaceShaderExamples.html
找到这一句话If you want to do reflections that are affected by normal maps, it needs to be slightly more involved: INTERNAL_DATA
needs to be added to the Input structure, and WorldReflectionVector
function used to compute per-pixel reflection vector after you’ve written the Normal output.
就是说计算世界反射向量的时候 使用了法线贴图就要加上 这个。
谷歌一下,发现网友说在 生成的代码中能看出来,然后就查看生成的代码
- Shader "CookBookShaders/Chapt4-4/Cubemap_NormalMap"
- {
- Properties
- {
- _MainTint("Diffuse Color",Color)=(1,1,1,1)
- _MainTex ("Base (RGB)", 2D) = "white" {}
-
- _NormalMap("Normal Map",2D) = "bump"{}
-
- _Cubemap("Cubemap",CUBE)=""{}
-
- _ReflAmount("Reflection Amount",Range(0,1))=0.5
- }
-
- SubShader
- {
- Tags { "RenderType"="Opaque" }
- LOD 200
-
-
- // ------------------------------------------------------------
- // Surface shader code generated out of a CGPROGRAM block:
-
-
- // ---- forward rendering base pass:
- Pass {
- Name "FORWARD"
- Tags { "LightMode" = "ForwardBase" }
-
- CGPROGRAM
- // compile directives
- #pragma vertex vert_surf
- #pragma fragment frag_surf
- #pragma multi_compile_fwdbase
- #include "HLSLSupport.cginc"
- #include "UnityShaderVariables.cginc"
- #define UNITY_PASS_FORWARDBASE
- #include "UnityCG.cginc"
- #include "Lighting.cginc"
- #include "AutoLight.cginc"
-
- #define INTERNAL_DATA half3 TtoW0; half3 TtoW1; half3 TtoW2;
- #define WorldReflectionVector(data,normal) reflect (data.worldRefl, half3(dot(data.TtoW0,normal), dot(data.TtoW1,normal), dot(data.TtoW2,normal)))
- #define WorldNormalVector(data,normal) fixed3(dot(data.TtoW0,normal), dot(data.TtoW1,normal), dot(data.TtoW2,normal))
-
- // Original surface shader snippet:
- #line 18 ""
- #ifdef DUMMY_PREPROCESSOR_TO_WORK_AROUND_HLSL_COMPILER_LINE_HANDLING
- #endif
-
- //#pragma surface surf Lambert
-
- float4 _MainTint;
- sampler2D _MainTex;
-
- sampler2D _NormalMap;
-
- samplerCUBE _Cubemap;
-
- float _ReflAmount;
-
-
-
- struct Input
- {
- float2 uv_MainTex;
-
- float2 uv_NormalMap;
-
- float3 worldRefl;
-
- INTERNAL_DATA
- };
-
- void surf (Input IN, inout SurfaceOutput o)
- {
- half4 c = tex2D (_MainTex, IN.uv_MainTex);
-
- //从法线贴图中提取法线信息,UnpackNormal这个函数在 CGInclude 文件夹中的Lighting中。
- float3 normals=UnpackNormal(tex2D(_NormalMap,IN.uv_NormalMap));
-
- o.Normal=normals;
-
- //上面使用法线贴图中的法线数据 替代了 原来的法线数据。
-
- //法线被修改了,就不能 直接用原来的 内置属性 worldRefl 这个反射向量,而是要通过 WorldReflectionVector(IN,o.Normal)来获取。
-
- //使用WorldReflectionVector 获得 基于法线贴图中的反射向量的 世界反射向量
- o.Emission = texCUBE(_Cubemap,WorldReflectionVector(IN,o.Normal)).rgb * _ReflAmount;
-
- o.Albedo = c.rgb * _MainTint;
- o.Alpha = c.a;
- }
-
-
- // vertex-to-fragment interpolation data
- #ifdef LIGHTMAP_OFF
- struct v2f_surf {
- float4 pos : SV_POSITION;
- float4 pack0 : TEXCOORD0;
- fixed4 TtoW0 : TEXCOORD1;
- fixed4 TtoW1 : TEXCOORD2;
- fixed4 TtoW2 : TEXCOORD3;
- fixed3 lightDir : TEXCOORD4;
- fixed3 vlight : TEXCOORD5;
- LIGHTING_COORDS(6,7)
- };
- #endif
- #ifndef LIGHTMAP_OFF
- struct v2f_surf {
- float4 pos : SV_POSITION;
- float4 pack0 : TEXCOORD0;
- fixed4 TtoW0 : TEXCOORD1;
- fixed4 TtoW1 : TEXCOORD2;
- fixed4 TtoW2 : TEXCOORD3;
- float2 lmap : TEXCOORD4;
- LIGHTING_COORDS(5,6)
- };
- #endif
- #ifndef LIGHTMAP_OFF
- float4 unity_LightmapST;
- #endif
- float4 _MainTex_ST;
- float4 _NormalMap_ST;
-
- // vertex shader
- v2f_surf vert_surf (appdata_full v) {
- v2f_surf o;
- o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
- o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
- o.pack0.zw = TRANSFORM_TEX(v.texcoord, _NormalMap);
- float3 viewDir = -ObjSpaceViewDir(v.vertex);
- float3 worldRefl = mul ((float3x3)_Object2World, viewDir);
- TANGENT_SPACE_ROTATION;
- o.TtoW0 = float4(mul(rotation, _Object2World[0].xyz), worldRefl.x)*unity_Scale.w;
- o.TtoW1 = float4(mul(rotation, _Object2World[1].xyz), worldRefl.y)*unity_Scale.w;
- o.TtoW2 = float4(mul(rotation, _Object2World[2].xyz), worldRefl.z)*unity_Scale.w;
- #ifndef LIGHTMAP_OFF
- o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
- #endif
- float3 worldN = mul((float3x3)_Object2World, SCALED_NORMAL);
- float3 lightDir = mul (rotation, ObjSpaceLightDir(v.vertex));
- #ifdef LIGHTMAP_OFF
- o.lightDir = lightDir;
- #endif
-
- // SH/ambient and vertex lights
- #ifdef LIGHTMAP_OFF
- float3 shlight = ShadeSH9 (float4(worldN,1.0));
- o.vlight = shlight;
- #ifdef VERTEXLIGHT_ON
- float3 worldPos = mul(_Object2World, v.vertex).xyz;
- o.vlight += Shade4PointLights (
- unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
- unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
- unity_4LightAtten0, worldPos, worldN );
- #endif // VERTEXLIGHT_ON
- #endif // LIGHTMAP_OFF
-
- // pass lighting information to pixel shader
- TRANSFER_VERTEX_TO_FRAGMENT(o);
- return o;
- }
- #ifndef LIGHTMAP_OFF
- sampler2D unity_Lightmap;
- #ifndef DIRLIGHTMAP_OFF
- sampler2D unity_LightmapInd;
- #endif
- #endif
-
- // fragment shader
- fixed4 frag_surf (v2f_surf IN) : SV_Target {
- // prepare and unpack data
- #ifdef UNITY_COMPILER_HLSL
- Input surfIN = (Input)0;
- #else
- Input surfIN;
- #endif
- surfIN.uv_MainTex = IN.pack0.xy;
- surfIN.uv_NormalMap = IN.pack0.zw;
- surfIN.worldRefl = float3(IN.TtoW0.w, IN.TtoW1.w, IN.TtoW2.w);
- surfIN.TtoW0 = IN.TtoW0.xyz;
- surfIN.TtoW1 = IN.TtoW1.xyz;
- surfIN.TtoW2 = IN.TtoW2.xyz;
- #ifdef UNITY_COMPILER_HLSL
- SurfaceOutput o = (SurfaceOutput)0;
- #else
- SurfaceOutput o;
- #endif
- o.Albedo = 0.0;
- o.Emission = 0.0;
- o.Specular = 0.0;
- o.Alpha = 0.0;
- o.Gloss = 0.0;
-
- // call surface function
- surf (surfIN, o);
-
- // compute lighting & shadowing factor
- fixed atten = LIGHT_ATTENUATION(IN);
- fixed4 c = 0;
-
- // realtime lighting: call lighting function
- #ifdef LIGHTMAP_OFF
- c = LightingLambert (o, IN.lightDir, atten);
- #endif // LIGHTMAP_OFF || DIRLIGHTMAP_OFF
- #ifdef LIGHTMAP_OFF
- c.rgb += o.Albedo * IN.vlight;
- #endif // LIGHTMAP_OFF
-
- // lightmaps:
- #ifndef LIGHTMAP_OFF
- #ifndef DIRLIGHTMAP_OFF
- // directional lightmaps
- fixed4 lmtex = tex2D(unity_Lightmap, IN.lmap.xy);
- fixed4 lmIndTex = tex2D(unity_LightmapInd, IN.lmap.xy);
- half3 lm = LightingLambert_DirLightmap(o, lmtex, lmIndTex, 1).rgb;
- #else // !DIRLIGHTMAP_OFF
- // single lightmap
- fixed4 lmtex = tex2D(unity_Lightmap, IN.lmap.xy);
- fixed3 lm = DecodeLightmap (lmtex);
- #endif // !DIRLIGHTMAP_OFF
-
- // combine lightmaps with realtime shadows
- #ifdef SHADOWS_SCREEN
- #if defined(UNITY_NO_RGBM)
- c.rgb += o.Albedo * min(lm, atten*2);
- #else
- c.rgb += o.Albedo * max(min(lm,(atten*2)*lmtex.rgb), lm*atten);
- #endif
- #else // SHADOWS_SCREEN
- c.rgb += o.Albedo * lm;
- #endif // SHADOWS_SCREEN
- c.a = o.Alpha;
- #endif // LIGHTMAP_OFF
-
- c.rgb += o.Emission;
- return c;
- }
-
- ENDCG
-
- }
-
- // ---- forward rendering additive lights pass:
- Pass {
- Name "FORWARD"
- Tags { "LightMode" = "ForwardAdd" }
- ZWrite Off Blend One One Fog { Color (0,0,0,0) }
-
- CGPROGRAM
- // compile directives
- #pragma vertex vert_surf
- #pragma fragment frag_surf
- #pragma multi_compile_fwdadd
- #include "HLSLSupport.cginc"
- #include "UnityShaderVariables.cginc"
- #define UNITY_PASS_FORWARDADD
- #include "UnityCG.cginc"
- #include "Lighting.cginc"
- #include "AutoLight.cginc"
-
- #define INTERNAL_DATA
- #define WorldReflectionVector(data,normal) data.worldRefl
- #define WorldNormalVector(data,normal) normal
-
- // Original surface shader snippet:
- #line 18 ""
- #ifdef DUMMY_PREPROCESSOR_TO_WORK_AROUND_HLSL_COMPILER_LINE_HANDLING
- #endif
-
- //#pragma surface surf Lambert
-
- float4 _MainTint;
- sampler2D _MainTex;
-
- sampler2D _NormalMap;
-
- samplerCUBE _Cubemap;
-
- float _ReflAmount;
-
-
-
- struct Input
- {
- float2 uv_MainTex;
-
- float2 uv_NormalMap;
-
- float3 worldRefl;
-
- INTERNAL_DATA
- };
-
- void surf (Input IN, inout SurfaceOutput o)
- {
- half4 c = tex2D (_MainTex, IN.uv_MainTex);
-
- //从法线贴图中提取法线信息,UnpackNormal这个函数在 CGInclude 文件夹中的Lighting中。
- float3 normals=UnpackNormal(tex2D(_NormalMap,IN.uv_NormalMap));
-
- o.Normal=normals;
-
- //上面使用法线贴图中的法线数据 替代了 原来的法线数据。
-
- //法线被修改了,就不能 直接用原来的 内置属性 worldRefl 这个反射向量,而是要通过 WorldReflectionVector(IN,o.Normal)来获取。
-
- //使用WorldReflectionVector 获得 基于法线贴图中的反射向量的 世界反射向量
- o.Emission = texCUBE(_Cubemap,WorldReflectionVector(IN,o.Normal)).rgb * _ReflAmount;
-
- o.Albedo = c.rgb * _MainTint;
- o.Alpha = c.a;
- }
-
-
- // vertex-to-fragment interpolation data
- struct v2f_surf {
- float4 pos : SV_POSITION;
- float4 pack0 : TEXCOORD0;
- half3 lightDir : TEXCOORD1;
- LIGHTING_COORDS(2,3)
- };
- float4 _MainTex_ST;
- float4 _NormalMap_ST;
-
- // vertex shader
- v2f_surf vert_surf (appdata_full v) {
- v2f_surf o;
- o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
- o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
- o.pack0.zw = TRANSFORM_TEX(v.texcoord, _NormalMap);
- TANGENT_SPACE_ROTATION;
- float3 lightDir = mul (rotation, ObjSpaceLightDir(v.vertex));
- o.lightDir = lightDir;
-
- // pass lighting information to pixel shader
- TRANSFER_VERTEX_TO_FRAGMENT(o);
- return o;
- }
-
- // fragment shader
- fixed4 frag_surf (v2f_surf IN) : SV_Target {
- // prepare and unpack data
- #ifdef UNITY_COMPILER_HLSL
- Input surfIN = (Input)0;
- #else
- Input surfIN;
- #endif
- surfIN.uv_MainTex = IN.pack0.xy;
- surfIN.uv_NormalMap = IN.pack0.zw;
- #ifdef UNITY_COMPILER_HLSL
- SurfaceOutput o = (SurfaceOutput)0;
- #else
- SurfaceOutput o;
- #endif
- o.Albedo = 0.0;
- o.Emission = 0.0;
- o.Specular = 0.0;
- o.Alpha = 0.0;
- o.Gloss = 0.0;
-
- // call surface function
- surf (surfIN, o);
- #ifndef USING_DIRECTIONAL_LIGHT
- fixed3 lightDir = normalize(IN.lightDir);
- #else
- fixed3 lightDir = IN.lightDir;
- #endif
- fixed4 c = LightingLambert (o, lightDir, LIGHT_ATTENUATION(IN));
- c.a = 0.0;
- return c;
- }
-
- ENDCG
-
- }
-
- // ---- deferred lighting base geometry pass:
- Pass {
- Name "PREPASS"
- Tags { "LightMode" = "PrePassBase" }
- Fog {Mode Off}
-
- CGPROGRAM
- // compile directives
- #pragma vertex vert_surf
- #pragma fragment frag_surf
-
- #pragma exclude_renderers flash
- #include "HLSLSupport.cginc"
- #include "UnityShaderVariables.cginc"
- #define UNITY_PASS_PREPASSBASE
- #include "UnityCG.cginc"
- #include "Lighting.cginc"
-
- #define INTERNAL_DATA
- #define WorldReflectionVector(data,normal) data.worldRefl
- #define WorldNormalVector(data,normal) normal
-
- // Original surface shader snippet:
- #line 18 ""
- #ifdef DUMMY_PREPROCESSOR_TO_WORK_AROUND_HLSL_COMPILER_LINE_HANDLING
- #endif
-
- //#pragma surface surf Lambert
-
- float4 _MainTint;
- sampler2D _MainTex;
-
- sampler2D _NormalMap;
-
- samplerCUBE _Cubemap;
-
- float _ReflAmount;
-
-
-
- struct Input
- {
- float2 uv_MainTex;
-
- float2 uv_NormalMap;
-
- float3 worldRefl;
-
- INTERNAL_DATA
- };
-
- void surf (Input IN, inout SurfaceOutput o)
- {
- half4 c = tex2D (_MainTex, IN.uv_MainTex);
-
- //从法线贴图中提取法线信息,UnpackNormal这个函数在 CGInclude 文件夹中的Lighting中。
- float3 normals=UnpackNormal(tex2D(_NormalMap,IN.uv_NormalMap));
-
- o.Normal=normals;
-
- //上面使用法线贴图中的法线数据 替代了 原来的法线数据。
-
- //法线被修改了,就不能 直接用原来的 内置属性 worldRefl 这个反射向量,而是要通过 WorldReflectionVector(IN,o.Normal)来获取。
-
- //使用WorldReflectionVector 获得 基于法线贴图中的反射向量的 世界反射向量
- o.Emission = texCUBE(_Cubemap,WorldReflectionVector(IN,o.Normal)).rgb * _ReflAmount;
-
- o.Albedo = c.rgb * _MainTint;
- o.Alpha = c.a;
- }
-
-
- // vertex-to-fragment interpolation data
- struct v2f_surf {
- float4 pos : SV_POSITION;
- float2 pack0 : TEXCOORD0;
- float3 TtoW0 : TEXCOORD1;
- float3 TtoW1 : TEXCOORD2;
- float3 TtoW2 : TEXCOORD3;
- };
- float4 _NormalMap_ST;
-
- // vertex shader
- v2f_surf vert_surf (appdata_full v) {
- v2f_surf o;
- o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
- o.pack0.xy = TRANSFORM_TEX(v.texcoord, _NormalMap);
- TANGENT_SPACE_ROTATION;
- o.TtoW0 = mul(rotation, ((float3x3)_Object2World)[0].xyz)*unity_Scale.w;
- o.TtoW1 = mul(rotation, ((float3x3)_Object2World)[1].xyz)*unity_Scale.w;
- o.TtoW2 = mul(rotation, ((float3x3)_Object2World)[2].xyz)*unity_Scale.w;
- return o;
- }
-
- // fragment shader
- fixed4 frag_surf (v2f_surf IN) : SV_Target {
- // prepare and unpack data
- #ifdef UNITY_COMPILER_HLSL
- Input surfIN = (Input)0;
- #else
- Input surfIN;
- #endif
- surfIN.uv_NormalMap = IN.pack0.xy;
- #ifdef UNITY_COMPILER_HLSL
- SurfaceOutput o = (SurfaceOutput)0;
- #else
- SurfaceOutput o;
- #endif
- o.Albedo = 0.0;
- o.Emission = 0.0;
- o.Specular = 0.0;
- o.Alpha = 0.0;
- o.Gloss = 0.0;
-
- // call surface function
- surf (surfIN, o);
- fixed3 worldN;
- worldN.x = dot(IN.TtoW0, o.Normal);
- worldN.y = dot(IN.TtoW1, o.Normal);
- worldN.z = dot(IN.TtoW2, o.Normal);
- o.Normal = worldN;
-
- // output normal and specular
- fixed4 res;
- res.rgb = o.Normal * 0.5 + 0.5;
- res.a = o.Specular;
- return res;
- }
-
- ENDCG
-
- }
-
- // ---- deferred lighting final pass:
- Pass {
- Name "PREPASS"
- Tags { "LightMode" = "PrePassFinal" }
- ZWrite Off
-
- CGPROGRAM
- // compile directives
- #pragma vertex vert_surf
- #pragma fragment frag_surf
- #pragma multi_compile_prepassfinal
- #pragma exclude_renderers flash
- #include "HLSLSupport.cginc"
- #include "UnityShaderVariables.cginc"
- #define UNITY_PASS_PREPASSFINAL
- #include "UnityCG.cginc"
- #include "Lighting.cginc"
-
- #define INTERNAL_DATA half3 TtoW0; half3 TtoW1; half3 TtoW2;
- #define WorldReflectionVector(data,normal) reflect (data.worldRefl, half3(dot(data.TtoW0,normal), dot(data.TtoW1,normal), dot(data.TtoW2,normal)))
- #define WorldNormalVector(data,normal) fixed3(dot(data.TtoW0,normal), dot(data.TtoW1,normal), dot(data.TtoW2,normal))
-
- // Original surface shader snippet:
- #line 18 ""
- #ifdef DUMMY_PREPROCESSOR_TO_WORK_AROUND_HLSL_COMPILER_LINE_HANDLING
- #endif
-
- //#pragma surface surf Lambert
-
- float4 _MainTint;
- sampler2D _MainTex;
-
- sampler2D _NormalMap;
-
- samplerCUBE _Cubemap;
-
- float _ReflAmount;
-
-
-
- struct Input
- {
- float2 uv_MainTex;
-
- float2 uv_NormalMap;
-
- float3 worldRefl;
-
- INTERNAL_DATA
- };
-
- void surf (Input IN, inout SurfaceOutput o)
- {
- half4 c = tex2D (_MainTex, IN.uv_MainTex);
-
- //从法线贴图中提取法线信息,UnpackNormal这个函数在 CGInclude 文件夹中的Lighting中。
- float3 normals=UnpackNormal(tex2D(_NormalMap,IN.uv_NormalMap));
-
- o.Normal=normals;
-
- //上面使用法线贴图中的法线数据 替代了 原来的法线数据。
-
- //法线被修改了,就不能 直接用原来的 内置属性 worldRefl 这个反射向量,而是要通过 WorldReflectionVector(IN,o.Normal)来获取。
-
- //使用WorldReflectionVector 获得 基于法线贴图中的反射向量的 世界反射向量
- o.Emission = texCUBE(_Cubemap,WorldReflectionVector(IN,o.Normal)).rgb * _ReflAmount;
-
- o.Albedo = c.rgb * _MainTint;
- o.Alpha = c.a;
- }
-
-
- // vertex-to-fragment interpolation data
- struct v2f_surf {
- float4 pos : SV_POSITION;
- float4 pack0 : TEXCOORD0;
- float4 screen : TEXCOORD1;
- fixed4 TtoW0 : TEXCOORD2;
- fixed4 TtoW1 : TEXCOORD3;
- fixed4 TtoW2 : TEXCOORD4;
- #ifdef LIGHTMAP_OFF
- float3 vlight : TEXCOORD5;
- #else
- float2 lmap : TEXCOORD5;
- #ifdef DIRLIGHTMAP_OFF
- float4 lmapFadePos : TEXCOORD6;
- #endif
- #endif
- };
- #ifndef LIGHTMAP_OFF
- float4 unity_LightmapST;
- #endif
- float4 _MainTex_ST;
- float4 _NormalMap_ST;
-
- // vertex shader
- v2f_surf vert_surf (appdata_full v) {
- v2f_surf o;
- o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
- o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
- o.pack0.zw = TRANSFORM_TEX(v.texcoord, _NormalMap);
- float3 viewDir = -ObjSpaceViewDir(v.vertex);
- float3 worldRefl = mul ((float3x3)_Object2World, viewDir);
- TANGENT_SPACE_ROTATION;
- o.TtoW0 = float4(mul(rotation, _Object2World[0].xyz), worldRefl.x)*unity_Scale.w;
- o.TtoW1 = float4(mul(rotation, _Object2World[1].xyz), worldRefl.y)*unity_Scale.w;
- o.TtoW2 = float4(mul(rotation, _Object2World[2].xyz), worldRefl.z)*unity_Scale.w;
- o.screen = ComputeScreenPos (o.pos);
- #ifndef LIGHTMAP_OFF
- o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
- #ifdef DIRLIGHTMAP_OFF
- o.lmapFadePos.xyz = (mul(_Object2World, v.vertex).xyz - unity_ShadowFadeCenterAndType.xyz) * unity_ShadowFadeCenterAndType.w;
- o.lmapFadePos.w = (-mul(UNITY_MATRIX_MV, v.vertex).z) * (1.0 - unity_ShadowFadeCenterAndType.w);
- #endif
- #else
- float3 worldN = mul((float3x3)_Object2World, SCALED_NORMAL);
- o.vlight = ShadeSH9 (float4(worldN,1.0));
- #endif
- return o;
- }
- sampler2D _LightBuffer;
- #if defined (SHADER_API_XBOX360) && defined (HDR_LIGHT_PREPASS_ON)
- sampler2D _LightSpecBuffer;
- #endif
- #ifndef LIGHTMAP_OFF
- sampler2D unity_Lightmap;
- sampler2D unity_LightmapInd;
- float4 unity_LightmapFade;
- #endif
- fixed4 unity_Ambient;
-
- // fragment shader
- fixed4 frag_surf (v2f_surf IN) : SV_Target {
- // prepare and unpack data
- #ifdef UNITY_COMPILER_HLSL
- Input surfIN = (Input)0;
- #else
- Input surfIN;
- #endif
- surfIN.uv_MainTex = IN.pack0.xy;
- surfIN.uv_NormalMap = IN.pack0.zw;
- surfIN.worldRefl = float3(IN.TtoW0.w, IN.TtoW1.w, IN.TtoW2.w);
- surfIN.TtoW0 = IN.TtoW0.xyz;
- surfIN.TtoW1 = IN.TtoW1.xyz;
- surfIN.TtoW2 = IN.TtoW2.xyz;
- #ifdef UNITY_COMPILER_HLSL
- SurfaceOutput o = (SurfaceOutput)0;
- #else
- SurfaceOutput o;
- #endif
- o.Albedo = 0.0;
- o.Emission = 0.0;
- o.Specular = 0.0;
- o.Alpha = 0.0;
- o.Gloss = 0.0;
-
- // call surface function
- surf (surfIN, o);
- half4 light = tex2Dproj (_LightBuffer, UNITY_PROJ_COORD(IN.screen));
- #if defined (SHADER_API_MOBILE)
- light = max(light, half4(0.001));
- #endif
- #ifndef HDR_LIGHT_PREPASS_ON
- light = -log2(light);
- #endif
- #if defined (SHADER_API_XBOX360) && defined (HDR_LIGHT_PREPASS_ON)
- light.w = tex2Dproj (_LightSpecBuffer, UNITY_PROJ_COORD(IN.screen)).r;
- #endif
-
- // add lighting from lightmaps / vertex / ambient:
- #ifndef LIGHTMAP_OFF
- #ifdef DIRLIGHTMAP_OFF
- // dual lightmaps
- fixed4 lmtex = tex2D(unity_Lightmap, IN.lmap.xy);
- fixed4 lmtex2 = tex2D(unity_LightmapInd, IN.lmap.xy);
- half lmFade = length (IN.lmapFadePos) * unity_LightmapFade.z + unity_LightmapFade.w;
- half3 lmFull = DecodeLightmap (lmtex);
- half3 lmIndirect = DecodeLightmap (lmtex2);
- half3 lm = lerp (lmIndirect, lmFull, saturate(lmFade));
- light.rgb += lm;
- #else
- // directional lightmaps
- fixed4 lmtex = tex2D(unity_Lightmap, IN.lmap.xy);
- fixed4 lmIndTex = tex2D(unity_LightmapInd, IN.lmap.xy);
- half4 lm = LightingLambert_DirLightmap(o, lmtex, lmIndTex, 1);
- light += lm;
- #endif
- #else
- light.rgb += IN.vlight;
- #endif
- half4 c = LightingLambert_PrePass (o, light);
- c.rgb += o.Emission;
- return c;
- }
-
- ENDCG
-
- }
-
- // ---- end of surface shader generated code
-
- #LINE 64
-
- }
- FallBack "Diffuse"
- }
果然,原来 INTERNAL_DATA 就是一个宏……
而且会发现在生成的代码中不止一个 INTERNAL_DATA。这是因为生成的代码中有多个PASS
forward rendering additive lights pass:
deferred lighting base geometry pass:
deferred lighting final pass:
forward rendering base pass:
每个PASS 都有一个,所以有好几个。
那么,不使用 INTERNAL_DATA,而是直接使用 具体的内容,可以吗?来试一下。
首先,从Shader 中删掉 INTERNAL_DATA。
Unity 报了以下错误
Shader error in 'CookBookShaders/Chapt4-4/Cubemap_NormalMap': invalid subscript 'TtoW0' at line 59
是这一行的错o.Emission = texCUBE(_Cubemap,WorldReflectionVector(IN,o.Normal)).rgb * _ReflAmount;
因为从上面 Shader 编译后的代码看到,WorldReflectionVector 也是一个宏
#define WorldReflectionVector(data,normal) reflect (data.worldRefl, half3(dot(data.TtoW0,normal), dot(data.TtoW1,normal), dot(data.TtoW2,normal)))
其实就是说,在WorldReflectionVector 这个函数里找不到 TtoW0 这个参数了。
然后,在 Input 结构体中添加 INTERNAL_DATA 的具体内容看看
struct Input
{
float2 uv_MainTex;
float2 uv_NormalMap;
float3 worldRefl;
half3 TtoW0; half3 TtoW1; half3 TtoW2;
};
法线 Shader 已经正常工作啦
B:在Input 中 添加 float3 worldRefl 和 INTERNAL_DATA ,给o.Normal 赋值的话,就可以 用 WorldReflectionVector(IN,o.Normal) 获取到 法线贴图 计算后的 反射向量。
原文是这样写的
在Input 结构体中还有更多的内置函数,其中一部分如下:
float3 viewDir :
Will contain view direction, for computing Parallax effects, rimlighting, and so on.
float4 COLOR :
Will contain interpolated per-vertex color.
float4 screenPos:
Will contain screen-space position for reflection effects. Used by WetStreet shader in Dark Unity, for example.
float3 worldPos :
Will contain world space position.
float3 worldRefl :
Will contain world reflection vector if Surface Shader does not write to o.Normal. See Reflect-Diffuse shader for example.
float3 worldNormal :
Will contain world normal vector if Surface Shader does not write to o.Normal.
float3 worldRef;INTERNAL_DATA:
Will contain world reflection vector if Surface Shader writes to o.Normal. To get the reflection vector based on per-pixel normal map, use WorldReflectionVector (IN,o.Normal). See Reflect-Bumped shader for example.
float3 worldNormal;INTERNAL_DATA:
Will contain world normal vector if Surface Shader writes to o.Normal. To get the normal vector based on per-pixel normal map, use WorldNormalVector (IN, o.Normal).
3、在 surf 函数中 添加了 读取 法线贴图的代码
//从法线贴图中提取法线信息,UnpackNormal这个函数在 CGInclude 文件夹中的Lighting中。
float3 normals=UnpackNormal(tex2D(_NormalMap,IN.uv_NormalMap));
4、上一节中直接使用 Input 中的 worldRefl 这个反射向量来获取立方图 采样。这一次需要使用上面说的 WorldReflectionVector 来计算世界反射向量。//使用WorldReflectionVector 获得 基于法线贴图中的反射向量的 世界反射向量
o.Emission = texCUBE(_Cubemap,WorldReflectionVector(IN,o.Normal)).rgb * _ReflAmount;
示例项目打包下载:http://pan.baidu.com/s/1c1TcSgS