zoukankan      html  css  js  c++  java
  • Unity shader学习之阴影

    Unity阴影采用的是 shadow map 的技术,即把摄像机放到光源位置上,看不到的地方就有阴影。

    前向渲染中,若一光源开启了阴影,Unity会计算它的阴影映射纹理(shadow map),它其实是一张深度图,记录了从光源位置出发,能看到的场景中距离它最近的表面位置的深度信息。

    Unity中采用LightMode为ShadowCaster的Pass来生成这张 shadow map,首先会从本shader中找这个pass,若没有就从fallback的shader中层层寻找。

    然后在fragment shader中,比较该点与shadow map中对应的点的深度,若大于,则处在阴影区域,否则不在阴影区域。

    阴影包括投射阴影和接收阴影2个部分。

    投射阴影,则需将该物体加入到光源的shadow map的计算中。

    接收阴影,则需要对shadow map进行采样,把采样结果和最后的光照结果相乘来产生阴影效果。

    shader如下:

    // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    
    Shader "Custom/Forward Rendering"
    {
        Properties
        {
            _MainTex("Main Texture", 2D) = "white" {}
            _Specular("Specular", Color) = (1,1,1,1)
            _Gloss("Gloss", Range(8,256)) = 8
        }
    
        SubShader
        {
            Pass
            {
                Tags
                {
                    "LightMode" = "ForwardBase"
                }
    
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #pragma multi_compile_fwdbase
    
                #include "UnityCg.cginc"
                #include "Lighting.cginc"
                #include "AutoLight.cginc"
    
                sampler2D _MainTex;
                fixed4 _Specular;
                float _Gloss;
    
                struct appdata
                {
                    float4 vertex : POSITION;
                    float2 uv : TEXCOORD0;
                    float3 normal : NORMAL;
                };
    
                struct v2f
                {
                    float4 pos : SV_POSITION;
                    float2 uv : TEXCOORD0;
                    float3 worldNormal : TEXCOORD1;
                    float4 worldPos: TEXCOORD2;
                    SHADOW_COORDS(3)
                };
    
                v2f vert(appdata v)
                {
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    o.uv = v.uv;
                    o.worldNormal = UnityObjectToWorldNormal(v.normal);
                    o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                    TRANSFER_SHADOW(o);
                    return o;
                }
    
                fixed4 frag(v2f i) : SV_TARGET
                {
                    fixed4 albedo = tex2D(_MainTex, i.uv);
                    fixed4 ambient = albedo * UNITY_LIGHTMODEL_AMBIENT;
    
                    float3 worldLight = normalize(UnityWorldSpaceLightDir(i.worldPos.xyz));
                    float3 worldView = normalize(UnityWorldSpaceViewDir(i.worldPos.xyz));
                    fixed4 diff = albedo * _LightColor0 * max(0, dot(i.worldNormal, worldLight));
    
                    float3 halfDir = normalize(worldView + worldLight);
                    fixed4 spec = albedo * _Specular * pow(max(0, dot(halfDir, i.worldNormal)), _Gloss);
    
                    float shadow = SHADOW_ATTENUATION(i);
                    fixed4 col = ambient + (diff + spec) * shadow;
                    return col;
                }
    
                ENDCG
            }
    
            Pass
            {
                Tags
                {
                    "LightMode" = "ForwardAdd"
                }
                Blend One One
    
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #pragma multi_compile_fwdadd
    
                #include "UnityCg.cginc"
                #include "Lighting.cginc"
                #include "AutoLight.cginc"
    
                sampler2D _MainTex;
                fixed4 _Specular;
                float _Gloss;
                
                struct appdata
                {
                    float4 vertex : POSITION;
                    float2 uv : TEXCOORD0;
                    float3 normal : NORMAL;
                };
    
                struct v2f
                {
                    float4 pos : SV_POSITION;
                    float2 uv : TEXCOORD0;
                    float3 worldNormal : TEXCOORD1;
                    float4 worldPos: TEXCOORD2;
                    SHADOW_COORDS(3)
                };
    
                v2f vert(appdata v)
                {
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    o.uv = v.uv;
                    o.worldNormal = UnityObjectToWorldNormal(v.normal);
                    o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                    TRANSFER_SHADOW(o);
                    return o;
                }
    
                fixed4 frag(v2f i) : SV_TARGET
                {
                    fixed4 albedo = tex2D(_MainTex, i.uv);
    
                    float3 worldLight = normalize(UnityWorldSpaceLightDir(i.worldPos.xyz));
                    float3 worldView = normalize(UnityWorldSpaceViewDir(i.worldPos.xyz));
                    fixed4 diff = albedo * _LightColor0 * max(0, dot(i.worldNormal, worldLight));
    
                    float3 halfDir = normalize(worldView + worldLight);
                    fixed4 spec = albedo * _Specular * pow(max(0, dot(halfDir, i.worldNormal)), _Gloss);
    
                    // 参考 AutoLight.cginc
                    float atten;
                    #ifdef USING_DIRECTIONAL_LIGHT
                    atten = 1;
                    #else
                        float4 lightCoord = mul(unity_WorldToLight, i.worldPos);
                        #ifdef POINT
                        atten = tex2D(_LightTexture0, dot(lightCoord.xyz,lightCoord.xyz).xx).UNITY_ATTEN_CHANNEL;
                        #elif SPOT
                        atten = (lightCoord.z > 0) * tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w * tex2D(_LightTextureB0, dot(lightCoord, lightCoord).xx).UNITY_ATTEN_CHANNEL;
                        #endif
                    #endif
    
                    float shadow = SHADOW_ATTENUATION(i);
    
                    fixed4 col = (diff + spec) * atten * shadow;
                    return col;
                }
    
                ENDCG
            }
        }
    
        Fallback "VertexLit"
    }

    效果如下:

  • 相关阅读:
    我爱java系列之---【微服务间的认证—Feign拦截器】
    我爱java系列之---【设置权限的三种解决方案】
    581. Shortest Unsorted Continuous Subarray
    129. Sum Root to Leaf Numbers
    513. Find Bottom Left Tree Value
    515. Find Largest Value in Each Tree Row
    155. Min Stack max stack Maxpop O(1) 操作
    painting house
    Minimum Adjustment Cost
    k Sum
  • 原文地址:https://www.cnblogs.com/jietian331/p/7196462.html
Copyright © 2011-2022 走看看