赞
踩
一.高度纹理(高度映射)
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" }
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" }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。