본문으로 바로가기

Shadowmask lightmap

category Technical Report/R&D test 2019. 2. 17. 22:21
반응형


subtactive


half4 bakedTex = UNITY_SAMPLE_TEX2D(unity_Lightmap, lightmapUV.xy);
half3 decodeColor = DecodeLightmap( bakedTex  );
col *= decodeColor;
return col;



Shadowmask

첫 번째 베이킹 그림자는 unity_Lightmap 다이어그램의 unity_ShadowMask에 없습니다. 이것은 UnityShaderVariables에 정의되어 있습니다



half4 getLightDirPerPixel(float2 lightmapUV) {
    #ifdef LIGHTMAP_ON
        half4 bakedDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, lightmapUV.xy);
        return half4(bakedDirTex.xyz-0.5h, bakedDirTex.w);
    #else
        return half4(normalize(_WorldSpaceLightPos0.xyz),1);
    #endif
}
 

이 그림자 마스크를 샘플링하려면 UnityShadowLibrary.cginc에 정의 된 UnitySampleBakedOcclusion 함수를 직접 사용할 수 있습니다



inline fixed UnitySampleBakedOcclusion (float2 lightmapUV, float3 worldPos)
{
    #if defined (SHADOWS_SHADOWMASK)
        #if defined(LIGHTMAP_ON)
            fixed4 rawOcclusionMask = UNITY_SAMPLE_TEX2D_SAMPLER(unity_ShadowMask, unity_Lightmap, lightmapUV.xy);
        #else
            fixed4 rawOcclusionMask = fixed4(1.0, 1.0, 1.0, 1.0);
            #if UNITY_LIGHT_PROBE_PROXY_VOLUME
                if (unity_ProbeVolumeParams.x == 1.0)
                    rawOcclusionMask = LPPV_SampleProbeOcclusion(worldPos);
                else
                    rawOcclusionMask = UNITY_SAMPLE_TEX2D(unity_ShadowMask, lightmapUV.xy);
            #else
                rawOcclusionMask = UNITY_SAMPLE_TEX2D(unity_ShadowMask, lightmapUV.xy);
            #endif
        #endif
        return saturate(dot(rawOcclusionMask, unity_OcclusionMaskSelector));
    #else
        //Handle LPPV baked occlusion for subtractive mode
        #if UNITY_LIGHT_PROBE_PROXY_VOLUME && !defined(LIGHTMAP_ON) && !UNITY_STANDARD_SIMPLE
            fixed4 rawOcclusionMask = fixed4(1.0, 1.0, 1.0, 1.0);
            if (unity_ProbeVolumeParams.x == 1.0)
                rawOcclusionMask = LPPV_SampleProbeOcclusion(worldPos);
            return saturate(dot(rawOcclusionMask, unity_OcclusionMaskSelector));
        #endif
        return 1.0;
    #endif
}
 




여기서는 unity_Lightmap을 직접 사용하는 샘플러 인 UNITY_SAMPLE_TEX2D_SAMPLER를 사용합니다. 그러나 unity_Lightmap을 먼저 정의하고 사용해야하며, 그렇지 않으면 컴파일러가 샘플러를 제거하고 오류를보고한다는 점에 유의해야합니다.
위의 예는 그림자 맵에 의해 계산 된 값과 유사한 감쇠 값을 반환하고 직접 색상을 곱하거나 색상을 lerp하는 데 사용합니다. 그래서 제빵의 그림자가 있습니다.

그러나 여전히 문제가 있습니다. 그림자 마스크 모드의 라이트 맵은 빼기 모드와 비교할 때 매우 어둡습니다.
Lightmap은 간접 조명이므로 실제 색상을 곱하는 대신 실시간 조명을 추가합니다.

따라서 Substractive 모드의 경우 라이트 맵에 확산을 곱하면됩니다.



half4 lightmapTex = UNITY_SAMPLE_TEX2D(unity_Lightmap, lightmapUV.xy);
half atten = SHADOW_ATTENUATION(i);
half3 directDiffuse = dot(worldNormal, lightDir) * _LightColor0.rgb;
half3 diffuse = directDiffuse * lightmapTex.xyz * atten;
return half4(diffuse + specular, 1);



하지만 그림자 마스크는 간접 조명이므로 직사광을 추가해야합니다.



half bakedAtten = UnitySampleBakedOcclusion(lightmapUV.xy, worldPos);
half directAtten = SHADOW_ATTENUATION(i);
half3 directDiffuse = dot(worldNormal, lightDir) * _LightColor0.rgb;
half3 diffuse = (indirectColor.xyz * 4.4 + directDiffuse * directAtten * bakedAtten);
return hal4(diffuse + specular, 1);



4.4의 계수에 관해서는, 그것은 시험되고 나는 놀랐다. DecodeLightmap에 2를 곱한다고하는 것이 합리적입니다. 이것은 원칙에 대해 명확하지 않습니다.




필자는 섀도우 마스크 모드 쉐이더와 내장 된 모바일 / 확산의 비교를 작성했습니다.

또한 버그가 있습니다. 내장 된 Mobile / Unlit (SupportLightmap)은 Shadowmask를 지원하지 않으며 확산으로 확산되는 것처럼 어두워집니다.

마지막으로이 셰이더를 넣으면 #if LIGHTMAP_ON 및 #if SHADOWS_SHADOWMASK 매크로 컨트롤이 사용되지 않으므로 라이트 맵 아래에만 표시 할 수 있습니다



Shader "lightmaptest"
{
       Properties
       {
              _myColor ("MainColor", color) = (1,1,1,1)
       }
       SubShader
       {
              Tags { "RenderType"="Opaque" }
              LOD 100
              Pass
              {
                     CGPROGRAM
                     #pragma vertex vert
                     #pragma fragment frag
                     #pragma multi_compile LIGHTMAP_ON
                     #pragma multi_compile SHADOWS_DEPTH SHADOWS_SCREEN
                     #pragma multi_compile SHADOWS_SHADOWMASK
                    
                     #include "UnityCG.cginc"
                     #include "AutoLight.cginc"
                     #include "UnityStandardCore.cginc"
                     struct appdata
                     {
                           float4 vertex : POSITION;
                           float2 uv : TEXCOORD0;
                           float4 texcoord1:TEXCOORD1;//lightmap uv
                           float3 normal:NORMAL;
                     };
                     struct v2f
                     {
                           float4 uv : TEXCOORD0;
                           float4 pos : SV_POSITION;
                           SHADOW_COORDS(1)
                           float4 worldPos : TEXCOORD2;
                           float3 worldNormal : TEXCOORD3;
                     };
                     fixed4 _myColor;
                    
                     v2f vert (appdata v)
                     {
                           v2f o;
                           o.pos = UnityObjectToClipPos(v.vertex);
                           o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                           o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);
                           o.uv.zw = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
                           o.worldNormal = UnityObjectToWorldNormal( v.normal);
                           TRANSFER_SHADOW(o);
                           return o;
                     }
                    
                     fixed4 frag (v2f i) : SV_Target
                     {
                           half directAtten = SHADOW_ATTENUATION(i);
                           half3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
                           half3 directColor = dot(lightDir, i.worldNormal) * _LightColor0;
                           half4 indirectColor = UNITY_SAMPLE_TEX2D(unity_Lightmap, i.uv.zw);
                           fixed bakedAtten = UnitySampleBakedOcclusion(i.uv.zw, i.worldPos);
                           half3 diffuse = (indirectColor.xyz*4.4 + (directColor)  * bakedAtten * directAtten);
                           return fixed4(diffuse , 1);
                     }
                     ENDCG
              }
       }
}








반응형