Unity Shader:(九)基础纹理

一、UV坐标

Q:什么是UV坐标?

A:顶点在纹理中对应的2D坐标,通常用(u,v)表示。

Q:UV坐标取值范围?

A:纹理有很多种像素大小,但是UV坐标通常被归一化在[0,1]范围内。

Q:原点(0,0)在纹理哪个位置?

A:左下角。

 二、单张纹理

 1 // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
 2 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
 3 
 4 Shader "Unlit/SingleTexture"
 5 {
 6     Properties
 7     {
 8         _MainTex("Texture", 2D) = "white" {}
 9         _Color("Color",Color) = (1,1,1,1)
10         _Specular("Specular", Color) = (1, 1, 1, 1)
11         _Gloss("Gloss",Range(8.0,256)) = 20
12     }
13         SubShader
14         {
15             Pass
16             {
17                 Tags { "LightMode" = "ForwardBase" }
18 
19                 CGPROGRAM
20                 #pragma vertex vert
21                 #pragma fragment frag
22 
23                 #include "Lighting.cginc"
24 
25                 sampler2D _MainTex;
26                 fixed4 _Color;
27                 fixed4 _Specular;
28                 float _Gloss;
29                 float4 _MainTex_ST;
30 
31             struct a2v //顶点着色器的输入结构体
32             {
33                 float4 vertex : POSITION;
34                 float3 normal:NORMAL;
35                 float4 texcoord : TEXCOORD0;
36             };
37 
38             struct v2f  //顶点着色器的输出结构体
39             {
40                 float4 pos : SV_POSITION;
41                 float3 worldNormal:TEXCOORD0;
42                 float3 worldPos:TEXCOORD1;
43                 float2 uv:TEXCOORD2;
44             };
45 
46             //顶点着色器
47             v2f vert(a2v v)
48             {
49                 v2f o;
50                 o.pos = UnityObjectToClipPos(v.vertex);
51                 o.worldNormal = UnityObjectToWorldNormal(v.normal);
52                 o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
53                 o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
54                 return o;
55             }
56 
57             fixed4 frag(v2f i) : SV_Target
58             {
59                 fixed3 worldNormal = normalize(i.worldNormal);//计算世界空间下的法线方向
60                 fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));//计算世界空间下的光照方向
61                 //材质的反射率
62                 fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb; //tex2D纹理采样:第一个参数:需要被采样的纹理,第二个参数:纹理坐标
63                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; //环境光照*材质反射率=环境光
64                 fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir));//漫反射
65                 fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
66                 fixed3 halfDir = normalize(worldLightDir + viewDir);
67                 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss); //高光反射
68                 return fixed4(ambient + diffuse + specular, 1.0);
69             }
70             ENDCG
71         }
72 
73         }
74             Fallback "Specular"
75 }
View Code

三、凹凸映射

使用一张纹理来修改模型的表面法线。

方法一:高度纹理:模拟表面位移然后得到一个修改后的发现值。

高度图的颜色越浅表示越凸。

优点:直观。

缺点:计算复杂。由像素灰度值计算而得。

方法二:法线纹理:直接存储表面法线。

法线方向分量范围 [-1,1]

像素分量范围[0,1]

相互转换:pixel = ( normal + 1 ) / 2

       normal = pixel * 2 -1

切线空间的法线纹理

优点:实现简单;边界更平滑;自由度高(见与模型空间法线区别);可进行UV动画;可重用;可压缩。

与模型空间法线区别:模型空间法线纹理记录的是绝对法线信息,仅可用于创建它时的那个模型,不能应用到其他模型。

而切线空间下法线纹理是相对法线信息,就算应用到不同网格上,也可以得到一个合理的结果。

实现:

1. 切线空间下计算:

思路:在片元着色器中通过纹理采样 => 切线空间下的法线

顶点着色器:从模型空间变换到切线空间 =>

