夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

ゼロから始めるUnityShader開発 第六章 セルルックなライティングを行う その③ハイライトの実装

本日はShader枠です。

現在はライティングについてのシェーダー構築をステップアップで見ています。

前回はShadowColorを追加して影の色を任意に変更できるようにしました。

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

今回はハイライトを実装します。

〇ハイライトの実装

ハイライトとは光が物体にあたるときにできる明るい部分を指します。

これは光源からの光が直接物体に反射して強調される光を指します。

毎度ですが、Shaderで光の当たり方の計算はNdotLです。

 float strength = dot(lt.direction, i.normalWS);

これは通常であれば1~0のグラデーションとして返されます。

ここでstep関数を使用して閾値をもとに0,1で振り分けたものがセルルックなシェーディングの影です。

                float shadow =step(0.3,strength);

この閾値を上げることで光が当たっているエリアを絞ることができます。

ここでは新たなパラメータhighlightとhightkightColorを定義し以下のように実装しました。

            float4 frag (v2f i) : SV_Target
            {
                float4 col = _MainColor;
                //Light.hlslで提供されるUnityのライトを取得する関数
                Light lt = GetMainLight();

                //ライトの向きを計算
                float strength = dot(lt.direction, i.normalWS);
                float shadow =step(0.3,strength);
                float highlight = step(0.95,strength);
                float4 lightColor = float4(lt.color, 1)*shadow;
                float4 shadowColor = _ShadowColor * (1-shadow);
                float4 hightlightColor = _HightlightColor * highlight;
                return col* (shadowColor + lightColor)+hightlightColor;
            }

 ここでhightlightColorは最終的に加算処理をしています。

この理由として加算を行うことで発光の効果が期待できるためです。 

https://redhologerbera.hatenablog.com/entry/2022/11/16/220437

今回はハイライトの閾値を0.95にしていますが、もっと上げることもできます。

最終的に以下のようにハイライトが付くようになります。

〇コード全文

Shader "Unlit/TutorialShader"
{
    Properties
    {
     //   _MainTex ("Texture", 2D) = "white" {}
        _MainColor("Color" ,color) = (1,1,1,1)
        _ShadowColor("ShadowColor",color) = (0,0,0,1)
        _HightlightColor("HightlightColor",color) = (1,1,1,1)
    }
    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;
                half3 normal: NORMAL;
            };

            struct v2f
            {
            float4 vertex : SV_POSITION;
            float3 normalWS : TEXCOORD1;
            };


            float4 _MainColor;
            float4 _ShadowColor;
            float4 _HightlightColor;
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = TransformObjectToHClip(v.vertex);
                //面の法線を取得、ライトの当たる向きを計算
                VertexNormalInputs normal = GetVertexNormalInputs(v.normal);
                o.normalWS = normal.normalWS;
                return o;
            }

            float4 frag (v2f i) : SV_Target
            {
                float4 col = _MainColor;
                //Light.hlslで提供されるUnityのライトを取得する関数
                Light lt = GetMainLight();

                //ライトの向きを計算
                float strength = dot(lt.direction, i.normalWS);
                float shadow =step(0.3,strength);
                float highlight = step(0.95,strength);
                float4 lightColor = float4(lt.color, 1)*shadow;
                float4 shadowColor = _ShadowColor * (1-shadow);
                float4 hightlightColor = _HightlightColor * highlight;
                return col* (shadowColor + lightColor)+hightlightColor;
            }
            ENDHLSL
        }
    }
}

ゼロから始めるUnityShader開発 第六章 セルルックなライティングを行う その②シャドウカラーの実装

本日はShader枠です。

 前回はライティングの一環としてセルルックなシェーダーを実装しました。

redhologerbera.hatenablog.com

 前回の状態だと影が真っ黒になります。

今回は影の色を変更可能にします。

〇影の取得

影に色を付けるためにはまずは影のピクセルを取得します。

