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

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

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

https://qiita.com/flankids/items/a92b14834792a10798e5

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

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

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

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

https://light11.hatenadiary.com/entry/2018/07/08/212014

### Unityの環境
Unity : 2023.2.3f1
URP : 16.0.4

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

## コード
```C: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`で定義されています。

遠すぎです。

同様に`UnityObjectToWorldNormal`も`TransformObjectToWorldNormal`に変更されています。
### 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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083521/f4baac2d-c108-f8ae-173f-1ba52c9ae67f.png)

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

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


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

## 参考にした記事

https://light11.hatenadiary.com/entry/2018/07/08/212014

https://qiita.com/flankids/items/a92b14834792a10798e5

https://zhuanlan.zhihu.com/p/626597575