关于在切线空间下与世界空间下计算法线贴图

以下过程均为自己实践的过程,不能保证过程及结论的正确性。如果哪里有错误,还希望大家批评指正。

 

最近在学习shader,当学到法线贴图时,遇到了让我疑惑不解的地方。法线贴图有两种,一种是模型空间的贴图,也就是贴图中的法线信息是在模型空间下的,第二种是切线空间的贴图,也就是贴图中的法线信息是在切线空间下的,由于后一种要比前一种好用(绝大多数法线贴图都是这种,具体原因不在赘述),所以后面用的皆为切线空间中的法线贴图。在计算法线贴图时,有两种方式,一种是将光源方向、视线方向、法线(实际上法线不用转换,因为本来就是切线空间中的)转换到切线空间中,然后计算;第二种方式是将以上信息转换到世界空间中计算。然而为什么在切线空间的计算方式下,将光源向量与视线向量转换到切线空间,可以在Vertex Shader阶段完成;而在世界空间的计算方式下,将光源向量与视线向量转换到世界空间,必须要在Fragment Shader中完成,假如两者计算的位置颠倒,那么又会有什么样的变化,这个问题思考了很久,决定弄清楚再继续接下来的学习。

为了对比这四者之间的差异,我先把这四种Shader都写出来,然后对比一下效果。

限定条件:单一光源,方向光

首先是在切线空间下,在VertexShader中计算:

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Unlit/BlinnSpecular"
{
     Properties{
        m_mainTex("MainTex",2D)=""{}
        m_normalMap("NormalMap",2D)=""{}
        m_normalMapScale("NormalMapScale",Range(-10,10))=1
        m_specular("Specular",Color)=(1,1,1,1)
        m_gloss("Gloss",Range(-10,10))=1
    }
    
    SubShader{
        Pass{
            Tags{"LightMode"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            
            sampler2D m_mainTex;                           //主贴图
            float4 m_mainTex_ST;                           //主贴图缩放偏移量
            sampler2D m_normalMap;                         //法线贴图
            float m_normalMapScale;                        //凹凸程度
            fixed3 m_specular;                             //反光的颜色
            float m_gloss;                                 //反光强度

            struct v2f{
                float4 pos:SV_POSITION;                    //MVP变换后的顶点坐标
                float2 uv:TEXCOORD1;                       //纹理采样
                float3 vertex:TEXCOORD2;                   //顶点坐标
                float3 tangentLight:TEXCOORD3;             //切线空间下的光源方向
                float3 tangentView:TEXCOORD4;              //切线空间下的视线方向
            };

            v2f vert(appdata_full v){
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = v.texcoord.xy*m_mainTex_ST.xy+m_mainTex_ST.zw;
                TANGENT_SPACE_ROTATION;                    //生成将模型空间转为切线空间的矩阵
                o.tangentLight = mul(rotation,(ObjSpaceLightDir(v.vertex))).xyz;
                o.tangentView = mul(rotation,(ObjSpaceViewDir(v.vertex))).xyz;
                return o;
            }

            fixed4 frag(v2f i):SV_TARGET0{
                fixed3 tangentLight = normalize(i.tangentLight);
                fixed3 tangentView = normalize(i.tangentView);

                fixed3 mainTex = tex2D(m_mainTex,i.uv);
                fixed3 tangentNormal = UnpackNormal(tex2D(m_normalMap,i.uv));
                
                fixed3 specular = _LightColor0.xyz*m_specular*pow(saturate(dot(tangentNormal,no
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值