これはNdotLにStep関数を使用した以下の個所が相当します。

                float strength = dot(lt.direction, i.normalWS);
                float shadow =step(0.3,strength);

1からこの影の値を引いた値に新しく定義する色であるShadowColorを掛け合わせることで影の色が定義できます。

                float4 shadowColor = _ShadowColor * (1-shadow);

1-shadowの理由ですが、shadowの状態では影の部分が黒になります。

黒に何を掛け合わせても黒になるため、逆数を取り色を掛け合わせます。

同様にshadowをlightColorに掛け合わせ、これらを加算することでシャドウカラーが実現できます。

〇コード全文

Shader "Unlit/TutorialShader"
{
    Properties
    {
     //   _MainTex ("Texture", 2D) = "white" {}
        _MainColor("Color" ,color) = (1,1,1,1)
        _ShadowColor("ShadowColor",color) = (0,0,0,1)
    }
    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;
                half3 normal: NORMAL;
            };

            struct v2f
            {
            float4 vertex : SV_POSITION;
            float3 normalWS : TEXCOORD1;
            };


            float4 _MainColor;
            float4 _ShadowColor;
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = TransformObjectToHClip(v.vertex);
                //面の法線を取得、ライトの当たる向きを計算
                VertexNormalInputs normal = GetVertexNormalInputs(v.normal);
                o.normalWS = normal.normalWS;
                return o;
            }

            float4 frag (v2f i) : SV_Target
            {
                float4 col = _MainColor;
                //Light.hlslで提供されるUnityのライトを取得する関数
                Light lt = GetMainLight();

                //ライトの向きを計算
                float strength = dot(lt.direction, i.normalWS);
                float shadow =step(0.3,strength);
                float4 lightColor = float4(lt.color, 1)*shadow;
                float4 shadowColor = _ShadowColor * (1-shadow);
                return col* (shadowColor+lightColor);
            }
            ENDHLSL
        }
    }
}

これを実行することで影の色を変更可能になりました。

本日は以上です。

ゼロから始めるUnityShader開発 第六章 セルルックなライティングを行う その①

本日はShader枠です。

今回はShaderの

〇環境

・Unity6000.0.2f1

・Windows11PC

〇セルルックなライティング

Unityのシェーダーの場合ライティングによる影の計算はNdotLが基本的な考え方です。

NdotLとはメッシュの法線=Normal、とライト=Lightのドット積によってライトが当たる面を計算するという意味です。

 ライトのベクトルと比較してメッシュの向きが一致する場合は影、逆に逆行している場合はライトが当たる部分というようになります。

https://redhologerbera.hatenablog.com/entry/2022/11/11/231804

今回は、基本形のライティングシェーダーから流用してセルルックなライティングを行います。  

Shader "Unlit/TutorialShader"
{
    Properties
    {
     //   _MainTex ("Texture", 2D) = "white" {}
        _MainColor("Color" ,color) = (1,1,1,1)
    }
    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;
                half3 normal: NORMAL;
            };

            struct v2f
            {
            float4 vertex : SV_POSITION;
            float3 normalWS : TEXCOORD1;
            };


            float4 _MainColor;
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = TransformObjectToHClip(v.vertex);
                //面の法線を取得、ライトの当たる向きを計算
                VertexNormalInputs normal = GetVertexNormalInputs(v.normal);
                o.normalWS = normal.normalWS;
                return o;
            }

            float4 frag (v2f i) : SV_Target
            {
                float4 col = _MainColor;
                //Light.hlslで提供されるUnityのライトを取得する関数
                Light lt = GetMainLight();

                //ライトの向きを計算
                float strength = dot(lt.direction, i.normalWS);
                float4 lightColor = float4(lt.color, 1);
                return col* lightColor*strength;
            }
            ENDHLSL
        }
    }
}

このままでは以下のように写実的にグラデーションとして影が付きます。

セルルックな見た目にするためには影の付き方をグラデーションではなくメリハリがあるつけ方をする必要があります。