计算视角方向、光照方向 => 光照结果

 1 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
 2 
 3 Shader "Unity Shaders Book/Chapter 7/Normal Map In Tangent Space" {
 4     Properties {
 5         _Color ("Color Tint", Color) = (1, 1, 1, 1)
 6         _MainTex ("Main Tex", 2D) = "white" {}
 7         _BumpMap ("Normal Map", 2D) = "bump" {}  //法线纹理,bump是内置纹理
 8         _BumpScale ("Bump Scale", Float) = 1.0   //控制凹凸层度
 9         _Specular ("Specular", Color) = (1, 1, 1, 1)
10         _Gloss ("Gloss", Range(8.0, 256)) = 20
11     }
12     SubShader {
13         Pass { 
14             Tags { "LightMode"="ForwardBase" }
15         
16             CGPROGRAM
17             
18             #pragma vertex vert
19             #pragma fragment frag
20             
21             #include "Lighting.cginc"
22             
23             fixed4 _Color;
24             sampler2D _MainTex;
25             float4 _MainTex_ST;
26             sampler2D _BumpMap;
27             float4 _BumpMap_ST;
28             float _BumpScale;
29             fixed4 _Specular;
30             float _Gloss;
31             
32             struct a2v {
33                 float4 vertex : POSITION;
34                 float3 normal : NORMAL;
35                 float4 tangent : TANGENT;   //切线方向 第4个坐标用来表示副切线的方向
36                 float4 texcoord : TEXCOORD0;
37             };
38             
39             struct v2f {
40                 float4 pos : SV_POSITION;
41                 float4 uv : TEXCOORD0;
42                 float3 lightDir: TEXCOORD1;
43                 float3 viewDir : TEXCOORD2;
44             };
45             
46             v2f vert(a2v v) {
47                 v2f o;
48                 o.pos = UnityObjectToClipPos(v.vertex);
49                 
50                 o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
51                 o.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;
52                 
53                 //UnityCG.cginc中定义,直接得到rotation变换矩阵
54                 TANGENT_SPACE_ROTATION;
55                 
56                 o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)).xyz;//把模型空间下的光照变换到切线空间
57                 o.viewDir = mul(rotation, ObjSpaceViewDir(v.vertex)).xyz; //把模型空间下的视角方向变换到切线空间
58                 
59                 return o;
60             }
61             
62             fixed4 frag(v2f i) : SV_Target {                
63                 fixed3 tangentLightDir = normalize(i.lightDir);
64                 fixed3 tangentViewDir = normalize(i.viewDir);
65                 
66                 fixed4 packedNormal = tex2D(_BumpMap, i.uv.zw); //对法线纹理采样
67                 fixed3 tangentNormal;
68                 
69                 tangentNormal = UnpackNormal(packedNormal);
70                 tangentNormal.xy *= _BumpScale;
71                 tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));
72                 
73                 fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;
74                 
75                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
76                 
77                 fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(tangentNormal, tangentLightDir));
78 
79                 fixed3 halfDir = normalize(tangentLightDir + tangentViewDir);
80                 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(tangentNormal, halfDir)), _Gloss);
81                 
82                 return fixed4(ambient + diffuse + specular, 1.0);
83             }
84             
85             ENDCG
86         }
87     } 
88     FallBack "Specular"
89 }
View Code

效果图:

凹凸层度调成-1,就是凸起效果:

 2. 世界空间下计算

在片元着色器中把法线方向从切线空间变换到世界空间下。

顶点着色器:顶点切线、副切线、法线 => 从切线空间到世界空间的变换矩阵,传递给片元着色器。

