7
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Universal RP】ライティング計算の実装を読んでみた

Last updated at Posted at 2020-12-10

はじめに

URP向けのシェーダーを書くとき、ライト計算を自前で実装したくなることがあります。
今回は、URPのライティング計算はどこに実装されているのかを調べてみました。

ちなみに、URPのサンプルシーンのオブジェクトにはLit.shaderが使用されており、PBRのライティングが実装されています。
image.png

環境

Universal RP 8.2.0
Unity 2020.1.2f1

リアルタイム ライト

Lit.shaderのPBRリアルタイムライト計算は、Lighting.hlslUniversalFragmentPBR メソッドに実装されています。

Lighting.hlsl
///////////////////////////////////////////////////////////////////////////////
//                      Fragment Functions                                   //
//       Used by ShaderGraph and others builtin renderers                    //
///////////////////////////////////////////////////////////////////////////////
half4 UniversalFragmentPBR(InputData inputData, half3 albedo, half metallic, half3 specular,
    half smoothness, half occlusion, half3 emission, half alpha)
{
    BRDFData brdfData;
    InitializeBRDFData(albedo, metallic, specular, smoothness, alpha, brdfData);
    
    Light mainLight = GetMainLight(inputData.shadowCoord);
    MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI, half4(0, 0, 0, 0));

    half3 color = GlobalIllumination(brdfData, inputData.bakedGI, occlusion, inputData.normalWS, inputData.viewDirectionWS);
    color += LightingPhysicallyBased(brdfData, mainLight, inputData.normalWS, inputData.viewDirectionWS);

# ifdef _ADDITIONAL_LIGHTS
    uint pixelLightCount = GetAdditionalLightsCount();
    for (uint lightIndex = 0u; lightIndex < pixelLightCount; ++lightIndex)
    {
        Light light = GetAdditionalLight(lightIndex, inputData.positionWS);
        color += LightingPhysicallyBased(brdfData, light, inputData.normalWS, inputData.viewDirectionWS);
    }
# endif

# ifdef _ADDITIONAL_LIGHTS_VERTEX
    color += inputData.vertexLighting * brdfData.diffuse;
# endif

    color += emission;
    return half4(color, alpha);
}

ライトの検証

ライトの挙動を検証するため、以下のようなシーンを用意してみました
・Directional Light を配置して、影を出す
、Point Light を1つ配置
・すべてのオブジェクトにはLit.shaderをアタッチ
image.png

Main Light

Main Light は以下のように実装されています。(Lighting.hlsl)

Lighting.hlsl
    Light mainLight = GetMainLight(inputData.shadowCoord);
    MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI, half4(0, 0, 0, 0));

    half3 color = GlobalIllumination(brdfData, inputData.bakedGI, occlusion, inputData.normalWS, inputData.viewDirectionWS);
    color += LightingPhysicallyBased(brdfData, mainLight, inputData.normalWS, inputData.viewDirectionWS);

比較

LightingPhysicallyBased() の呼び出しをコメントアウトして、画面がどのように変化するのかを見ていきます。

変更前

image.png

変更後

image.png

DirectionalLightによる光が消え、画面全体が暗くなりました。

Main Lightの落ち影を消す

LitForwardPass.hlsl を見ると、シャドウマップ用のテクスチャ座標(shadowCoord)の計算処理があります。

LitForwardPass.hlsl
# if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
    inputData.shadowCoord = input.shadowCoord;
# elif defined(MAIN_LIGHT_CALCULATE_SHADOWS)
    inputData.shadowCoord = TransformWorldToShadowCoord(inputData.positionWS);
# else
    inputData.shadowCoord = float4(0, 0, 0, 0);
# endif

このshadowCoord は Main Light の影に利用されます。

Lighting.hlsl
Light GetMainLight(float4 shadowCoord)
{
    Light light = GetMainLight();
    light.shadowAttenuation = MainLightRealtimeShadow(shadowCoord);
    return light;
}

比較

inputData.shadowCoord の計算を削除したときの画面の変化を見ていきます。

変更前

image.png

変更後

image.png

落ち影が無くなりました。

Additional Light

ポイントライトなどの追加ライトは以下のコードで実装されています。(Lighting.hlsl)

Lighting.hlsl
# ifdef _ADDITIONAL_LIGHTS
    uint pixelLightCount = GetAdditionalLightsCount();
    for (uint lightIndex = 0u; lightIndex < pixelLightCount; ++lightIndex)
    {
        Light light = GetAdditionalLight(lightIndex, inputData.positionWS);
        color += LightingPhysicallyBased(brdfData, light, inputData.normalWS, inputData.viewDirectionWS);
    }
# endif

比較

LightingPhysicallyBased() の呼び出しをコメントアウトしたとき、画面がどのように変化するのかを見ていきます。

変更前

image.png

変更後

image.png

ポイントライトが照らされている部分が暗くなりました。

Baked GI (ライトマップ)

ライトのベイク情報の取得は、LitForwardPass.hlsl に実装されています。
実装コードは以下になります。

LitForwardPass.hlsl
inputData.bakedGI = SAMPLE_GI(input.lightmapUV, input.vertexSH, inputData.normalWS);

比較

SAMPLE_GI() マクロの呼び出しを削除したときに画面の変化を見ていきます。

変更前

今回は、ライトをベイクしたシーンを使用します。
image.png

変更後

image.png

SAMPLE_GI()の呼び出しを削除すると、ライトがベイクされていない状態と同じ見た目になります。

参考

Unity URP のライティング
https://note.com/npaka/n/n22986e11615e

Unity Learning Materials - ライティングのセッション
https://learning.unity3d.jp/tag/%E3%83%A9%E3%82%A4%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0/

7
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?