Unity Shaders and Effects Cookbook:法线贴图与反射

发表于2017-11-23
评论0 1.8k浏览

法线贴图在之前学习过了,我们使用法线贴图在低分辨率的模型上模拟高分辨率的效果。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.


就是说计算世界反射向量的时候 使用了法线贴图就要加上 这个。


谷歌一下,发现网友说在 生成的代码中能看出来,然后就查看生成的代码

  1. Shader "CookBookShaders/Chapt4-4/Cubemap_NormalMap"   
  2. {  
  3.     Properties   
  4.     {  
  5.         _MainTint("Diffuse Color",Color)=(1,1,1,1)  
  6.         _MainTex ("Base (RGB)", 2D) = "white" {}  
  7.   
  8.         _NormalMap("Normal Map",2D) = "bump"{}  
  9.   
  10.         _Cubemap("Cubemap",CUBE)=""{}  
  11.   
  12.         _ReflAmount("Reflection Amount",Range(0,1))=0.5  
  13.     }  
  14.   
  15.     SubShader   
  16.     {  
  17.         Tags { "RenderType"="Opaque" }  
  18.         LOD 200  
  19.           
  20.           
  21.     // ------------------------------------------------------------  
  22.     // Surface shader code generated out of a CGPROGRAM block:  
  23.       
  24.   
  25.     // ---- forward rendering base pass:  
  26.     Pass {  
  27.         Name "FORWARD"  
  28.         Tags { "LightMode" = "ForwardBase" }  
  29.   
  30. CGPROGRAM  
  31. // compile directives  
  32. #pragma vertex vert_surf  
  33. #pragma fragment frag_surf  
  34. #pragma multi_compile_fwdbase  
  35. #include "HLSLSupport.cginc"  
  36. #include "UnityShaderVariables.cginc"  
  37. #define UNITY_PASS_FORWARDBASE  
  38. #include "UnityCG.cginc"  
  39. #include "Lighting.cginc"  
  40. #include "AutoLight.cginc"  
  41.   
  42. #define INTERNAL_DATA half3 TtoW0; half3 TtoW1; half3 TtoW2;  
  43. #define WorldReflectionVector(data,normal) reflect (data.worldRefl, half3(dot(data.TtoW0,normal), dot(data.TtoW1,normal), dot(data.TtoW2,normal)))  
  44. #define WorldNormalVector(data,normal) fixed3(dot(data.TtoW0,normal), dot(data.TtoW1,normal), dot(data.TtoW2,normal))  
  45.   
  46. // Original surface shader snippet:  
  47. #line 18 ""  
  48. #ifdef DUMMY_PREPROCESSOR_TO_WORK_AROUND_HLSL_COMPILER_LINE_HANDLING  
  49. #endif  
  50.   
  51.         //#pragma surface surf Lambert  
  52.   
  53.         float4 _MainTint;  
  54.         sampler2D _MainTex;  
  55.   
  56.         sampler2D _NormalMap;  
  57.   
  58.         samplerCUBE _Cubemap;  
  59.   
  60.         float _ReflAmount;  
  61.   
  62.   
  63.   
  64.         struct Input   
  65.         {  
  66.             float2 uv_MainTex;  
  67.   
  68.             float2 uv_NormalMap;  
  69.   
  70.             float3 worldRefl;  
  71.   
  72.             INTERNAL_DATA  
  73.         };  
  74.   
  75.         void surf (Input IN, inout SurfaceOutput o)   
  76.         {  
  77.             half4 c = tex2D (_MainTex, IN.uv_MainTex);  
  78.   
  79.             //从法线贴图中提取法线信息,UnpackNormal这个函数在 CGInclude 文件夹中的Lighting中。  
  80.             float3 normals=UnpackNormal(tex2D(_NormalMap,IN.uv_NormalMap));  
  81.   
  82.             o.Normal=normals;  
  83.   
  84.             //上面使用法线贴图中的法线数据 替代了 原来的法线数据。  
  85.   
  86.             //法线被修改了,就不能 直接用原来的 内置属性 worldRefl 这个反射向量,而是要通过 WorldReflectionVector(IN,o.Normal)来获取。  
  87.   
  88.             //使用WorldReflectionVector 获得 基于法线贴图中的反射向量的 世界反射向量  
  89.             o.Emission = texCUBE(_Cubemap,WorldReflectionVector(IN,o.Normal)).rgb * _ReflAmount;  
  90.   
  91.             o.Albedo = c.rgb * _MainTint;  
  92.             o.Alpha = c.a;  
  93.         }  
  94.           
  95.   
  96. // vertex-to-fragment interpolation data  
  97. #ifdef LIGHTMAP_OFF  
  98. struct v2f_surf {  
  99.   float4 pos : SV_POSITION;  
  100.   float4 pack0 : TEXCOORD0;  
  101.   fixed4 TtoW0 : TEXCOORD1;  
  102.   fixed4 TtoW1 : TEXCOORD2;  
  103.   fixed4 TtoW2 : TEXCOORD3;  
  104.   fixed3 lightDir : TEXCOORD4;  
  105.   fixed3 vlight : TEXCOORD5;  
  106.   LIGHTING_COORDS(6,7)  
  107. };  
  108. #endif  
  109. #ifndef LIGHTMAP_OFF  
  110. struct v2f_surf {  
  111.   float4 pos : SV_POSITION;  
  112.   float4 pack0 : TEXCOORD0;  
  113.   fixed4 TtoW0 : TEXCOORD1;  
  114.   fixed4 TtoW1 : TEXCOORD2;  
  115.   fixed4 TtoW2 : TEXCOORD3;  
  116.   float2 lmap : TEXCOORD4;  
  117.   LIGHTING_COORDS(5,6)  
  118. };  
  119. #endif  
  120. #ifndef LIGHTMAP_OFF  
  121. float4 unity_LightmapST;  
  122. #endif  
  123. float4 _MainTex_ST;  
  124. float4 _NormalMap_ST;  
  125.   
  126. // vertex shader  
  127. v2f_surf vert_surf (appdata_full v) {  
  128.   v2f_surf o;  
  129.   o.pos = mul (UNITY_MATRIX_MVP, v.vertex);  
  130.   o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);  
  131.   o.pack0.zw = TRANSFORM_TEX(v.texcoord, _NormalMap);  
  132.   float3 viewDir = -ObjSpaceViewDir(v.vertex);  
  133.   float3 worldRefl = mul ((float3x3)_Object2World, viewDir);  
  134.   TANGENT_SPACE_ROTATION;  
  135.   o.TtoW0 = float4(mul(rotation, _Object2World[0].xyz), worldRefl.x)*unity_Scale.w;  
  136.   o.TtoW1 = float4(mul(rotation, _Object2World[1].xyz), worldRefl.y)*unity_Scale.w;  
  137.   o.TtoW2 = float4(mul(rotation, _Object2World[2].xyz), worldRefl.z)*unity_Scale.w;  
  138.   #ifndef LIGHTMAP_OFF  
  139.   o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;  
  140.   #endif  
  141.   float3 worldN = mul((float3x3)_Object2World, SCALED_NORMAL);  
  142.   float3 lightDir = mul (rotation, ObjSpaceLightDir(v.vertex));  
  143.   #ifdef LIGHTMAP_OFF  
  144.   o.lightDir = lightDir;  
  145.   #endif  
  146.   
  147.   // SH/ambient and vertex lights  
  148.   #ifdef LIGHTMAP_OFF  
  149.   float3 shlight = ShadeSH9 (float4(worldN,1.0));  
  150.   o.vlight = shlight;  
  151.   #ifdef VERTEXLIGHT_ON  
  152.   float3 worldPos = mul(_Object2World, v.vertex).xyz;  
  153.   o.vlight += Shade4PointLights (  
  154.     unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,  
  155.     unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,  
  156.     unity_4LightAtten0, worldPos, worldN );  
  157.   #endif // VERTEXLIGHT_ON  
  158.   #endif // LIGHTMAP_OFF  
  159.   
  160.   // pass lighting information to pixel shader  
  161.   TRANSFER_VERTEX_TO_FRAGMENT(o);  
  162.   return o;  
  163. }  
  164. #ifndef LIGHTMAP_OFF  
  165. sampler2D unity_Lightmap;  
  166. #ifndef DIRLIGHTMAP_OFF  
  167. sampler2D unity_LightmapInd;  
  168. #endif  
  169. #endif  
  170.   
  171. // fragment shader  
  172. fixed4 frag_surf (v2f_surf IN) : SV_Target {  
  173.   // prepare and unpack data  
  174.   #ifdef UNITY_COMPILER_HLSL  
  175.   Input surfIN = (Input)0;  
  176.   #else  
  177.   Input surfIN;  
  178.   #endif  
  179.   surfIN.uv_MainTex = IN.pack0.xy;  
  180.   surfIN.uv_NormalMap = IN.pack0.zw;  
  181.   surfIN.worldRefl = float3(IN.TtoW0.w, IN.TtoW1.w, IN.TtoW2.w);  
  182.   surfIN.TtoW0 = IN.TtoW0.xyz;  
  183.   surfIN.TtoW1 = IN.TtoW1.xyz;  
  184.   surfIN.TtoW2 = IN.TtoW2.xyz;  
  185.   #ifdef UNITY_COMPILER_HLSL  
  186.   SurfaceOutput o = (SurfaceOutput)0;  
  187.   #else  
  188.   SurfaceOutput o;  
  189.   #endif  
  190.   o.Albedo = 0.0;  
  191.   o.Emission = 0.0;  
  192.   o.Specular = 0.0;  
  193.   o.Alpha = 0.0;  
  194.   o.Gloss = 0.0;  
  195.   
  196.   // call surface function  
  197.   surf (surfIN, o);  
  198.   
  199.   // compute lighting & shadowing factor  
  200.   fixed atten = LIGHT_ATTENUATION(IN);  
  201.   fixed4 c = 0;  
  202.   
  203.   // realtime lighting: call lighting function  
  204.   #ifdef LIGHTMAP_OFF  
  205.   c = LightingLambert (o, IN.lightDir, atten);  
  206.   #endif // LIGHTMAP_OFF || DIRLIGHTMAP_OFF  
  207.   #ifdef LIGHTMAP_OFF  
  208.   c.rgb += o.Albedo * IN.vlight;  
  209.   #endif // LIGHTMAP_OFF  
  210.   
  211.   // lightmaps:  
  212.   #ifndef LIGHTMAP_OFF  
  213.     #ifndef DIRLIGHTMAP_OFF  
  214.       // directional lightmaps  
  215.       fixed4 lmtex = tex2D(unity_Lightmap, IN.lmap.xy);  
  216.       fixed4 lmIndTex = tex2D(unity_LightmapInd, IN.lmap.xy);  
  217.       half3 lm = LightingLambert_DirLightmap(o, lmtex, lmIndTex, 1).rgb;  
  218.     #else // !DIRLIGHTMAP_OFF  
  219.       // single lightmap  
  220.       fixed4 lmtex = tex2D(unity_Lightmap, IN.lmap.xy);  
  221.       fixed3 lm = DecodeLightmap (lmtex);  
  222.     #endif // !DIRLIGHTMAP_OFF  
  223.   
  224.     // combine lightmaps with realtime shadows  
  225.     #ifdef SHADOWS_SCREEN  
  226.       #if defined(UNITY_NO_RGBM)  
  227.       c.rgb += o.Albedo * min(lm, atten*2);  
  228.       #else  
  229.       c.rgb += o.Albedo * max(min(lm,(atten*2)*lmtex.rgb), lm*atten);  
  230.       #endif  
  231.     #else // SHADOWS_SCREEN  
  232.       c.rgb += o.Albedo * lm;  
  233.     #endif // SHADOWS_SCREEN  
  234.   c.a = o.Alpha;  
  235.   #endif // LIGHTMAP_OFF  
  236.   
  237.   c.rgb += o.Emission;  
  238.   return c;  
  239. }  
  240.   
  241. ENDCG  
  242.   
  243. }  
  244.   
  245.     // ---- forward rendering additive lights pass:  
  246.     Pass {  
  247.         Name "FORWARD"  
  248.         Tags { "LightMode" = "ForwardAdd" }  
  249.         ZWrite Off Blend One One Fog { Color (0,0,0,0) }  
  250.   
  251. CGPROGRAM  
  252. // compile directives  
  253. #pragma vertex vert_surf  
  254. #pragma fragment frag_surf  
  255. #pragma multi_compile_fwdadd  
  256. #include "HLSLSupport.cginc"  
  257. #include "UnityShaderVariables.cginc"  
  258. #define UNITY_PASS_FORWARDADD  
  259. #include "UnityCG.cginc"  
  260. #include "Lighting.cginc"  
  261. #include "AutoLight.cginc"  
  262.   
  263. #define INTERNAL_DATA  
  264. #define WorldReflectionVector(data,normal) data.worldRefl  
  265. #define WorldNormalVector(data,normal) normal  
  266.   
  267. // Original surface shader snippet:  
  268. #line 18 ""  
  269. #ifdef DUMMY_PREPROCESSOR_TO_WORK_AROUND_HLSL_COMPILER_LINE_HANDLING  
  270. #endif  
  271.   
  272.         //#pragma surface surf Lambert  
  273.   
  274.         float4 _MainTint;  
  275.         sampler2D _MainTex;  
  276.   
  277.         sampler2D _NormalMap;  
  278.   
  279.         samplerCUBE _Cubemap;  
  280.   
  281.         float _ReflAmount;  
  282.   
  283.   
  284.   
  285.         struct Input   
  286.         {  
  287.             float2 uv_MainTex;  
  288.   
  289.             float2 uv_NormalMap;  
  290.   
  291.             float3 worldRefl;  
  292.   
  293.             INTERNAL_DATA  
  294.         };  
  295.   
  296.         void surf (Input IN, inout SurfaceOutput o)   
  297.         {  
  298.             half4 c = tex2D (_MainTex, IN.uv_MainTex);  
  299.   
  300.             //从法线贴图中提取法线信息,UnpackNormal这个函数在 CGInclude 文件夹中的Lighting中。  
  301.             float3 normals=UnpackNormal(tex2D(_NormalMap,IN.uv_NormalMap));  
  302.   
  303.             o.Normal=normals;  
  304.   
  305.             //上面使用法线贴图中的法线数据 替代了 原来的法线数据。  
  306.   
  307.             //法线被修改了,就不能 直接用原来的 内置属性 worldRefl 这个反射向量,而是要通过 WorldReflectionVector(IN,o.Normal)来获取。  
  308.   
  309.             //使用WorldReflectionVector 获得 基于法线贴图中的反射向量的 世界反射向量  
  310.             o.Emission = texCUBE(_Cubemap,WorldReflectionVector(IN,o.Normal)).rgb * _ReflAmount;  
  311.   
  312.             o.Albedo = c.rgb * _MainTint;  
  313.             o.Alpha = c.a;  
  314.         }  
  315.           
  316.   
  317. // vertex-to-fragment interpolation data  
  318. struct v2f_surf {  
  319.   float4 pos : SV_POSITION;  
  320.   float4 pack0 : TEXCOORD0;  
  321.   half3 lightDir : TEXCOORD1;  
  322.   LIGHTING_COORDS(2,3)  
  323. };  
  324. float4 _MainTex_ST;  
  325. float4 _NormalMap_ST;  
  326.   
  327. // vertex shader  
  328. v2f_surf vert_surf (appdata_full v) {  
  329.   v2f_surf o;  
  330.   o.pos = mul (UNITY_MATRIX_MVP, v.vertex);  
  331.   o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);  
  332.   o.pack0.zw = TRANSFORM_TEX(v.texcoord, _NormalMap);  
  333.   TANGENT_SPACE_ROTATION;  
  334.   float3 lightDir = mul (rotation, ObjSpaceLightDir(v.vertex));  
  335.   o.lightDir = lightDir;  
  336.   
  337.   // pass lighting information to pixel shader  
  338.   TRANSFER_VERTEX_TO_FRAGMENT(o);  
  339.   return o;  
  340. }  
  341.   
  342. // fragment shader  
  343. fixed4 frag_surf (v2f_surf IN) : SV_Target {  
  344.   // prepare and unpack data  
  345.   #ifdef UNITY_COMPILER_HLSL  
  346.   Input surfIN = (Input)0;  
  347.   #else  
  348.   Input surfIN;  
  349.   #endif  
  350.   surfIN.uv_MainTex = IN.pack0.xy;  
  351.   surfIN.uv_NormalMap = IN.pack0.zw;  
  352.   #ifdef UNITY_COMPILER_HLSL  
  353.   SurfaceOutput o = (SurfaceOutput)0;  
  354.   #else  
  355.   SurfaceOutput o;  
  356.   #endif  
  357.   o.Albedo = 0.0;  
  358.   o.Emission = 0.0;  
  359.   o.Specular = 0.0;  
  360.   o.Alpha = 0.0;  
  361.   o.Gloss = 0.0;  
  362.   
  363.   // call surface function  
  364.   surf (surfIN, o);  
  365.   #ifndef USING_DIRECTIONAL_LIGHT  
  366.   fixed3 lightDir = normalize(IN.lightDir);  
  367.   #else  
  368.   fixed3 lightDir = IN.lightDir;  
  369.   #endif  
  370.   fixed4 c = LightingLambert (o, lightDir, LIGHT_ATTENUATION(IN));  
  371.   c.a = 0.0;  
  372.   return c;  
  373. }  
  374.   
  375. ENDCG  
  376.   
  377. }  
  378.   
  379.     // ---- deferred lighting base geometry pass:  
  380.     Pass {  
  381.         Name "PREPASS"  
  382.         Tags { "LightMode" = "PrePassBase" }  
  383.         Fog {Mode Off}  
  384.   
  385. CGPROGRAM  
  386. // compile directives  
  387. #pragma vertex vert_surf  
  388. #pragma fragment frag_surf  
  389.   
  390. #pragma exclude_renderers flash  
  391. #include "HLSLSupport.cginc"  
  392. #include "UnityShaderVariables.cginc"  
  393. #define UNITY_PASS_PREPASSBASE  
  394. #include "UnityCG.cginc"  
  395. #include "Lighting.cginc"  
  396.   
  397. #define INTERNAL_DATA  
  398. #define WorldReflectionVector(data,normal) data.worldRefl  
  399. #define WorldNormalVector(data,normal) normal  
  400.   
  401. // Original surface shader snippet:  
  402. #line 18 ""  
  403. #ifdef DUMMY_PREPROCESSOR_TO_WORK_AROUND_HLSL_COMPILER_LINE_HANDLING  
  404. #endif  
  405.   
  406.         //#pragma surface surf Lambert  
  407.   
  408.         float4 _MainTint;  
  409.         sampler2D _MainTex;  
  410.   
  411.         sampler2D _NormalMap;  
  412.   
  413.         samplerCUBE _Cubemap;  
  414.   
  415.         float _ReflAmount;  
  416.   
  417.   
  418.   
  419.         struct Input   
  420.         {  
  421.             float2 uv_MainTex;  
  422.   
  423.             float2 uv_NormalMap;  
  424.   
  425.             float3 worldRefl;  
  426.   
  427.             INTERNAL_DATA  
  428.         };  
  429.   
  430.         void surf (Input IN, inout SurfaceOutput o)   
  431.         {  
  432.             half4 c = tex2D (_MainTex, IN.uv_MainTex);  
  433.   
  434.             //从法线贴图中提取法线信息,UnpackNormal这个函数在 CGInclude 文件夹中的Lighting中。  
  435.             float3 normals=UnpackNormal(tex2D(_NormalMap,IN.uv_NormalMap));  
  436.   
  437.             o.Normal=normals;  
  438.   
  439.             //上面使用法线贴图中的法线数据 替代了 原来的法线数据。  
  440.   
  441.             //法线被修改了,就不能 直接用原来的 内置属性 worldRefl 这个反射向量,而是要通过 WorldReflectionVector(IN,o.Normal)来获取。  
  442.   
  443.             //使用WorldReflectionVector 获得 基于法线贴图中的反射向量的 世界反射向量  
  444.             o.Emission = texCUBE(_Cubemap,WorldReflectionVector(IN,o.Normal)).rgb * _ReflAmount;  
  445.   
  446.             o.Albedo = c.rgb * _MainTint;  
  447.             o.Alpha = c.a;  
  448.         }  
  449.           
  450.   
  451. // vertex-to-fragment interpolation data  
  452. struct v2f_surf {  
  453.   float4 pos : SV_POSITION;  
  454.   float2 pack0 : TEXCOORD0;  
  455.   float3 TtoW0 : TEXCOORD1;  
  456.   float3 TtoW1 : TEXCOORD2;  
  457.   float3 TtoW2 : TEXCOORD3;  
  458. };  
  459. float4 _NormalMap_ST;  
  460.   
  461. // vertex shader  
  462. v2f_surf vert_surf (appdata_full v) {  
  463.   v2f_surf o;  
  464.   o.pos = mul (UNITY_MATRIX_MVP, v.vertex);  
  465.   o.pack0.xy = TRANSFORM_TEX(v.texcoord, _NormalMap);  
  466.   TANGENT_SPACE_ROTATION;  
  467.   o.TtoW0 = mul(rotation, ((float3x3)_Object2World)[0].xyz)*unity_Scale.w;  
  468.   o.TtoW1 = mul(rotation, ((float3x3)_Object2World)[1].xyz)*unity_Scale.w;  
  469.   o.TtoW2 = mul(rotation, ((float3x3)_Object2World)[2].xyz)*unity_Scale.w;  
  470.   return o;  
  471. }  
  472.   
  473. // fragment shader  
  474. fixed4 frag_surf (v2f_surf IN) : SV_Target {  
  475.   // prepare and unpack data  
  476.   #ifdef UNITY_COMPILER_HLSL  
  477.   Input surfIN = (Input)0;  
  478.   #else  
  479.   Input surfIN;  
  480.   #endif  
  481.   surfIN.uv_NormalMap = IN.pack0.xy;  
  482.   #ifdef UNITY_COMPILER_HLSL  
  483.   SurfaceOutput o = (SurfaceOutput)0;  
  484.   #else  
  485.   SurfaceOutput o;  
  486.   #endif  
  487.   o.Albedo = 0.0;  
  488.   o.Emission = 0.0;  
  489.   o.Specular = 0.0;  
  490.   o.Alpha = 0.0;  
  491.   o.Gloss = 0.0;  
  492.   
  493.   // call surface function  
  494.   surf (surfIN, o);  
  495.   fixed3 worldN;  
  496.   worldN.x = dot(IN.TtoW0, o.Normal);  
  497.   worldN.y = dot(IN.TtoW1, o.Normal);  
  498.   worldN.z = dot(IN.TtoW2, o.Normal);  
  499.   o.Normal = worldN;  
  500.   
  501.   // output normal and specular  
  502.   fixed4 res;  
  503.   res.rgb = o.Normal * 0.5 + 0.5;  
  504.   res.a = o.Specular;  
  505.   return res;  
  506. }  
  507.   
  508. ENDCG  
  509.   
  510. }  
  511.   
  512.     // ---- deferred lighting final pass:  
  513.     Pass {  
  514.         Name "PREPASS"  
  515.         Tags { "LightMode" = "PrePassFinal" }  
  516.         ZWrite Off  
  517.   
  518. CGPROGRAM  
  519. // compile directives  
  520. #pragma vertex vert_surf  
  521. #pragma fragment frag_surf  
  522. #pragma multi_compile_prepassfinal  
  523. #pragma exclude_renderers flash  
  524. #include "HLSLSupport.cginc"  
  525. #include "UnityShaderVariables.cginc"  
  526. #define UNITY_PASS_PREPASSFINAL  
  527. #include "UnityCG.cginc"  
  528. #include "Lighting.cginc"  
  529.   
  530. #define INTERNAL_DATA half3 TtoW0; half3 TtoW1; half3 TtoW2;  
  531. #define WorldReflectionVector(data,normal) reflect (data.worldRefl, half3(dot(data.TtoW0,normal), dot(data.TtoW1,normal), dot(data.TtoW2,normal)))  
  532. #define WorldNormalVector(data,normal) fixed3(dot(data.TtoW0,normal), dot(data.TtoW1,normal), dot(data.TtoW2,normal))  
  533.   
  534. // Original surface shader snippet:  
  535. #line 18 ""  
  536. #ifdef DUMMY_PREPROCESSOR_TO_WORK_AROUND_HLSL_COMPILER_LINE_HANDLING  
  537. #endif  
  538.   
  539.         //#pragma surface surf Lambert  
  540.   
  541.         float4 _MainTint;  
  542.         sampler2D _MainTex;  
  543.   
  544.         sampler2D _NormalMap;  
  545.   
  546.         samplerCUBE _Cubemap;  
  547.   
  548.         float _ReflAmount;  
  549.   
  550.   
  551.   
  552.         struct Input   
  553.         {  
  554.             float2 uv_MainTex;  
  555.   
  556.             float2 uv_NormalMap;  
  557.   
  558.             float3 worldRefl;  
  559.   
  560.             INTERNAL_DATA  
  561.         };  
  562.   
  563.         void surf (Input IN, inout SurfaceOutput o)   
  564.         {  
  565.             half4 c = tex2D (_MainTex, IN.uv_MainTex);  
  566.   
  567.             //从法线贴图中提取法线信息,UnpackNormal这个函数在 CGInclude 文件夹中的Lighting中。  
  568.             float3 normals=UnpackNormal(tex2D(_NormalMap,IN.uv_NormalMap));  
  569.   
  570.             o.Normal=normals;  
  571.   
  572.             //上面使用法线贴图中的法线数据 替代了 原来的法线数据。  
  573.   
  574.             //法线被修改了,就不能 直接用原来的 内置属性 worldRefl 这个反射向量,而是要通过 WorldReflectionVector(IN,o.Normal)来获取。  
  575.   
  576.             //使用WorldReflectionVector 获得 基于法线贴图中的反射向量的 世界反射向量  
  577.             o.Emission = texCUBE(_Cubemap,WorldReflectionVector(IN,o.Normal)).rgb * _ReflAmount;  
  578.   
  579.             o.Albedo = c.rgb * _MainTint;  
  580.             o.Alpha = c.a;  
  581.         }  
  582.           
  583.   
  584. // vertex-to-fragment interpolation data  
  585. struct v2f_surf {  
  586.   float4 pos : SV_POSITION;  
  587.   float4 pack0 : TEXCOORD0;  
  588.   float4 screen : TEXCOORD1;  
  589.   fixed4 TtoW0 : TEXCOORD2;  
  590.   fixed4 TtoW1 : TEXCOORD3;  
  591.   fixed4 TtoW2 : TEXCOORD4;  
  592. #ifdef LIGHTMAP_OFF  
  593.   float3 vlight : TEXCOORD5;  
  594. #else  
  595.   float2 lmap : TEXCOORD5;  
  596. #ifdef DIRLIGHTMAP_OFF  
  597.   float4 lmapFadePos : TEXCOORD6;  
  598. #endif  
  599. #endif  
  600. };  
  601. #ifndef LIGHTMAP_OFF  
  602. float4 unity_LightmapST;  
  603. #endif  
  604. float4 _MainTex_ST;  
  605. float4 _NormalMap_ST;  
  606.   
  607. // vertex shader  
  608. v2f_surf vert_surf (appdata_full v) {  
  609.   v2f_surf o;  
  610.   o.pos = mul (UNITY_MATRIX_MVP, v.vertex);  
  611.   o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);  
  612.   o.pack0.zw = TRANSFORM_TEX(v.texcoord, _NormalMap);  
  613.   float3 viewDir = -ObjSpaceViewDir(v.vertex);  
  614.   float3 worldRefl = mul ((float3x3)_Object2World, viewDir);  
  615.   TANGENT_SPACE_ROTATION;  
  616.   o.TtoW0 = float4(mul(rotation, _Object2World[0].xyz), worldRefl.x)*unity_Scale.w;  
  617.   o.TtoW1 = float4(mul(rotation, _Object2World[1].xyz), worldRefl.y)*unity_Scale.w;  
  618.   o.TtoW2 = float4(mul(rotation, _Object2World[2].xyz), worldRefl.z)*unity_Scale.w;  
  619.   o.screen = ComputeScreenPos (o.pos);  
  620. #ifndef LIGHTMAP_OFF  
  621.   o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;  
  622.   #ifdef DIRLIGHTMAP_OFF  
  623.     o.lmapFadePos.xyz = (mul(_Object2World, v.vertex).xyz - unity_ShadowFadeCenterAndType.xyz) * unity_ShadowFadeCenterAndType.w;  
  624.     o.lmapFadePos.w = (-mul(UNITY_MATRIX_MV, v.vertex).z) * (1.0 - unity_ShadowFadeCenterAndType.w);  
  625.   #endif  
  626. #else  
  627.   float3 worldN = mul((float3x3)_Object2World, SCALED_NORMAL);  
  628.   o.vlight = ShadeSH9 (float4(worldN,1.0));  
  629. #endif  
  630.   return o;  
  631. }  
  632. sampler2D _LightBuffer;  
  633. #if defined (SHADER_API_XBOX360) && defined (HDR_LIGHT_PREPASS_ON)  
  634. sampler2D _LightSpecBuffer;  
  635. #endif  
  636. #ifndef LIGHTMAP_OFF  
  637. sampler2D unity_Lightmap;  
  638. sampler2D unity_LightmapInd;  
  639. float4 unity_LightmapFade;  
  640. #endif  
  641. fixed4 unity_Ambient;  
  642.   
  643. // fragment shader  
  644. fixed4 frag_surf (v2f_surf IN) : SV_Target {  
  645.   // prepare and unpack data  
  646.   #ifdef UNITY_COMPILER_HLSL  
  647.   Input surfIN = (Input)0;  
  648.   #else  
  649.   Input surfIN;  
  650.   #endif  
  651.   surfIN.uv_MainTex = IN.pack0.xy;  
  652.   surfIN.uv_NormalMap = IN.pack0.zw;  
  653.   surfIN.worldRefl = float3(IN.TtoW0.w, IN.TtoW1.w, IN.TtoW2.w);  
  654.   surfIN.TtoW0 = IN.TtoW0.xyz;  
  655.   surfIN.TtoW1 = IN.TtoW1.xyz;  
  656.   surfIN.TtoW2 = IN.TtoW2.xyz;  
  657.   #ifdef UNITY_COMPILER_HLSL  
  658.   SurfaceOutput o = (SurfaceOutput)0;  
  659.   #else  
  660.   SurfaceOutput o;  
  661.   #endif  
  662.   o.Albedo = 0.0;  
  663.   o.Emission = 0.0;  
  664.   o.Specular = 0.0;  
  665.   o.Alpha = 0.0;  
  666.   o.Gloss = 0.0;  
  667.   
  668.   // call surface function  
  669.   surf (surfIN, o);  
  670.   half4 light = tex2Dproj (_LightBuffer, UNITY_PROJ_COORD(IN.screen));  
  671. #if defined (SHADER_API_MOBILE)  
  672.   light = max(light, half4(0.001));  
  673. #endif  
  674. #ifndef HDR_LIGHT_PREPASS_ON  
  675.   light = -log2(light);  
  676. #endif  
  677. #if defined (SHADER_API_XBOX360) && defined (HDR_LIGHT_PREPASS_ON)  
  678.   light.w = tex2Dproj (_LightSpecBuffer, UNITY_PROJ_COORD(IN.screen)).r;  
  679. #endif  
  680.   
  681.   // add lighting from lightmaps / vertex / ambient:  
  682.   #ifndef LIGHTMAP_OFF  
  683.     #ifdef DIRLIGHTMAP_OFF  
  684.       // dual lightmaps  
  685.       fixed4 lmtex = tex2D(unity_Lightmap, IN.lmap.xy);  
  686.       fixed4 lmtex2 = tex2D(unity_LightmapInd, IN.lmap.xy);  
  687.       half lmFade = length (IN.lmapFadePos) * unity_LightmapFade.z + unity_LightmapFade.w;  
  688.       half3 lmFull = DecodeLightmap (lmtex);  
  689.       half3 lmIndirect = DecodeLightmap (lmtex2);  
  690.       half3 lm = lerp (lmIndirect, lmFull, saturate(lmFade));  
  691.       light.rgb += lm;  
  692.     #else  
  693.       // directional lightmaps  
  694.       fixed4 lmtex = tex2D(unity_Lightmap, IN.lmap.xy);  
  695.       fixed4 lmIndTex = tex2D(unity_LightmapInd, IN.lmap.xy);  
  696.       half4 lm = LightingLambert_DirLightmap(o, lmtex, lmIndTex, 1);  
  697.       light += lm;  
  698.     #endif  
  699.   #else  
  700.     light.rgb += IN.vlight;  
  701.   #endif  
  702.   half4 c = LightingLambert_PrePass (o, light);  
  703.   c.rgb += o.Emission;  
  704.   return c;  
  705. }  
  706.   
  707. ENDCG  
  708.   
  709. }  
  710.   
  711.     // ---- end of surface shader generated code  
  712.   
  713. #LINE 64  
  714.   
  715.     }   
  716.     FallBack "Diffuse"  
  717. }  

果然,原来 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 

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

0个评论