そこでNdotLの計算結果をStep関数を用いて0,1に分割することでこれが可能です。

                //ライトの向きを計算
                float strength = dot(lt.direction, i.normalWS);
                float4 lightColor = float4(lt.color, 1);
                return col* lightColor* step(0.3,strength);

Step関数は引数との差をもとに0,1で値を分けてくれます。

これによってセルルックなライティングの基本形が完成しました。

本日は以上です。

UnityComputeShaderで頂点一つ一つに対して独自の処理を実装する

本日はUnity Shader枠です。

昨年よりComputeShaderに力を入れ始めましたが、筆者の中でコンピュートシェーダーの挙動に関してまだ慣れない点があり、今回は検証も兼ねて実装します。

〇環境

・Windows11PC

・Unity2022.3.6f1

〇頂点ごとに違う出力を与える

今回は頂点カラーを例に頂点ごとに違う出力を行っていきます。

頂点は配列としてIDで管理されMeshクラスに格納されています。

このID順に色を分けて与えていきます。

ComputeShaderを用いた頂点カラーの設定法は過去の記事を参考にしてください。

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

HLSLを用いたシェーダープログラムの場合一般的にVertexShaderステージ、FragmentShaderステージが分かれており、頂点ごとに行う処理はVertexShaderステージで行われます。その後ラフタライズされ、ピクセルごとにFragmentShaderステージでの処理が行われます。

ComputeShaderの場合は、上記のようなVertexShaderステージ、FragmentShaderステージといったステージで処理されるのではなく、グラフィックスAPI上の特定のシェーダーステージに属さず、独立したステージで実行されます。

 このために[numthreads(256, 1, 1)]でスレッドを作成しており、メモリーがバッファとして確保されます。

 今回のように頂点1つ1つに対して処理を行いたい場合は実際のところは頂点シェーダー同様頂点ごとに並列処理が実行されます。そのためfor文などは記載する必要はありません。

下記は前回のコンピュートシェーダー回収した例です。

#pragma kernel CSMain

// バッファの宣言
StructuredBuffer<float3> vertexBuffer;
RWStructuredBuffer<float4> colorBuffer;

[numthreads(256, 1, 1)]
void CSMain(uint3 id : SV_DispatchThreadID)
{
    uint index = id.x;

    // バッファの範囲をチェック
    if (index >= vertexBuffer.Length)
        return;

    // 色の明るさを計算
    float brightness = (float)index / (float)(vertexBuffer.Length - 1);

    // 黒から白へのグラデーションを設定
    colorBuffer[index] = float4(brightness, brightness, brightness, 1.0);
}

この時vertexBufferには頂点のIDが格納されます。各頂点IDをバッファの長さで正規化することで、brightness を 0.0 ~ 1.0 の範囲で算出します。 index / (Length - 1)とすることで、最初のIDが 0(黒)、最後のIDが 1(白)となります。

C#側は不要なバッファの宣言等を省いたにすぎません

using UnityEngine;