片元着色器:法线方向从切空间转换到世界空间。

 1 // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
 2 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
 3 
 4 Shader "Unity Shaders Book/Chapter 7/Normal Map In World Space" {
 5     Properties {
 6         _Color ("Color Tint", Color) = (1, 1, 1, 1)
 7         _MainTex ("Main Tex", 2D) = "white" {}
 8         _BumpMap ("Normal Map", 2D) = "bump" {}
 9         _BumpScale ("Bump Scale", Float) = 1.0
10         _Specular ("Specular", Color) = (1, 1, 1, 1)
11         _Gloss ("Gloss", Range(8.0, 256)) = 20
12     }
13     SubShader {
14         Pass { 
15             Tags { "LightMode"="ForwardBase" }
16         
17             CGPROGRAM
18             
19             #pragma vertex vert
20             #pragma fragment frag
21             
22             #include "Lighting.cginc"
23             
24             fixed4 _Color;
25             sampler2D _MainTex;
26             float4 _MainTex_ST;
27             sampler2D _BumpMap;
28             float4 _BumpMap_ST;
29             float _BumpScale;
30             fixed4 _Specular;
31             float _Gloss;
32             
33             struct a2v {
34                 float4 vertex : POSITION;
35                 float3 normal : NORMAL;
36                 float4 tangent : TANGENT;
37                 float4 texcoord : TEXCOORD0;
38             };
39             
40             struct v2f {
41                 float4 pos : SV_POSITION;
42                 float4 uv : TEXCOORD0;
43                 float4 TtoW0 : TEXCOORD1;  
44                 float4 TtoW1 : TEXCOORD2;  
45                 float4 TtoW2 : TEXCOORD3; 
46             };
47             
48             v2f vert(a2v v) {
49                 v2f o;
50                 o.pos = UnityObjectToClipPos(v.vertex);
51                 
52                 o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
53                 o.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;
54                 
55                 float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;  
56                 fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);  
57                 fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);  
58                 fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w; 
59                 
60                 // Compute the matrix that transform directions from tangent space to world space
61                 // Put the world position in w component for optimization
62                 o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
63                 o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
64                 o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
65                 
66                 return o;
67             }
68             
69             fixed4 frag(v2f i) : SV_Target {
70                 // Get the position in world space        
71                 float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);
72                 // Compute the light and view dir in world space
73                 fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
74                 fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
75                 
76                 // Get the normal in tangent space
77                 fixed3 bump = UnpackNormal(tex2D(_BumpMap, i.uv.zw));
78                 bump.xy *= _BumpScale;
79                 bump.z = sqrt(1.0 - saturate(dot(bump.xy, bump.xy)));
80                 // Transform the narmal from tangent space to world space
81                 bump = normalize(half3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz, bump), dot(i.TtoW2.xyz, bump)));
82                 
83                 fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;
84                 
85                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
86                 
87                 fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(bump, lightDir));
88 
89                 fixed3 halfDir = normalize(lightDir + viewDir);
90                 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(bump, halfDir)), _Gloss);
91                 
92                 return fixed4(ambient + diffuse + specular, 1.0);
93             }
94             
95             ENDCG
96         }
97     } 
98     FallBack "Specular"
99 }
View Code

四、渐变纹理

 1 // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
 2 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
 3 
 4 Shader "Unity Shaders Book/Chapter 7/Ramp Texture" {
 5     Properties {
 6         _Color ("Color Tint", Color) = (1, 1, 1, 1)
 7         _RampTex ("Ramp Tex", 2D) = "white" {}
 8         _Specular ("Specular", Color) = (1, 1, 1, 1)
 9         _Gloss ("Gloss", Range(8.0, 256)) = 20
10     }
11     SubShader {
12         Pass { 
13             Tags { "LightMode"="ForwardBase" }
14         
15             CGPROGRAM
16             
17             #pragma vertex vert
18             #pragma fragment frag
19 
20             #include "Lighting.cginc"
21             
22             fixed4 _Color;
23             sampler2D _RampTex;
24             float4 _RampTex_ST;
25             fixed4 _Specular;
26             float _Gloss;
27             
28             struct a2v {
29                 float4 vertex : POSITION;
30                 float3 normal : NORMAL;
31                 float4 texcoord : TEXCOORD0;
32             };
33             
34             struct v2f {
35                 float4 pos : SV_POSITION;
36                 float3 worldNormal : TEXCOORD0;
37                 float3 worldPos : TEXCOORD1;
38                 float2 uv : TEXCOORD2;
39             };
40             
41             v2f vert(a2v v) {
42                 v2f o;
43                 o.pos = UnityObjectToClipPos(v.vertex);
44                 
45                 o.worldNormal = UnityObjectToWorldNormal(v.normal);
46                 
47                 o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
48                 
49                 o.uv = TRANSFORM_TEX(v.texcoord, _RampTex);
50                 
51                 return o;
52             }
53             
54             fixed4 frag(v2f i) : SV_Target {
55                 fixed3 worldNormal = normalize(i.worldNormal);
56                 fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
57                 
58                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
59                 
60                 // Use the texture to sample the diffuse color
61                 fixed halfLambert  = 0.5 * dot(worldNormal, worldLightDir) + 0.5;//半兰伯特模型
62                 fixed3 diffuseColor = tex2D(_RampTex, fixed2(halfLambert, halfLambert)).rgb * _Color.rgb;
63                 
64                 fixed3 diffuse = _LightColor0.rgb * diffuseColor;
65                 
66                 fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
67                 fixed3 halfDir = normalize(worldLightDir + viewDir);
68                 fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);
69                 
70                 return fixed4(ambient + diffuse + specular, 1.0);
71             }
72             
73             ENDCG
74         }
75     } 
76     FallBack "Specular"
77 }
View Code

