精华内容
下载资源
问答
  • //注 和切线空间法线使用的相同纹理图,但并未出现法现效果。 // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld' // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with '...

    //注 和切线空间法线使用的相同纹理图,但并未出现法现效果。

    // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

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


    Shader "Test/WorldNormalShader" 
    {
    Properties
    {
    _Color("Color",Color)=(1,1,1,1)
    _MainTex("Main",2D) = "white"{}
    _Bump("Bump",2D) = "white"{}
    _BumpScale("Scale",float) = 1
    _Specular("Specular",Color) = (1,1,1,1)
    _Gloss("Gloss",Range(1,20)) = 1
    }


    SubShader
    {
    Pass
    {
    Tags{"LightMode" = "ForwardBase"}
    CGPROGRAM


    #pragma vertex vert
    #pragma fragment frag


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


    sampler2D _MainTex;
    sampler2D _Bump;
    float4 _MainTex_ST;
    float4 _Bump_ST;
    float4 _Color;
    float4 _Specular; 
    float _BumpScale;
    float _Gloss;


    struct a2v
    {
    float4 vertex : POSITION;
    float3 normal : NORMAL;
    float4 tangent : TANGENT;
    float3 texcoord : TEXCOORD0;
    };


    struct v2f
    {
    float4 pos : SV_POSITION;
    float4 uv : TEXCOORD0;
    float4 toWorld0 : TEXCOORD1;
    float4 toWorld1 : TEXCOORD2;
    float4 toWorld2 : TEXCOORD3;


    };


    v2f vert(a2v v)
    {
    v2f o;
    o.pos = UnityObjectToClipPos(v.vertex);
    o.uv.xy = TRANSFORM_TEX(v.texcoord,_MainTex);
    o.uv.zw = TRANSFORM_TEX(v.texcoord,_Bump);


    float3 worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
    float3 worldNormal = UnityObjectToWorldNormal(v.normal);
    float3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
    float3 worldBiNormal = cross(worldNormal,worldTangent) * v.tangent.w;


    o.toWorld0 = float4(worldTangent.x,worldBiNormal.x,worldNormal.x,worldPos.x);
    o.toWorld1 = float4(worldTangent.x,worldBiNormal.x,worldNormal.x,worldPos.x);
    o.toWorld2 = float4(worldTangent.x,worldBiNormal.x,worldNormal.x,worldPos.x);




    return o;
    }


    fixed4 frag(v2f o) : SV_Target
    {
    //世界空间计算信息
    float3 worldPos = float3(o.toWorld0.w,o.toWorld1.w,o.toWorld2.w);
    float3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos)); 
    float3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));


    fixed4 packedNormal = tex2D(_Bump,o.uv.zw);
    fixed3 bumpNormal =UnpackNormal(packedNormal);
    bumpNormal.xy *= _BumpScale;
    bumpNormal.z = sqrt(1 - saturate(dot(bumpNormal.xy,bumpNormal.xy)));

    bumpNormal  = normalize(half3(dot(o.toWorld0.xyz,bumpNormal),dot(o.toWorld1.xyz,bumpNormal),dot(o.toWorld2.xyz,bumpNormal)));
    //tex2D(纹理名,UV坐标)
    float3 albedo = tex2D(_MainTex,o.uv.xy).rgb * _Color.rgb;
    //环境光
    float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
    //漫返射
    float3 diffuse = _LightColor0.rgb * albedo * saturate(dot(bumpNormal,lightDir));



    float3 halfDir = normalize(lightDir+viewDir);


    //高光反射
    float3 reflectColor = _LightColor0.rgb * _Specular * pow(saturate(dot(bumpNormal,halfDir)),_Gloss); 


    float3 finalColor = reflectColor + diffuse + ambient;
    return fixed4(finalColor,1);
    }




    ENDCG
    }
    }
    }
    展开全文
  • 关键是求出切线空间到世界空间的变换矩阵,在顶点着色其中算出该矩阵(法线向量的的变化矩阵只需要3X3的矩阵即可,但是为了充分利用插值寄存器的存储空间,把世界空间的定点位置存储在W分量中) 如果一个变换仅存在...

    在进行一些光照计算时经常需要将法线和顶点坐标,光照转到同一个坐标系下

    在游戏中发法线经常存储在切线线空间,当然也可以根据需要存储在是世界空间和模型空间等。

    1.法线由切线空间转到世界空间
    关键是求出切线空间到世界空间的变换矩阵,在顶点着色其中算出该矩阵,然后传递给片元着色器,(法线向量的的变化矩阵只需要3X3的矩阵即可,但是为了充分利用插值寄存器的存储空间,把世界空间的顶点位置存储在W分量中)得到一个3X4的矩阵。切线空间到世界空间的变换矩阵等于把世界空间的切线X轴,副法线y轴,法线Z轴的顺序按列排列。最后在片元着色其中把采样得到的法线乘以该矩阵,转化到世界空间下。由于在片元着色其中计算,所以计算量比较大。

    顶点着色器代码
    o.tTow1 = float4(WTangent.x,WBinormal.x,WNormal.x,worldPos.x);
    o.tTow2 = float4(WTangent.y,WBinormal.y,WNormal.x,worldPos.y);
    o.tTow3 = float4(WTangent.z,WBinormal.z,WNormal.x,worldPos.z);
    
    

    片元着色器

    float3 bump = UnpackNormal(tex2D(_bump,i,xy));
    //切线空间到世界空间
    float3 bumpW = normalize(half3(dot(o.tTow1.xyz,bump),half3(dot(o.tTow2.xyz,bump),half3(dot(o.tTow3.xyz,bump)));
    

    如果一个变换仅存在平移和旋转,这个变换的逆矩阵就等于它的转置矩阵

    2.光照和视角方向等从模型空间到切线空间
    从模型空间到切线空间的变换矩阵,把切线X轴,副法线y轴,法线Z轴的顺序按行排列即可得到

    //v.tangent.w和叉积结果进行相乘,W用来决定副切线的最终方向,因为垂直的方向跟左右手有关系
    float3 binormal = cross(normalize(v,normal),normalize(v.tangent.xyz))*v.tangent.w;
    float3X3 rotation = float3X3(tangent.xyz,binormal ,normal);//变换矩阵
    lightDir = mul(rotation,lightDir).xyz;
    ViewDir = mul(rotation,ViewDir).xyz;
    
    展开全文
  • 世界空间法线映射

    千次阅读 2006-05-22 03:23:00
    一看今天还挺早的(对于正常作息来说,也很“早”^^),再写点东西。最近一直在研究地形相关的东西,其中一个问题就是地形在经过了LOD处理之后,顶点光照变得不再适用。...于是就考虑使用一个法线图来计算光照,分

    一看今天还挺早的(对于正常作息来说,也很“早”^^),再写点东西。

    最近一直在研究地形相关的东西,其中一个问题就是地形在经过了LOD处理之后,顶点光照变得不再适用。因为patch的LOD级别变化时,一些顶点会突然出现或消失,如果采用顶点光照,pop顶点附近的亮度就会发生突然的改变,看起来很不自然;另一个缺点是视野中远处的地形会缺乏光照细节,因为顶点很少。

    于是就考虑使用一个法线图来计算光照,分辨率只需要每地形格一个象素,可以根据顶点坐标事先处理好。这样在近处就能有和顶点光照同样的细节度,而远处不论mesh的精度有多低,光照细节始终保持不变。地形本身不会运动,所以这种法线映射可以是世界空间的,也就是说省去了切线变换等计算(关于切线空间法线映射的原理可以看前一篇文章),在PS中采样到的法线已经是世界空间的向量,可以直接拿来计算光照,这样也不用写VS了。另外由于使用了法线映射并且不需要计算切线变换矩阵,顶点数据中就不需要附带法线信息了。

    当然只有支持ps_1_1以上的显卡才可以用,不知道固定渲染管线是否这种映射,稍后可以查一下资料。

    如果还要在地形细节纹理中使用法线映射,那切线空间的计算又变得必须了。虽然理论上在PS中根据法线图采样得到的世界空间的法线也能计算出切线变换矩阵(因为地形顶点的特殊性,顶点的平面坐标和纹理坐标是线性相关的),但那样必然造成效率上的很大损失。如果恢复顶点的normal,tangent等信息,恢复VS的切线矩阵计算的话,世界空间的法线映射又变得没有用武之地。可能比较好的折中方案是对近处的地表采用顶点法线+细节法线映射;远处的地表直接采用世界空间的法线映射,反正远处的细节凹凸也看不出来。

    这种文章没有图确实比较不爽,下回争取搞点图:)

    展开全文
  • 法线贴图有两种,一种是模型空间的贴图,也就是贴图中的法线信息是在模型空间下的,第二种是切线空间的贴图,也就是贴图中的法线信息是在切线空间下的,由于后一种要比前一种好用(绝大多数法线贴图都是这种,具体...

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

     

    最近在学习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,normalize(tangentLight+tangentView))),m_gloss);
                    return fixed4(mainTex+specular,1);
                }
    
                ENDCG
            }
        }
    }
    

    左图是普通的Blinn高光反射,右图是计算法线贴图之后的结果,多了不少细节。

    下面再来看一下在切线空间下,在FragmentShader中计算:

    我需要把vert中通过宏计算的矩阵传到frag中

    // 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;                       //纹理采样
                    float4 vertex:TEXCOORD2;                   //顶点坐标
                    float3 tangentLight:TEXCOORD3;             //切线空间下的光源方向
                    float3 tangentView:TEXCOORD4;              //切线空间下的视线方向
    
                    float3 objectToTangent1:TEXCOORD5;         //模型空间到切线空间矩阵第一行
                    float3 objectToTangent2:TEXCOORD6;         //模型空间到切线空间矩阵第二行
                    float3 objectToTangent3:TEXCOORD7;         //模型空间到切线空间矩阵第三行
                };
    
                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.objectToTangent1 = rotation[0];
                    o.objectToTangent2 = rotation[1];
                    o.objectToTangent3 = rotation[2];          //把矩阵保存起来
                    o.vertex = v.vertex;
                    return o;
                }
    
                fixed4 frag(v2f i):SV_TARGET0{
                    float3x3 objectToTangent = float3x3(i.objectToTangent1,i.objectToTangent2,i.objectToTangent3);
                    fixed3 tangentLight = normalize(mul(objectToTangent,ObjSpaceLightDir(i.vertex)));//生成切线空间下的光源向量
                    fixed3 tangentView = normalize(mul(objectToTangent,ObjSpaceViewDir(i.vertex)));//生成切线空间下的视角向量
    
                    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,normalize(tangentLight+tangentView))),m_gloss);
                    return fixed4(mainTex+specular,1);
                }
    
                ENDCG
            }
        }
    }
    

    左边依旧拿个Blinn做对比,右图是修改过后的Shader,我发现,这好像并没有什么区别。

    再详细对比一下,左图是Vert,右图是Frag,这好像还是看不出有什么区别。

    那好吧,接下来再看看在切线空间下,在FragmentShader中计算:

    // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    
    // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    
    Shader "Unlit/NormalMapWorldSpaceShader"
    {   
        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;
                    float2 uv:TEXCOORD1;
                    float4 worldVertex:TEXCOORD2;
                    float3 tangentToWorld1:TEXCOORD3;          //切线坐标转为世界坐标
                    float3 tangentToWorld2:TEXCOORD4;
                    float3 tangentToWorld3:TEXCOORD5;
                };
    
                v2f vert(appdata_full v){
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    o.worldVertex = mul(unity_ObjectToWorld,v.vertex);
                    o.uv = v.texcoord.xy*m_mainTex_ST.xy+m_mainTex_ST.zw;
    
                    float3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
                    float3 worldNormal = UnityObjectToWorldNormal(v.normal);
                    float3 worldBinormal = cross(worldNormal,worldTangent)*v.tangent.w;
                    o.tangentToWorld1 = float3(worldTangent.x,worldBinormal.x,worldNormal.x);
                    o.tangentToWorld2 = float3(worldTangent.y,worldBinormal.y,worldNormal.y);
                    o.tangentToWorld3 = float3(worldTangent.z,worldBinormal.z,worldNormal.z);
    
                    return o;                
                }
    
                fixed4 frag(v2f i):SV_TARGET0{
                    fixed3 mainTex = tex2D(m_mainTex,i.uv);
                    
                    float3 tangentNormal = UnpackNormal(tex2D(m_normalMap,i.uv));
                    float3 worldNormal = float3(dot(i.tangentToWorld1,tangentNormal),dot(i.tangentToWorld2,tangentNormal),dot(i.tangentToWorld3,tangentNormal));
                    
                    float3 worldLight = normalize(UnityWorldSpaceLightDir(i.worldVertex));
                    float3 worldView = normalize(UnityWorldSpaceViewDir(i.worldVertex));
                    fixed3 specular = _LightColor0.xyz*m_specular.xyz*pow(saturate(dot(worldNormal,normalize(worldLight+worldView))),m_gloss);
                    return fixed4(mainTex+specular,1);
                }
    
                ENDCG
            }
        }
    }

       

    左图是切线空间下,在FragmentShader中计算法线贴图,右图是在世界空间下,在FragmentShader中计算法线贴图,这个效果一样是在预料之中的。

    最后一个,看看在切线空间下,在VertexShader中计算:

    // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    
    // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    
    Shader "Unlit/NormalMapWorldSpaceShader"
    {   
        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;
                    float2 uv:TEXCOORD1;
                    float4 worldVertex:TEXCOORD2;
                    float3 tangentToWorld1:TEXCOORD3;          //切线坐标转为世界坐标
                    float3 tangentToWorld2:TEXCOORD4;
                    float3 tangentToWorld3:TEXCOORD5;
    
                    float3 worldLight:TEXCOORD6;
                    float3 worldView:TEXCOORD7;
                };
    
                v2f vert(appdata_full v){
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    o.worldVertex = mul(unity_ObjectToWorld,v.vertex);
                    o.uv = v.texcoord.xy*m_mainTex_ST.xy+m_mainTex_ST.zw;
    
                    float3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
                    float3 worldNormal = UnityObjectToWorldNormal(v.normal);
                    float3 worldBinormal = cross(worldNormal,worldTangent)*v.tangent.w;
                    o.tangentToWorld1 = float3(worldTangent.x,worldBinormal.x,worldNormal.x);
                    o.tangentToWorld2 = float3(worldTangent.y,worldBinormal.y,worldNormal.y);
                    o.tangentToWorld3 = float3(worldTangent.z,worldBinormal.z,worldNormal.z);
    
                    o.worldLight = normalize(UnityWorldSpaceLightDir(o.worldVertex));
                    o.worldView = normalize(UnityWorldSpaceViewDir(o.worldVertex));
                    return o;                
                }
    
                fixed4 frag(v2f i):SV_TARGET0{
                    fixed3 mainTex = tex2D(m_mainTex,i.uv);
                    
                    float3 tangentNormal = UnpackNormal(tex2D(m_normalMap,i.uv));
                    float3 worldNormal = float3(dot(i.tangentToWorld1,tangentNormal),dot(i.tangentToWorld2,tangentNormal),dot(i.tangentToWorld3,tangentNormal));
                    
                    
                    fixed3 specular = _LightColor0.xyz*m_specular.xyz*pow(saturate(dot(worldNormal,normalize(i.worldLight+i.worldView))),m_gloss);
                    return fixed4(mainTex+specular,1);
                }
    
                ENDCG
            }
        }
    }
    

           

    左图依然是在切线空间下,在FragmentShader中计算法线贴图,右图是在世界空间下,在VertexShader中计算法线贴图,这两者之间的区别就比较显而易见了,虽然理论上右边的计算方式是错误的,但是怎么感觉效果还要好一点

    目前可以得到一个结论,从效果上来讲,第一种方式=第二种方式=第三种方式≠第四种方式。(再次强调一下,不能保证正确性,如果有错误的话希望各位能批评指正)

    展开全文
  • // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'Shader "Custom/texture/test3" {// 定义纹理属性 增加法线纹理 Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Main
  • 一、基于切线空间坐标系的法线贴图理解:使用法线贴图是因为在低模下想获得高模凹凸表面光照效果。因为基于模型坐标系的法线贴图,在换到不同的模型下时候法线贴图不能复用。故引入切线空间法线贴图可以在相同网格...
  • 在网上看到了一篇很好的讲这两个原理的文章,这里mark一下。 http://www.cnblogs.com/flytrace/p/3387748.html 转载于:https://www.cnblogs.com/xmandy/p/5990628.html
  • Shader法线贴图(世界空间

    千次阅读 2018-09-27 12:10:51
    法线贴图,世界空间下计算 参考 《unity shader 入门精要》 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' Shader "Book/07.WorldNormal" { //法线贴图 ...
  • 问: ...是世界变换矩阵的转置的逆? struct VertexIn { float4 position : POSITION; float4 normal : NORMAL; }; struct VertexScreen { float4 oPosition : POSITION; float4 color : COLO...
  •       本文由@唐三十胖子出品,转载请注明出处。...  ...这篇文章将总结和提炼《Unity Shader入门精要》的第七章“基础纹理”的内容。...1)法线贴图概念与使用 ...2)模型空间 vs 切线空间法线纹理 3)切线空...
  • 一、坐标空间 上篇文章讲述了如何使用矩阵来表示基本的变换,如平移、旋转和缩放,在本节我们将关注如何使用这些变换来对坐标空间进行变换。 渲染游戏的过程可以理解成是把一个个顶点经过层层处理最终转换为屏幕上...
  • 这篇:我们重点讲解一下 法线从对象空间变换到世界空间 的变换矩阵的推导过程,因为之前四篇光照处理有用到,但没有细节的去讲解到。 本人才疏学浅,如有什么错误,望不吝指出。 Unity 中的处理 在 Unity ShaderLab...
  • 法线贴图中法线值的坐标空间选择

    千次阅读 2015-10-17 17:31:32
    法线贴图是目前游戏中被广泛使用的技术,通过从贴图采样...这种方法在runtime的时候,将光线从世界坐标转换到模型的局部坐标,然后在局部空间同每个pixel的采样到的法线做光照计算。这种方法有个最大的缺点就是法线
  • Shader "Unlit/WorldNormalTex" { Properties { _MainTex ("Texture", 2D) = "white" {} _MainNormalTex("NormalTex",2D) = "white"{} } SubShader { Tags { "RenderTy
  • 结论: Unity内置的矩阵UNITY_MATRIX_IT_MV,是UNITY_MATRIX_MV的逆转置矩阵,其作用正是将法线从模型空间转换到观察空间 -------------------------
  • 在学习法线贴图纹理的时候无法避免的遇到了切线空间的学习和理解的问题,在此记录下自己理解的过程。 法线纹理的目的和存在的意义: 是在底模上表现出高模的各种凹凸细节,而为什么要表现凹凸细节呢,很简单,就是...
  • 一、法线空间变换原理(源于Shader入门精要中介绍:) ...假设已知切线空间TBN,切线空间的法线Nt,计算世界空间下的法线Nw? 由于TBN是正交矩阵,所以Nw * TBN = Nt; 两边左乘TBN-1,Nw=TBN-1Nt=Nt...
  • Unity Shader 法线贴图(NormalMap)

    千次阅读 2019-08-22 09:16:17
    normalmap ...世界空间法线 彩色,因为法线会指向各个方向 切线空间法线 淡蓝色,切线空间,法线向外 无法线贴图 有法线贴图 Material面板 shader Shader "DC/Shader/ShaderDemo/NormalMa...
  • Shader "MyShader/NormalMapWorldMapSpace" { Properties { _Color("Color Tint",Color) = (1,1,1,1) _MainTex("Main Tex",2D) = "white"{} _BumpMap("Normal Map",2D) = "bump"{}...
  • 法线贴图和切线空间

    千次阅读 2018-01-10 11:58:39
    法线贴图是一种特殊的texture,法线贴图中每个像素存储的不是rgb颜色值,而是该片元的法向量。 法向量可以决定物体表面的凹凸情况,使用法线贴图可以在几乎不增加性能消耗的情况下,使得渲染出来的物体更有凹凸感,...
  • //这是计算世界空间下的顶点切线、副切线和法线的矢量表示 // 并把他们按列排放!重点:按列 :代表从切线空间到世界空间 //所以这是个3x3的变换矩阵,但是把世界空间下的顶点位置存储在这些变量的w分量...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,652
精华内容 3,060
关键字:

世界空间法线