[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class VertexColorCompute : MonoBehaviour
{
    public ComputeShader vertexColorComputeShader; 
    [SerializeField] private Color _paintColor;
    
    private Mesh mesh;
    private Vector3[] vertices;
    private Color[] colors;

    private ComputeBuffer vertexBuffer;
    private ComputeBuffer colorBuffer;
    void Start()
    {
        // メッシュの取得
        mesh = GetComponent<MeshFilter>().mesh;
        vertices = mesh.vertices;
        colors = new Color[vertices.Length];

        // 頂点バッファの作成
        vertexBuffer = new ComputeBuffer(vertices.Length, sizeof(float) * 3);
        vertexBuffer.SetData(vertices);
        
        // カラーバッファの作成
        colorBuffer = new ComputeBuffer(colors.Length, sizeof(float) * 4);
        colorBuffer.SetData(colors);
        
        // メッシュに初期カラーを設定
        mesh.colors = colors;
    }

    void Update()
    {
        // コンピュートシェーダーのセットアップ
        int kernelHandle = vertexColorComputeShader.FindKernel("CSMain");

        // シェーダーにバッファをセット
        vertexColorComputeShader.SetBuffer(kernelHandle, "vertexBuffer", vertexBuffer);
        vertexColorComputeShader.SetBuffer(kernelHandle, "colorBuffer", colorBuffer);
        // ワールド変換行列をセット(必要に応じて)
        vertexColorComputeShader.SetMatrix("localToWorldMatrix", transform.localToWorldMatrix);

        // シェーダーをディスパッチ
        int threadGroups = Mathf.CeilToInt(vertices.Length / 256.0f);
        vertexColorComputeShader.Dispatch(kernelHandle, threadGroups, 1, 1);
        // カラーバッファからデータを取得
        colorBuffer.GetData(colors);

        // メッシュにカラーを適用
        mesh.colors = colors;
    }

    void OnDestroy()
    {
        // バッファの解放
        if (vertexBuffer != null)
            vertexBuffer.Release();
    }
}

〇頂点カラーの可視化

デフォルトのマテリアルに設定されているシェーダーでは頂点カラーの可視化に対応していません。

今回はMixed RealityToolkit GraphicsToolsのStandardShadferからVertex Colorsの機能を使用します。

ここでは影の影響を無視したいのでUnlitの設定を使用しています。

〇挙動確認

最後に挙動を確認します。

実行すると次のような結果を得ることができました。

白黒ですが、頂点ごとにIDに基づいた色分けの実装ができました。

本日は以上です。

ゼロから始めるUnityShader開発 第六章 ステンシルを用いたShader表現

本日はShader枠です。

〇環境

・Windows11PC

・Unity6000.3.2f1

 ・URP

〇ステンシルとは?

 Shaderにおけるステンシル(Stencil)は、特定のピクセルを描画するかどうかを制御するための機能です。

 シェーダープログラムでは最終的な出力をRGBの色としていますが、例えばアルファ値などのように直接画素に影響するわけではなく、ほかの描画計算と影響しあい最終描画を行うために用いられるパラメータのように様々な値を出力できます。

 ステンシルはステンシルバッファと呼ばれるリソースに格納される出力であり、ステンシルバッファを使用することで、複雑なマスク処理やオブジェクトの描画順序を制御することができます。

 例えばステンシルを用いることで、あるオブジェクトを通さないと描画されないオブジェクトということが実装できます。

ポータルを通さないと見えないオブジェクトの例

 ステンシルバッファを書き込むことで、描画準に応じて、同じピクセルにおいてすでに書き込まれているステンシルバッファの値と比較して処理を行うことができ、これを活用するシェーダーをステンシルの処理と呼びます。

〇ステンシルを使用したマスク表現

ステンシルはPass内、CGPROGRAM~ENDCGブロックの前に記述します。

 Stencil
            {
                Ref 1
                Comp Always
                Pass Replace
            }

パラメータは今回は3つ定義しています。

それぞれ次のような意味になります。

・Ref: ステンシルバッファに書き込む参照値

・Comp: ステンシルテストの比較関数

・Pass: ステンシルテストが成功した場合の操作

Refは数値を用いて、この数値が書き込まれるステンシル値になります。

Compではすでに描画されているピクセルのステンシル値と比較する際の挙動を定義します。

 Alwaysはステンシルの比較を常に行うという意味です。

 つまりすでにステンシル値が定義されていた場合は常にステンシルテストに合格するという意味です。

最後のPassでは、ステンシルテストに成功した際の処理を定義します。

 例ではReplace…つまりすでに書き込まれている描画色と現在のシェーダーの計算色を置き換えて現在のシェーダーの色を採用するという意味です。

今回はこれを用いて2つのシェーダーを作成しました。

Shader "Custom/StencilMask"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "Queue" = "Geometry" }
        Pass
        {
            Stencil
            {
                Ref 1
                Comp Always
                Pass Replace
            }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            sampler2D _MainTex;
            struct appdata_t
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };
            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };
            v2f vert (appdata_t v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }
            fixed4 frag (v2f i) : SV_Target
            {
                return tex2D(_MainTex, i.uv);
            }
            ENDCG
        }
    }
}

