SRP_05_BakedLights


一、Indirect Bake Mode

  • 烘焙的时候,会把环境光也烘焙进去
  • image-20221117204126990

静态物体

  • Light 的模式设置

    • Realtime

      • 纯实时光计算,不会有任何信息烘焙进 lightmap
    • Mixed

      • 间接光(indirect)烘焙到 lightmap
        • image-20221117204400853
      • 直接光 direct 实时计算
    • Baked

      • 直接光信息和间接光信息都烘焙到 lightmap 中

        • image-20221117204538699
      • 不会有任何实时光计算

    静态物体通过光照贴图获取间接光信息

    shader 中采样

    #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl"
    #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ImageBasedLighting.hlsl"
    
    //Lightmap
    TEXTURE2D(unity_Lightmap);
    SAMPLER(samplerunity_Lightmap);
    
    // lightMapUV 计算,使用第二套 UV
    // float2 lightMapUV : TEXCOORD1;
    // output.lightMapUV = input.lightMapUV * unity_LightmapST.xy + unity_LightmapST.zw;
        
    float3 SamplerLightMap(float2 lightMapUV)
    {
        #if defined(LIGHTMAP_ON)
            return SampleSingleLightmap(
                    TEXTURE2D_ARGS(unity_Lightmap, samplerunity_Lightmap),lightMapUV,
                    float4(1.0,1.0,0.0,0.0),
                    #if defined(UNITY_LIGHTMAP_FULL_HDR)
                        false,
                    #else
                        true,
                    #endif
                    float4(LIGHTMAP_HDR_MULTIPLIER, LIGHTMAP_HDR_EXPONENT, 0.0, 0.0)
            );
        #else
            return 0.0;
        #endif
    }

动态物体

动态物体可以通过 LightProbe 来获取间接光,较长的物体可以通过 LPPV 方式进行获取 lightProbe

通过摆放 LightProbe,可以将间接光信息烘焙到 LightProbe 中。LightProbe 数据通过球谐函数传入

  • 不使用 LPPV
    • image-20221117205303684
  • 使用 LPPV
    • image-20221117205320798
    • image-20221117205748847

LightProbe 和 LPPV 使用方式

  • 管线
SortingSettings sortingSettings = new SortingSettings(_camera)
{
    criteria = SortingCriteria.CommonOpaque
};

DrawingSettings drawingSettings = new DrawingSettings(UnlitShaderTagId, sortingSettings)
{
    enableDynamicBatching = useDynamicBatching,
    enableInstancing = useGPUInstancing,
    perObjectData =
        PerObjectData.ReflectionProbes | //启用反射探针
        PerObjectData.Lightmaps | PerObjectData.ShadowMask | //启用光照贴图、ShadowMask贴图
        PerObjectData.LightProbe | PerObjectData.OcclusionProbe | //启用 LightProbe、OcclusionProbe
        PerObjectData.LightProbeProxyVolume | PerObjectData.OcclusionProbeProxyVolume | //启用对应 LPPV 模式
};
drawingSettings.SetShaderPassName(1, LitShaderTagId);

FilteringSettings filteringSettings = new FilteringSettings(RenderQueueRange.opaque, renderingLayerMask: (uint) renderingLayerMask);
_context.DrawRenderers(_cullingResults, ref drawingSettings, ref filteringSettings);

_context.DrawSkybox(_camera);
if (_useColorTexture || _useDepthTexture)
{
    CopyAttachments();
}

sortingSettings.criteria = SortingCriteria.CommonTransparent;
drawingSettings.sortingSettings = sortingSettings;
filteringSettings.renderQueueRange = RenderQueueRange.transparent;
_context.DrawRenderers(_cullingResults, ref drawingSettings, ref filteringSettings);
  • shader
//需要使用宏定义,静态物体会开启 LIGHTMAP_ON
#pragma multi_compile _ LIGHTMAP_ON

#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/ImageBasedLighting.hlsl"

// LightProbe 的球谐函数参数
float4 unity_SHAr;
float4 unity_SHAg;
float4 unity_SHAb;
float4 unity_SHBr;
float4 unity_SHBg;
float4 unity_SHBb;
float4 unity_SHC;

//LPPV
//LightProbeProxyVolume 和 OcclusionProbeProxyVolume 使用同一个数据结构
// 如果使用了 LPPV, unity_ProbeVolumeParams.x 为 1
float4 unity_ProbeVolumeParams;
float4x4 unity_ProbeVolumeWorldToObject;
float4 unity_ProbeVolumeSizeInv;
float4 unity_ProbeVolumeMin;

//LPPV
TEXTURE3D_FLOAT(unity_ProbeVolumeSH);
SAMPLER(samplerunity_ProbeVolumeSH);

float3 SampleLightProbe (Surface surfaceWS) 
{
    #if defined(LIGHTMAP_ON)
        return 0.0;
    #else
        if (unity_ProbeVolumeParams.x)
        {
            return SampleProbeVolumeSH4(
                TEXTURE3D_ARGS(unity_ProbeVolumeSH, samplerunity_ProbeVolumeSH),
                surfaceWS.position, surfaceWS.normal,
                unity_ProbeVolumeWorldToObject,
                unity_ProbeVolumeParams.y, unity_ProbeVolumeParams.z,
                unity_ProbeVolumeMin.xyz, unity_ProbeVolumeSizeInv.xyz
            );
        }
        else
        {
            float4 coefficients[7];
            coefficients[0] = unity_SHAr;
            coefficients[1] = unity_SHAg;
            coefficients[2] = unity_SHAb;
            coefficients[3] = unity_SHBr;
            coefficients[4] = unity_SHBg;
            coefficients[5] = unity_SHBb;
            coefficients[6] = unity_SHC;
            return max(0.0, SampleSH9(coefficients, surfaceWS.normal));
        }
    
    #endif
}

