UnityShader学习笔记(凹凸映射)

法线纹理

法线纹理中存储的就是表面的法线方向。由于法线方向的分量范围在[-1, 1],而像素的分量范围为[0, 1],因此我们需要做一个映射, 通常使用的映射就是:normal + 12

这就要求,我们在Shader中对法线纹理进行纹理采样后,还需要对结果进行一次反映射的过程,以得到原先的法线方向。反映射的过程实际就是使用上面映射函数的逆函数:normal-pixelx2- -1

在切线空间下进行光照计算

		//纹理贴图
        _MainTex("MainTex",2D)="white"{}
        //法线贴图
        _BumpMap("Normal Map",2D) = "bump"{}
        //定义
        	sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _BumpMap;
            float4 _BumpMap_ST;
v2f vert (appdata_tan v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
                o.normalUv = TRANSFORM_TEX(v.texcoord,_BumpMap);

                //求副切线向量
                //float3 binormal = cross(normalize(v.normal),normalize(v.tangent.xyz)) * v.tangent.w;
                //float3x3 rotation = float3x3(v.tangent.xyz,binormal,v.normal);
                TANGENT_SPACE_ROTATION;

                //求切线空间光源方向及视角方向
                //我们使用Unity的内置函数ObjSpaceLightDir和ObjSpaceViewDir来得到模型空间下的光照和视角方向
                //再利用变换矩阵rotation把它们从模型空间变换到切线空间中。
                o.lightDir = mul(rotation,ObjSpaceLightDir(v.vertex)).xyz;
                o.viewDir = mul(rotation,ObjSpaceViewDir(v.vertex)).xyz;
                
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                //在切线空间进行光照计算
                //切线空间的光照方向  视角方向
                fixed3 tangentLightDir = normalize(i.lightDir);
                fixed3 tangentviewDir = normalize(i.viewDir);
                //法线贴图采样
                fixed4 packedNormal = tex2D(_BumpMap,i.normalUv);
                //UnpackNormal函数得到法线方向
                fixed3 tangentNormal = UnpackNormal(packedNormal);
                tangentNormal.xy *= _BumpScale;
                tangentNormal.z = sqrt(1 - saturate(dot(tangentNormal.xy,tangentNormal.xy)));

                //环境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 albedo = tex2D(_MainTex,i.uv).rgb;
                //漫反射
                fixed3 diffuse = _LightColor0.rgb * albedo * _Diffuse.rgb * (max(0,dot(tangentLightDir,tangentNormal))*0.5 + 0.5);
                //高光反射
                fixed3 halfDir = normalize(tangentLightDir + tangentviewDir);
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(tangentNormal,halfDir)),_Gloss);

                fixed3 color = ambient + diffuse + specular;
                return fixed4(color,1);
            }

在这里插入图片描述在这里插入图片描述
在世界空间下进行光照计算

struct v2f
            {
                float4 vertex:SV_POSITION;
                float4 uv:TEXCOORD0;
                float4 TtiW0 : TEXCOORD1;
                float4 TtiW1 : TEXCOORD2;
                float4 TtiW2 : TEXCOORD3;
            };

            v2f vert (appdata_tan v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                //TRANSFORM_TEX将模型顶点的uv和Tiling、Offset两个变量进行运算,计算出实际显示用的定点uv。
                o.uv.xy = TRANSFORM_TEX(v.texcoord,_MainTex);
                o.uv.zw = TRANSFORM_TEX(v.texcoord,_BumpMap);
                //计算世界坐标下的顶点位置,法线,切线,副法线
                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;
                //按列摆放得到从切线空间到世界空间的变化矩阵
                o.TtiW0 = float4(worldTangent.x,worldBinormal.x,worldNormal.x,worldPos.x);
                o.TtiW1 = float4(worldTangent.y,worldBinormal.y,worldNormal.y,worldPos.y);
                o.TtiW2 = float4(worldTangent.z,worldBinormal.z,worldNormal.z,worldPos.z);
                
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                //求世界坐标
                float3 worldPos =float3(i.TtiW0.w,i.TtiW1.w,i.TtiW2.w);
                //计算世界空间下的光照和视角
                fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
                fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
                //获得法线纹理
                fixed4 packedNormal = tex2D(_BumpMap,i.uv.zw);
                fixed3 tangentNormal = UnpackNormal(packedNormal);
                tangentNormal.xy *= _BumpScale;

                //切线空间法线转换到世界坐标
                fixed3 worldNormal = normalize(float3(dot(i.TtiW0.xyz,tangentNormal),dot(i.TtiW1.xyz,tangentNormal),dot(i.TtiW2.xyz,tangentNormal)));

                //环境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 albedo = tex2D(_MainTex,i.uv.xy).rgb;
                //漫反射
                fixed3 diffuse = _LightColor0.rgb * albedo * _Diffuse.rgb * (max(0,dot(lightDir,tangentNormal))*0.5 + 0.5);
                //高光反射
                fixed3 halfDir = normalize(lightDir + viewDir);
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(tangentNormal,halfDir)),_Gloss);

                fixed3 color = ambient + diffuse + specular;
                return fixed4(color,1);
            }

在这里插入图片描述
从视觉表现上, 在切线空间下和在世界空间下计算光照几乎没有任何差别。

渐变纹理

//漫反射
                fixed3 worldLightDir = UnityWorldSpaceLightDir(i.worldPos);
                fixed halfLambert = max(0,dot(worldLightDir,i.worldNormal))*0.5 + 0.5;
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * tex2D(_RampTex,fixed2(halfLambert,halfLambert));      

使用的纹理依次是:
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

在这里插入图片描述
遮罩纹理(mask texture)

它非常有用,在很多商业游戏中都可以见到它的身影。那么什么是遮罩呢?简单来讲,遮罩允许我们可以保护某些区域,使它们免于某些修改。

例如,在之前的实现中,我们都是把高光反射应用到模型表面的所有地方,即所有的像素都使用同样大小的高光强度和高光指数。但有时,我们希望模型表面某些区域的反光强烈一些,而某些区域弱一些。为了得到更加细腻的效果,我们就可以使用一张遮 罩纹理来控制光照。另一种常见的应用是在制作地形材质时需要混合多张图片,例如表现草地的纹理、表现石子的纹理、表现裸露土地的纹理等,使用遮罩纹理可以控制如何混合这些纹理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值