本日は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に指定したゲームオブジェクトの距離に応じて頂点カラーが設定されます。


本日は以上です。