当前位置:   article > 正文

【Shader笔记5】基础纹理-凹凸映射_浅凸

浅凸

一.高度纹理(高度映射)
1.模拟表面位移,得到一个修改后的法线值
2.每一张高度纹理存储的是强度值,表示模型表面局部的海拔高度
3.深:凹,浅:凸
在这里插入图片描述
二.法线纹理(法线映射)
1.直接存储表面的法线方向
2.由于法线方向的分量范围为【-1,1】,而像素的分量范围为【0,1】,所以需要做一个映射
pixel=(normal+1)/2;(pixel法线纹理的顶点)
Normal=pixel x 2 -1;
3.两种空间下的法线纹理
1)模型空间的法线纹理:模型顶点自带的法线,是定义在模型空间中的,将这些修改后的表面法线存储在一张纹理中;
(所有的法线都在用一个坐标空间下,即模型空间但法线方向各异)
(为什么是彩色的呢?:因为法线方向各异,映射后存储到纹理就是不同的颜色)
在这里插入图片描述
2)切线空间的法线纹理
切线空间:原点为该顶点本身,z轴是法线方向(n),x轴是顶点的切线方向(t),y轴是副切线(b)/副法线;,副切线可由法线和切线叉积而得
(每个法线方向所在的坐标空间是不一样的)
(为什么是蓝色的呢?:法线方向一直在z轴映射后就是蓝色,大片的蓝色说明大部分蓝色是和模型本身法线一样)
在这里插入图片描述
4.代码
1) _NormalMap(“Normal Map”,2D)=“bump”{}
“bump”是unity内置的法线纹理,当没有提供任何法线纹理时,“bump”就对应了模型自带的法线信息。
2)tangent的类型是float4,因为要使用tangent.w分量来决定切线空间中的第三个坐标轴-副切线的方向性;(切线和法线垂直的方向有两个)
3)当使用“UnpackNormal”函数计算法线纹理中的法线方向时,需要把纹理类型标识为“Normal Map”;
如果不是标识为“Normal Map”的话,则要用
//fixed3 tangentNormal = normalize(normalColor.xyz * 2 -1); //如果贴图没有标识“Normal Map”,则用这种方法转换
有标识的话
fixed3 tangentNormal = UnpackNormal(normalColor); //用系统自带的转换

整体思路:就是添加法线贴图,然后把法线和平行光从世界空间转换到切线空间,不改变模型顶点法线而是改变像素点的法线方向

效果:
在这里插入图片描述
实践:
1.切线空间下

