zoukankan      html  css  js  c++  java
  • Unity Shaders and Effects Cookbook (4-4)在Cubemap 上使用 法线贴图 (法线贴图与反射)

    法线贴图 在之前学习过了,我们使使用方法线贴图在低分辨率的模型上 模拟 高分辨率的效果。

    Unity中 通过 UnpackNormal 函数 来使使用方法线贴图。


    之前学习法线贴图的记录

    Unity Shaders and Effects Cookbook (2-5) 怎样使使用方法线贴图

    这一节讲的是 在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 是用来读取 法线贴图数据的。

    转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn

    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


  • 相关阅读:
    C++中char*,String,int,CString间转换
    获取本地MAC地址和多IP
    子窗口
    linux记录键盘
    curses和窗口
    使用curses函数写的hello world 程序
    Java 复习笔记
    Ubuntu apt install 下载软件很慢的解决办法
    Ubuntu python多个版本管理
    VMware下的Ubuntu16设置连接主机网络,设置主机下可以通过xshell访问 VMware下的Ubuntu
  • 原文地址:https://www.cnblogs.com/wgwyanfs/p/7259258.html
Copyright © 2011-2022 走看看