需要注意,要把渐变纹理的Wrap Mode改为Clamp模式,因为精度问题,Repeat模式可能会在高光区域反黑点。

五、遮罩纹理

遮罩有什么作用?遮罩允许我们可以保护某些区域,使他们免于某些修改。

 1 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
 2 
 3 Shader "Unity Shaders Book/Chapter 7/Mask Texture" {
 4     Properties {
 5         _Color ("Color Tint", Color) = (1, 1, 1, 1)
 6         _MainTex ("Main Tex", 2D) = "white" {}
 7         _BumpMap ("Normal Map", 2D) = "bump" {}
 8         _BumpScale("Bump Scale", Float) = 1.0
 9         _SpecularMask ("Specular Mask", 2D) = "white" {} //遮罩纹理
10         _SpecularScale ("Specular Scale", Float) = 1.0  //遮罩影响度
11         _Specular ("Specular", Color) = (1, 1, 1, 1)
12         _Gloss ("Gloss", Range(8.0, 256)) = 20
13     }
14     SubShader {
15         Pass { 
16             Tags { "LightMode"="ForwardBase" }
17         
18             CGPROGRAM
19             
20             #pragma vertex vert
21             #pragma fragment frag
22             
23             #include "Lighting.cginc"
24             
25             fixed4 _Color;
26             sampler2D _MainTex;
27             float4 _MainTex_ST;
28             sampler2D _BumpMap;
29             float _BumpScale;
30             sampler2D _SpecularMask;
31             float _SpecularScale;
32             fixed4 _Specular;
33             float _Gloss;
34             
35             struct a2v {
36                 float4 vertex : POSITION;
37                 float3 normal : NORMAL;
38                 float4 tangent : TANGENT;
39                 float4 texcoord : TEXCOORD0;
40             };
41             
42             struct v2f {
43                 float4 pos : SV_POSITION;
44                 float2 uv : TEXCOORD0;
45                 float3 lightDir: TEXCOORD1;
46                 float3 viewDir : TEXCOORD2;
47             };
48             
49             v2f vert(a2v v) {
50                 v2f o;
51                 o.pos = UnityObjectToClipPos(v.vertex);
52                 
53                 o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
54                 
55                 TANGENT_SPACE_ROTATION;
56                 o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)).xyz;
57                 o.viewDir = mul(rotation, ObjSpaceViewDir(v.vertex)).xyz;
58                 
59                 return o;
60             }
61             
62             fixed4 frag(v2f i) : SV_Target {
63                  fixed3 tangentLightDir = normalize(i.lightDir);
64                 fixed3 tangentViewDir = normalize(i.viewDir);
65 
66                 fixed3 tangentNormal = UnpackNormal(tex2D(_BumpMap, i.uv));
67                 tangentNormal.xy *= _BumpScale;
68                 tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));
69 
70                 fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;
71                 
72                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
73                 
74                 fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(tangentNormal, tangentLightDir));
75                 
76                  fixed3 halfDir = normalize(tangentLightDir + tangentViewDir);
77                  // Get the mask value
78                  fixed specularMask = tex2D(_SpecularMask, i.uv).r * _SpecularScale;
79                  // Compute specular term with the specular mask
80                  fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(tangentNormal, halfDir)), _Gloss) * specularMask;
81             
82                 return fixed4(ambient + diffuse + specular, 1.0);
83             }
84             
85             ENDCG
86         }
87     } 
88     FallBack "Specular"
89 }
View Code

 

posted @ 2022-02-17 18:08  番茄玛丽  阅读(154)  评论(0编辑  收藏  举报