Shader "Custom/StencilMasked"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "Queue" = "Geometry+1" }
        Pass
        {
            Stencil
            {
                Ref 1
                Comp Equal
            }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            sampler2D _MainTex;
            struct appdata_t
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };
            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };
            v2f vert (appdata_t v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }
            fixed4 frag (v2f i) : SV_Target
            {
                return tex2D(_MainTex, i.uv);
            }
            ENDCG
        }
    }
}

一つ目のシェーダーは最もシンプルなUnlitシェーダーにステンシルを定義しています。

2つ目のシェーダーは通常時は見えません。

しかし1つ目のシェーダーのマテリアルを通してであれば描画されます。

これはステンシルを含む2つのテクニックがあります。

〇今回のシェーダーのテクニック

今回2つ目の通常時は見えないシェーダーではステンシルの他にRenderQueueにも秘密があります。

        Tags { "Queue" = "Geometry+1" }

Geometryとは2000を意味し、このシェーダーは2001のキューを持ちます。

RenderQueueは描画順番であり、通常若い順番で描画されます。

つまり、このオブジェクトはほかの不透明オブジェクトよりも後に描画されます。

後に描画された状態で

   Stencil
            {
                Ref 1
                Comp Always
                Pass Replace
            }

のステンシル値が書き込まれているピクセル

    Stencil
            {
                Ref 1
                Comp Equal
            }

ピクセルが描画される際に、ステンシルテストが行われます。具体的には、最初のシェーダーがステンシルバッファに値 1 を書き込みます。

 この値が書き込まれたピクセルに対して、次のシェーダーが描画される際に、ステンシルテストが実行されます。

 ステンシルテストの比較関数 Comp Equal は、ステンシルバッファの値が Ref で指定された値(この場合は 1)と等しい場合にのみ描画を許可します。したがって、最初のシェーダーによってステンシルバッファに値 1 が書き込まれたピクセルに対してのみ、次のシェーダーの描画が行われます。

 この仕組みでシェーダー1を使用したマテリアルを通してのみ描画される表現ができるのです。

本日は以上です。

MRTK3のUIのボードを半透明にする

2024年最後の記事はMRKT3,MRGT枠です。

MRTK3ではMRTKv2から引き継いだMicrosoft FluentSystemに基づいたUIコンポーネントが提供されています。

〇環境

・Windows11PC

・Unity2022.3.6f1

〇MRTKのUIを半透明にする

MRTK3ではUGUIに基づいたCanvas上に構成されるUIとNonCanvasなUIオブジェクトの2つが提供されています。

今回はHandMenuプレファブを例にUIボードを半透明にします。

HandMenu

デフォルトの状態でHandMenuプレファブにはMenuContentとしてバックプレートに相当するUX.HandMenu.Backplateとボタンを格納するButtonCollectionオブジェクトが存在します。

このUX.HandMenu.BackplateはMRGTで提供されるGraphics Tools/Non-Canvas/Backplateシェーダーが使用されています。

このマテリアルはPackage内に存在するためデフォルトの状態ではパラメータの編集ができません。

デフォルトでPackages/org.mixedrealitytoolkit.standardassets/Materials/CompressedButtonMaterial/MRTK_Backplate_08mm_Gradient.matに存在するマテリアルをドラッグアンドドロップでAssets内にコピーします。

UX.HandMenu.BackplateオブジェクトのMeshRendererのMaterialsに複製したマテリアルをアタッチすることでパラメータの編集が可能となります。

〇透過設定

透過を行うためにはAlphaBlendingとRenderqueが重要です。

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