Shader "Custom/Tangent—NormalMap"
{
	Properties
	{
		_MainTex("MainTex",2D)="white"{}
		_Color("MainTex Color",COLOR)=(1,1,1,1)
		_Specular("Specular Color",Color)=(1,1,1,1)
		_Gloss("Gloss",Range(1,50))=20
		
		//“bump”没有指定法线贴图时,用自己顶点自带的法线
		_NormalMap("Normal Map",2D)="bump"{}
		_BumpScale("Bump Scale",Float)=1 //凹凸的程度
		_AlphaScale("Alpha Scale",Range(0,1))=1
	}

	SubShader
	{
		Tags{"Queue"="Transparent" "IngnoreProject"="True" "RenderType" = "Transparent"} 
		//渲染队列
		// "IngnoreProject"="True" :这个shader不会受到投影器“Projectors”的影响

		Pass
		{
			//LightMode标签是Pass标签的一种,用于定义该Pass在Unity的光照流水线中的角色
			Tags{"LightMode"="ForwardBase"}

			ZWrite off  //深度写入  关闭
			Blend SrcAlpha OneMinusSrcAlpha  //透明度混合:混合因子为【1-目标颜色的透明度值(A通道)】

			CGPROGRAM
			//定义顶点着色器和片元着色器的名字
			#pragma vertex vert
			#pragma fragment frag

			#include"Lighting.cginc"
			#include"UnityCG.cginc"

			sampler2D _MainTex;						
			float4 _MainTex_ST;//得到纹理的缩放(scale)和平移(translation) ;_MainTex_ST.xy 存储的是缩放值;_MainTex_ST.zw是偏移值
			fixed4 _Color;
			fixed4 _Specular;
			half _Gloss;
			half _AlphaScale;

			sampler2D _NormalMap;
			float4 _NormalMap_ST;
			float _BumpScale;
			
			struct a2v
			{
				float4 vertex:POSITION;  //取得顶点位置
				float3 normal:NORMAL; //切线空间的确是是通过(存储到模型里面)法线和切线确定的
				float4 tangent:TANGENT; //tangent.w是用来确定切线空间中坐标的方向
				float4 texcoord:TEXCOORD0; 			
			};
			struct v2f
			{
				float4 svPos:SV_POSITION;  //剪裁空间下的顶点坐标
				//float3 worldNormal:TEXCOORD0;
				float3 lightDir:TEXCOORD0; //切线空间下 平行光的方向
				float3 viewDir:TEXCOORD1; //世界空间下的顶点坐标
				float4 uv:TEXCOORD2; //设为float4,xy存储MainTex的纹理坐标,zw存储NormalMap的纹理坐标
			};

			v2f vert(a2v v)
			{
				v2f f;
				f.svPos=UnityObjectToClipPos(v.vertex);
				//f.worldNormal=UnityObjectToWorldNormal(v.normal); //法线从模型空间=》世界空间
				//f.worldVertex=mul(unity_ObjectToWorld,v.vertex); //顶点坐标从模型空间=》世界空间


				//对纹理进行偏移和缩放
				f.uv.xy=v.texcoord * _MainTex_ST.xy - _MainTex_ST .zw; //第一种:拆开计算
				//f.uv=TRANSFORM_TEX(v.texcoord,_MainTex);				//第二种:内置宏				
				//对法线贴图进行偏移缩放
				f.uv.zw=v.texcoord * _NormalMap_ST.xy - _NormalMap_ST .zw; 

				TANGENT_SPACE_ROTATION;  //调用这个宏之后,会得到一个矩阵 rotation ,这个矩阵用来把模型空间下的方向转换为切线空间下的
				f.lightDir= mul(rotation,ObjSpaceLightDir(v.vertex)); // ObjSpaceLightDir(v.vertex) 模型空间下平行光的方向
				f.viewDir=mul(rotation,ObjSpaceViewDir(v.vertex));

				return f;
			}
			//从法线贴图里面取得的法线方向是在切线空间下的
			//平行光也要从实践空间下转换到切线空间下
			fixed4 frag(v2f f):SV_TARGET
			{
				//fixed3 normalDir = normalize(f.worldNormal); //原本的世界空间下的法线
				fixed4 normalColor= tex2D( _NormalMap,f.uv.zw);
				//fixed3 tangentNormal = normalize(normalColor.xyz * 2 -1); //如果贴图没有标识为“Normal Map”,则用这种方法转换
				fixed3 tangentNormal = UnpackNormal(normalColor); //用系统自带的转换
				tangentNormal.xy=tangentNormal.xy * _BumpScale;
				tangentNormal=normalize(tangentNormal);

				fixed3 lightDir=normalize(f.lightDir); //光线向量				
				fixed3 viewDir=normalize((f.viewDir)); //视野方向

				fixed3 texColor=tex2D(_MainTex,f.uv)*_Color; //纹理颜色
				fixed3 ambient=normalize(UNITY_LIGHTMODEL_AMBIENT).rgb * texColor; //环境光颜色,*texColor环境光和纹理融合效果好点
				fixed3 diffuse=_LightColor0.rgb * texColor.rgb * max(0,dot(lightDir ,tangentNormal)); //漫反射			
				//fixed3 specular=_LightColor0.rgb * _Specular.rgb * pow ( max(0,dot(normalDir,halfDir) ),_Gloss); //高光反射		
				
				fixed3 tempcolor= diffuse + ambient; //
				return fixed4(tempcolor,_AlphaScale);
			}
			ENDCG
		}
	}
	FallBack"SPECULAR"
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112

2.世界空间下

Shader "Custom/World—NormalMap"
{
	Properties {
		_Color ("Color Tint", Color) = (1, 1, 1, 1)
		_MainTex ("Main Tex", 2D) = "white" {}
		_BumpMap ("Normal Map", 2D) = "bump" {}
		_BumpScale ("Bump Scale", Float) = 1.0
		_Specular ("Specular", Color) = (1, 1, 1, 1)
		_Gloss ("Gloss", Range(8.0, 256)) = 20
			}
	SubShader {
		Pass { 
			Tags { "LightMode"="ForwardBase" }
		
			CGPROGRAM
			
			#pragma vertex vert
			#pragma fragment frag
			
			#include "Lighting.cginc"
			
			fixed4 _Color;
			sampler2D _MainTex;
			float4 _MainTex_ST;
			sampler2D _BumpMap;
			float4 _BumpMap_ST;
			float _BumpScale;
			fixed4 _Specular;
			float _Gloss;
			
			struct a2v {
				float4 vertex : POSITION;
				float3 normal : NORMAL;
				float4 tangent : TANGENT;
				float4 texcoord : TEXCOORD0;
			};
			
			struct v2f {
				float4 pos : SV_POSITION;
				float4 uv : TEXCOORD0;
				
				//从切线空间到世界空间的变换矩阵,TtoW0,TtoW1,TtoW2代表着每一行
				float4 TtoW0 : TEXCOORD1;  
				float4 TtoW1 : TEXCOORD2;  
				float4 TtoW2 : TEXCOORD3; 
			};
			
			v2f vert(a2v v) {
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				
				o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
				o.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;
				
				//世界空间下的顶点切线,副切线和法线
				float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;  
				fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);  
				fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);  
				fixed3 worldBinormal=cross(worldNormal,worldTangent) * v.tangent.w; //副切线.法线和切线叉乘

				// Compute the matrix that transform directions from tangent space to world space
				// Put the world position in w component for optimization	
				o.TtoW0 = float4(worldTangent.x ,worldBinormal.x, worldNormal.x, worldPos.x);
				o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
				o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);

				
				return o;
			}
			
			fixed4 frag(v2f i) : SV_Target {
				//把世界空间下的顶点位置的xyz分量分别存储在了这些变量的w分量中	
				float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);
				// Compute the light and view dir in world space
				fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
				fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
			

				// Get the normal in tangent space
				fixed3 bump = UnpackNormal(tex2D(_BumpMap, i.uv.zw));
				bump.xy *= _BumpScale;			
				bump.z = sqrt(1.0 - saturate(dot(bump.xy, bump.xy)));
				//saturate函数(如果x取值小于0,则返回值为0。如果x取值大于1,则返回值为1。若x在0到1之间,则直接返回x的值.)
				//sqrt :求 x 的平方根

				// Transform the narmal from tangent space to world space
				//转换到世界空间下,通过点乘来实现矩阵的每一行和法线相乘
				bump = normalize(half3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz, bump), dot(i.TtoW2.xyz, bump)));
				
				fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;
				
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
				
				fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(bump, lightDir));

				fixed3 halfDir = normalize(lightDir + viewDir);
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(bump, halfDir)), _Gloss);
				
				return fixed4(ambient + diffuse + specular, 1.0);
			}
			
			ENDCG
		}
	} 
	FallBack "Specular"
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/649793
推荐阅读
相关标签
  

闽ICP备14008679号