Unity 烘焙的硬编码

Unity 烘焙使用硬编码 _MainTex、Color、_Cutoff 来进行计算 alpha 的

Unity 根据材质球的渲染队列来判断使用哪种方式进行计算 alpha

  • 支持的半透明烘焙,材质球渲染队列为:Transparent & 3000
  • image-20221117210211939
  • 支持的 Clip 烘焙,材质球渲染队列为: AlphaTest & 2450
  • image-20221117210219469
  • 正常不透明的烘焙,材质球渲染队列为:Opaque & 2000
  • image-20221117210232094

Directional Mode

https://catlikecoding.com/unity/tutorials/rendering/part-16/

正常烘焙的间接光信息是没有法线计算的,所以没有凹凸效果,细节效果Unity 支持 Dominant Direction 模式

image-20221122155447769

image-20221122155050083

shader使用

//宏定义
#pragma multi_compile _ DIRLIGHTMAP_COMBINED // 启用 DirectionalMode
#pragma multi_compile _ LIGHTMAP_ON

//贴图名字
#define LIGHTMAP_NAME unity_Lightmap
#define LIGHTMAP_INDIRECTION_NAME unity_LightmapInd //DirectionalLightmap 贴图名称

//使用 SampleLightmap 中的分子
#if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED)
    diffuseLighting = SampleDirectionalLightmap(TEXTURE2D_LIGHTMAP_ARGS(LIGHTMAP_NAME, LIGHTMAP_SAMPLER_NAME),
        TEXTURE2D_LIGHTMAP_ARGS(LIGHTMAP_INDIRECTION_NAME, LIGHTMAP_SAMPLER_NAME),
        LIGHTMAP_SAMPLE_EXTRA_ARGS, transformCoords, normalWS, encodedLightmap, decodeInstructions);
#elif defined(LIGHTMAP_ON)
    diffuseLighting = SampleSingleLightmap(TEXTURE2D_LIGHTMAP_ARGS(LIGHTMAP_NAME, LIGHTMAP_SAMPLER_NAME), LIGHTMAP_SAMPLE_EXTRA_ARGS, transformCoords, encodedLightmap, decodeInstructions);
#endif
    
//具体方法
//directional Lightmap 存储的不是单位向量的灯光方向
//通过使用半兰伯特计算,来模拟表面受到多个光照后的效果
void SampleDirectionalLightmap(TEXTURE2D_LIGHTMAP_PARAM(lightmapTex, lightmapSampler), TEXTURE2D_LIGHTMAP_PARAM(lightmapDirTex, lightmapDirSampler), LIGHTMAP_EXTRA_ARGS, float4 transform,
    float3 normalWS, float3 backNormalWS, bool encodedLightmap, real4 decodeInstructions, inout real3 bakeDiffuseLighting, inout real3 backBakeDiffuseLighting)
{
     // In directional mode Enlighten bakes dominant light direction
    // in a way, that using it for half Lambert and then dividing by a "rebalancing coefficient"
    // gives a result close to plain diffuse response lightmaps, but normalmapped.

    // Note that dir is not unit length on purpose. Its length is "directionality", like
    // for the directional specular lightmaps.

    // transform is scale and bias
    uv = uv * transform.xy + transform.zw;

    real4 direction = SAMPLE_TEXTURE2D_LIGHTMAP(lightmapDirTex, lightmapDirSampler, LIGHTMAP_EXTRA_ARGS_USE);
    // Remark: baked lightmap is RGBM for now, dynamic lightmap is RGB9E5
    real3 illuminance = real3(0.0, 0.0, 0.0);
    if (encodedLightmap)
    {
        real4 encodedIlluminance = SAMPLE_TEXTURE2D_LIGHTMAP(lightmapTex, lightmapSampler, LIGHTMAP_EXTRA_ARGS_USE).rgba;
        illuminance = DecodeLightmap(encodedIlluminance, decodeInstructions);
    }
    else
    {
        illuminance = SAMPLE_TEXTURE2D_LIGHTMAP(lightmapTex, lightmapSampler, LIGHTMAP_EXTRA_ARGS_USE).rgb;
    }

    real halfLambert = dot(normalWS, direction.xyz - 0.5) + 0.5;
    bakeDiffuseLighting += illuminance * halfLambert / max(1e-4, direction.w);

    real backHalfLambert = dot(backNormalWS, direction.xyz - 0.5) + 0.5;
    backBakeDiffuseLighting += illuminance * backHalfLambert / max(1e-4, direction.w);
}

image-20221122160035650

Bakery 支持烘焙更多 Directional 方式

image-20221122160605640

问题

光照探针是如何存储数据的,如何存储自定义数据?

unity_OneOverOutputBoost,unity_MaxOutputValue


文章作者: 血魂S
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 血魂S !
  目录