1
1

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 1 year has passed since last update.

【Unity】HLSLPROGRAMでReflection Probeを反映させたい【URP】

Last updated at Posted at 2024-01-27

自己紹介

HLSLシェーダーの魔導書を誕生日プレゼントにもらってシェーダーに入門した大学生。

今回の記事の背景

Build-in RenderPipeline時代のUnityは「CG言語」というものでシェーダーを書いていたそうです。
しかし、SRP(URP / HDRPの基盤)となってからは「HLSL言語」が推奨されています。
こちらのほうが最適化されているそうです。
詳しくは以下のQiitaをご覧ください。

一方で、ネットには今でもCG言語でかかれたものが多く、HLSL言語で書かれたものは比較的少ないです。

今回はHLSL言語を学ぶ過程で、せっかくならHLSL言語の記事を増やそうというノリで書いています。

本題

鏡面反射の実装でUnityではReflection Probeを使うことが多いと思います。(知らんけど)
ということで、それをHLSLで実装する方法です。

CG言語版はCAの矢野さんが書かれています。

Unityの環境

Unity : 2023.2.3f1
URP : 16.0.4

URPもうすぐRender Graphってやつで作り直されるらしいけどそれでも使えるよ…ね?

コード

Reflection.shader
Shader "Custom/Reflection"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 WorldPos : TEXCOORD0;
                float3 worldNormal : TEXCOORD1;
                float3 pos : TEXCOORD2;
            };

            v2f vert (appdata v)
            {
                v2f o = (v2f) 0;
                o.vertex = TransformObjectToHClip(v.vertex.xyz);
                o.worldNormal = TransformObjectToWorldNormal(v.normal, true);
                return o;
            }

            half4 frag (v2f i) : SV_Target
            {
                half3 worldViewDir = normalize(_WorldSpaceCameraPos - i.WorldPos);
                half3 reflectDir = normalize(reflect(-worldViewDir, i.worldNormal));

                half4 envCol = SAMPLE_TEXTURECUBE(unity_SpecCube0, samplerunity_SpecCube0, reflectDir);
                envCol.rgb = DecodeHDREnvironment(envCol, unity_SpecCube0_HDR);
                return envCol;
            }
            ENDHLSL
        }
    }
}

こちらのコードは実はほぼコピペではあるのですが、ところどころ改良しています。

ポイント

ここからは上記で挙げた矢野さんの記事を参考にCG言語との差を見ていきたいと思います。

オブジェクト空間からスクリーン空間へ

ここは組み込み関数がUnityObjectToClipPosからTransformObjectToHClipに変更されています。

この関数はPackages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlslの中でincludeされている、Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlslでincludeされているPackages/com.unity.render-pipelines.core/ShaderLibrary/SpaceTransforms.hlslで定義されています。

遠すぎです。

同様にUnityObjectToWorldNormalTransformObjectToWorldNormalに変更されています。

Reflection Probeのサンプリングの方法

ここが一番情報なくて困りました…
正直コードの通りとしかいいようがないです!

またDecodeHDREnviromentは、Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlslでincludeされているPackages/com.unity.render-pipelines.universal/ShaderLibrary/GlobalIllumination.hlslでincludeされているPackages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlslで実装されています。

とおおおおおおおおおおおおおいのよ全部

結果

image.png

このようにレンダリングされます。
(矢野さんに見習ってSceneビューで:thinking:

まとめ

組み込み関数のリファレンスが本当になくて、めちゃめちゃ大変。。。

これからもHLSLの記事を少しずつ世に増やして行ければと思ってます。
ではまた…!

参考にした記事

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?