百人计划图形篇2.5笔记(视差贴图)

该文介绍了Unity中使用Shader进行切线空间的光照计算,包括法线纹理的处理和视差映射技术。通过切线、副切线和法线构建世界空间到切线空间的转换矩阵,利用视差映射提升表面细节的真实感。文中还提到了陡峭视差映射的优化方法,虽然计算消耗较高,但能显著改善效果。
摘要由CSDN通过智能技术生成

光照的计算需要在切线空间下计算。先将法线、切线传到顶点着色器中,叉乘计算出副切线

float3x3(切线、副切线、法线)构成世界空间转切线空间转换矩阵

将法线纹理中解包UnpackNormal,参与计算。

Shader "Custom/Bump"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Main Tex", 2D) = "white" {}
        _Gloss ("Gloss", Range(8,256)) = 20
        _Specular ("Specular", Color) = (1,1,1,1)

        _BumpTex("Bump Tex",2D) = "bump"{}
        _Scale("Scale",Range(0,1)) = 0.1
        _HeightTex("Height Tex",2D) = "black"{}

    }

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

            CGPROGRAM

            #include "Lighting.cginc"

            #pragma vertex vert 
            #pragma fragment frag 

            fixed4 _Color;
            sampler2D _MainTex;
            float _Gloss;
            fixed4 _Specular;
            sampler2D _HeightTex;
            sampler2D _BumpTex;
            float _Scale;


            struct a2v
            {   
                fixed4 vertex : POSITION;
                fixed3 normal : NORMAL;
                fixed3 tangent : TANGENT;
                fixed2 texcoord : TEXCOORD0;
            };

            struct v2f
            {
                fixed4 pos : SV_POSITION;
                fixed2 uv : TEXCOORD0;

                fixed3 worldNormal : TEXCOORD1;
                fixed3 worldTangent :TEXCOORD2;
                fixed3 worldBinormal : TEXCOORD3;
                fixed3 worldPos : TEXCOORD4;
            };

            v2f vert(a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);

                o.uv = v.texcoord.xy;

                o.worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));

                o.worldTangent = normalize(mul(unity_ObjectToWorld,v.tangent));

                o.worldBinormal = normalize(cross(o.worldNormal,o.worldTangent));
                o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;





                return o;
            }


            //视差映射
            float2 ParallaxMapping(float2 uv ,float3 viewDir)
            {
                fixed height = 1 - tex2D(_HeightTex,uv).r;
                float2 offset = viewDir.xy / viewDir.z * height * _Scale;

                return uv + offset;
           
            }



            fixed4 frag(v2f i) : SV_Target
            {

                
                fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
                fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
                fixed3 worldNormal = i.worldNormal;

                float3x3 TBN = float3x3(i.worldTangent,i.worldBinormal,i.worldNormal);

                float3 viewDir = mul(TBN,worldViewDir);
                float3 lightDir = mul(TBN,worldLightDir);

                float2 uv = ParallaxMapping(i.uv,viewDir);

                fixed3 tangentNormal = UnpackNormal(tex2D(_BumpTex,uv));

                fixed3 halfDir = normalize(lightDir + viewDir);

                fixed3 albedo = _Color.rgb * tex2D(_MainTex,uv);
                fixed3 diffuse = albedo * _LightColor0.rgb * saturate(dot(lightDir,tangentNormal));
                fixed3 specular = albedo * _Specular.rgb * pow(saturate(dot(tangentNormal,halfDir)),_Gloss);



                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;




                return fixed4(diffuse + specular + ambient,1);

                
            }

            ENDCG


        }
    }
   FallBack "Specular"
}

视差映射前:

 视差映射:

 靠近了之后效果会变得很差

陡峭视差映射  :  

            float2 SteepParallaxMapping(float2 uv ,float3 viewDir)
            {
                //层数100层
                float layerNum = 100;

                //层深度初始化为1/100
                float layerHeight = 1.0/layerNum;
                
                //当前层深度为0
                float currentLayerHeight = 0.0;

                //偏移UV = 视线方向.xy / 视线方向.z * 偏移范围控制量
                float2 offLayerUV = viewDir.xy/viewDir.z*_Scale;

                //迭代增加的步数 偏移UV/100
                float2 Steeping = offLayerUV/layerNum;

                //迭代uv的增加量
                float2 AddUV = float2(0,0);

                //当前所取的uv点的深度图的值
                float currentHeightMapValue = 1-tex2D(_HeightTex,uv+AddUV);

                //当层深度>当前uv点的深度图的值时立刻返回
                for (int i = 0;i<layerNum;i++)
                {
                    if(currentLayerHeight > currentHeightMapValue)
                    {
                        return uv+AddUV;
                    }
                    AddUV += Steeping;
                    currentHeightMapValue =1- tex2D(_HeightTex,uv+AddUV);
                    currentLayerHeight+=layerHeight;

                }
                return uv+AddUV;
            }

效果会好很多,但是消耗有点高

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值