Graphics Tools/Non-Canvas/Backplateシェーダーでは下部にBlendingのパラメータが存在します。

Source BlendをScrAplha、Source Blend AlphaをOneMinusScrAlphaに設定します。

またRender Queueを3000に設定します。

以上の設定が透明度を扱う設定です。

最後にBaseColorのパラメータでα値を下げることで透過が行われます。

以上がMRTK3のUIボードを半透明にする処理設定でした。

この設定はNoncanvasのみに適応される点に注意が必要です。

本日は以上です。

UnityComputeShaderで外部に定義した処理のHLSLファイルを使用する

本日はShader枠です。

通常のShaderでは型や関数の定義や一般的使用可能な処理は外部ファイルに定義し、includeすることで使いまわします。

今回はComputeShaderでも同様に外部ファイルに処理を記述して読み込むことが可能であるのか気になったので調べていきます。

〇環境

・Windows11PC

・Unity6000.32f1

〇外部に定義したHLSLファイルを読み込む

今回はメインのコンピュートシェーダーを次のように構成しました。

#pragma kernel CSMain


// 出力用の構造体
struct ResultData {
    float3 value;
};

// スレッドグループのサイズ(1x1x1)
[numthreads(1, 1, 1)]
void CSMain(uint3 id : SV_DispatchThreadID, RWStructuredBuffer<ResultData> resultBuffer)
{
    // 入力データ
    float3 a = float3(1.0, 0.0, 0.0);
    float3 b = float3(0.0, 1.0, 0.0);

    // 関数の呼び出し
    float3 result = Function(a, b);
    
    // 結果をRWStructuredBufferに格納
    resultBuffer[0].value = result;
}

ここではただ計算をするだけですが、実際の計算は別のfuc.hlslファイルに定義しました。

float3 Function(float3 a, float3 b)
{
    return a + b;
}

Unityでこれを動かすためのC#コードは以下のようになります。

using UnityEngine;

public class ComputeShaderController : MonoBehaviour
{
    public ComputeShader computeShader;
    private ComputeBuffer resultBuffer;
    private Vector3 result;

    void Start()
    {
        // コンピュートシェーダーの実行
        DispatchComputeShader();

        // 結果を表示
        Debug.Log("結果: " + result);
    }

    void DispatchComputeShader()
    {
        // 結果を格納するためのComputeBufferを作成
        resultBuffer = new ComputeBuffer(1, sizeof(float) * 3); // float3のサイズを指定
        int kernelHandle = computeShader.FindKernel("CSMain");

        // コンピュートシェーダーにバッファを設定
        computeShader.SetBuffer(kernelHandle, "resultBuffer", resultBuffer);

        // コンピュートシェーダーをディスパッチ
        computeShader.Dispatch(kernelHandle, 1, 1, 1);

        // 結果をCPU側にコピー
        Vector3[] resultArray = new Vector3[1];
        resultBuffer.GetData(resultArray);

        // 結果をログに表示
        result = resultArray[0];
        Debug.Log("計算結果: " + result);

        // バッファを解放
        resultBuffer.Release();
    }
}

ここではresultBufferというバッファを作成し、結果を受け取ります。

コンピュートシェーダー側でfnc.hlslの処理を使用するために#include fnc.hlslを定義します。

#pragma kernel CSMain
#include "fnc.hlsl"//定義

・・・

[numthreads(1, 1, 1)]
void CSMain(uint3 id : SV_DispatchThreadID, RWStructuredBuffer<ResultData> resultBuffer)
{
  ・・・
}

これによってコンピュートシェーダー側でFunction()の処理が使用可能となります。

今回の処理は以下の二つのベクトルの足し算です。

    float3 a = float3(1.0, 0.0, 0.0);
    float3 b = float3(0.0, 1.0, 0.0);

この処理を実行するとコンソールに正しい計算結果が表示されました。

以上で外部に定義したHLSLファイルをコンピュートシェーダーでも使用可能であることがわかりました。

本日は以上です。