夜風のMixedReality

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

Unity ComputeShaderでメッシュの頂点カラーを設定する その③任意の色を分ける

本日はShader枠です。

 昨日はコンピュートシェーダーを使用して、Unityの任意のオブジェクトの情報を毎フレームコンピュートシェーダー内で使用することができました。

 

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

今回は任意のColor型の情報をComputeShaderに渡していきます。

〇色の情報をコンピュートシェーダーで使用する

まずはC#側のスクリプトにColorを定義します。ここでは

    [SerializeField] private Color _paintingColor;//追加

として定義しました。

using UnityEngine;

[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class VertexColorCompute : MonoBehaviour
{
    public ComputeShader vertexColorComputeShader;
    public GameObject targetObject; // ターゲットオブジェクト

    private Mesh mesh;
    private Vector3[] vertices;
    private int[] triangles;
    private Color[] colors;
    [SerializeField] private Color _paintingColor;//追加

    private ComputeBuffer vertexBuffer;
    private ComputeBuffer triangleBuffer;
    private ComputeBuffer colorBuffer;
    private ComputeBuffer targetBuffer; // ターゲットオブジェクトの位置を保持するバッファ

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

        // 頂点バッファの作成
        vertexBuffer = new ComputeBuffer(vertices.Length, sizeof(float) * 3);
        vertexBuffer.SetData(vertices);

        // インデックスバッファの作成
        triangleBuffer = new ComputeBuffer(triangles.Length, sizeof(int));
        triangleBuffer.SetData(triangles);

        // カラーバッファの作成
        colorBuffer = new ComputeBuffer(colors.Length, sizeof(float) * 4);
        colorBuffer.SetData(colors);

        // ターゲットオブジェクトの位置を保持するバッファの作成
        targetBuffer = new ComputeBuffer(1, sizeof(float) * 3);
        targetBuffer.SetData(new Vector3[] { targetObject.transform.position });

        // メッシュに初期カラーを設定
        mesh.colors = colors;
    }

    void Update()
    {
        // ターゲットオブジェクトの位置をターゲットバッファに更新
        targetBuffer.SetData(new Vector3[] { targetObject.transform.position });

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

        // シェーダーにバッファをセット
        vertexColorComputeShader.SetBuffer(kernelHandle, "vertexBuffer", vertexBuffer);
        vertexColorComputeShader.SetBuffer(kernelHandle, "colorBuffer", colorBuffer);
        vertexColorComputeShader.SetBuffer(kernelHandle, "targetBuffer", targetBuffer);

        // ワールド変換行列をセット(必要に応じて)
        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();
        if (triangleBuffer != null)
            triangleBuffer.Release();
        if (colorBuffer != null)
            colorBuffer.Release();
        if (targetBuffer != null)
            targetBuffer.Release();
    }
}

このカラー情報は毎フレームコンピュートシェーダー側に渡す必要があるため、Update関数で値を渡します。

これはComputeShader.SetVectorで値を渡します。

この使い方はマテリアルパラメータに参照する際のShader.SetFloatなどと同じです。

void Update()
{
  ・・・

    // シェーダーにペイントカラーを設定
    vertexColorComputeShader.SetVector("_paintingColor", _paintingColor);

 ・・・
    mesh.colors = colors;
}

〇コンピュートシェーダー側の処理

コンピュートシェーダーのHLSL側で実装することは以下の二点です。

・定数バッファとして _paintingColor を宣言。

・距離判定後に _paintingColor を使用。

#pragma kernel CSMain

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

// ワールド変換行列
float4x4 localToWorldMatrix;

// ペイントカラー
float4 _paintingColor;

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

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

    // 頂点位置を取得
    float3 vertexPos = vertexBuffer[index];

    // ターゲット位置をバッファから取得
    float3 targetPos = targetBuffer[0];

    // 頂点とターゲットの距離を計算
    float distance = length(vertexPos - targetPos);

    // ターゲットに近い頂点にカラーを設定
    if (distance < 1.0)  // 任意の距離閾値
    {
        // ターゲットに近い場合、ペイントカラーを使用
        colorBuffer[index] = _paintingColor;
    }
    else
    {
        // それ以外は青色
        colorBuffer[index] = float4(0.0, 0.0, 1.0, 1.0);
    }
}

これによって任意の色をColor型のパラメータとしてコンピュートシェーダーに渡すことができるようになりました。

本日は以上です。