以下の内容はhttps://redhologerbera.hatenablog.com/entry/2024/12/06/230833より取得しました。


Unity ComputeShaderでメッシュの頂点カラーを設定する その②あるオブジェクトを基準に色を分ける

本日はComputeShader枠です。

 先日Unityのコンピュートシェーダーを用いてメッシュの頂点カラーを設定しました。

この時にワールド座標に基づいて色を付けていました。

 今回はUnityのゲームオブジェクトを基準に頂点カラーを与える実装を行います。

〇環境

・Unity6000.0.2f1

・Windows11PC

〇実装

C#側の実装は以下のようになります。

targetObjectという名前で定義しています。

行っていることは新しくComputeBufferを定義しています。

またUpdate関数で定義したComputeBufferにtargetObjectの座標を設定します。

targetBuffer.SetData(new Vector3[] { targetObject.transform.position });
using UnityEngine;

[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class VertexColorCompute : MonoBehaviour
{
    public ComputeShader vertexColorComputeShader;
    public GameObject targetObject; // ターゲットオブジェクト
    [SerializeField] private Color _paintColor;
    
    private Mesh mesh;
    private Vector3[] vertices;
    private int[] triangles;
    private Color[] colors;

    private ComputeBuffer vertexBuffer;
    private ComputeBuffer triangleBuffer;
    private ComputeBuffer colorBuffer;
    private ComputeBuffer targetBuffer; // ターゲットオブジェクトの位置を保持するバッファ
    private ComputeBuffer paintColorBuffer;
    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 });

        paintColorBuffer = new ComputeBuffer(1, sizeof(float) * 3);
        paintColorBuffer.SetData(new Color[] { _paintColor });
        // メッシュに初期カラーを設定
        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();
    }
}

コンピュートシェーダーは以下のようになります。

C#同様にStructuredBufferを定義します。

#pragma kernel CSMain

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

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

[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];
    float3 paintColor = paintColorBuffer[0];

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

    // ターゲットに近い頂点にカラーを設定
    if (distance < 0.1)  // 任意の距離閾値
    {
        // ターゲットに近い場合、赤色に
        colorBuffer[index] = float4(paintColor, 1.0);
    }

}

これを実装することでTargetObjectに指定したゲームオブジェクトの距離に応じて頂点カラーが設定されます。

本日は以上です。




以上の内容はhttps://redhologerbera.hatenablog.com/entry/2024/12/06/230833より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14