Unityの頂点カラーを表示するシェーダーの作り方

最近のCGだとあまり使用する機会がない気がする頂点カラーですが、たまにどんな感じの色付けになっているのか確認したいケースがあります。ただ、Unityではデフォルトの機能で確認する方法がないので、頂点カラーを表示するためのシェーダーを書く必要があります。

今回は、Unityで頂点カラーを表示する簡単なシェーダーの作り方を紹介します。

頂点カラーを持つモデルを用意する

まず初めに、今回のシェーダーは頂点カラーを持つモデルでないと効果がありません。頂点カラーを持つモデルはBlenderなどのDCCで作成するか、以下のコードをオブジェクトにアタッチして作成してください。

using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
[ExecuteInEditMode]
public class MeshGeneratorWithColor : MonoBehaviour
{
    void Start()
    {
        CubeWithColor();
    }

    private void OnValidate()
    {
        CubeWithColor();
    }

    void CubeWithColor()
    {
        List<Vector3> vertices = new List<Vector3>() {
            // 0
            new Vector3(0.0f, 0.0f, 0.0f), // 正面
            new Vector3(1.0f, 0.0f, 0.0f),
            new Vector3(1.0f, 1.0f, 0.0f),
            new Vector3(0.0f, 1.0f, 0.0f),
            // 4
            new Vector3(1.0f, 1.0f, 0.0f), // 上面
            new Vector3(0.0f, 1.0f, 0.0f),
            new Vector3(0.0f, 1.0f, 1.0f),
            new Vector3(1.0f, 1.0f, 1.0f),
            // 8
            new Vector3(1.0f, 0.0f, 0.0f), // 右面
            new Vector3(1.0f, 1.0f, 0.0f),
            new Vector3(1.0f, 1.0f, 1.0f),
            new Vector3(1.0f, 0.0f, 1.0f),
            // 12
            new Vector3(0.0f, 0.0f, 0.0f), // 左面
            new Vector3(0.0f, 1.0f, 0.0f),
            new Vector3(0.0f, 1.0f, 1.0f),
            new Vector3(0.0f, 0.0f, 1.0f),
            // 16
            new Vector3(0.0f, 1.0f, 1.0f), // 背面
            new Vector3(1.0f, 1.0f, 1.0f),
            new Vector3(1.0f, 0.0f, 1.0f),
            new Vector3(0.0f, 0.0f, 1.0f),
            // 20
            new Vector3(0.0f, 0.0f, 0.0f), // 下面
            new Vector3(1.0f, 0.0f, 0.0f),
            new Vector3(1.0f, 0.0f, 1.0f),
            new Vector3(0.0f, 0.0f, 1.0f),

        };
        List<int> triangles = new List<int> {
            0, 3, 2,  0, 2, 1, //前面 ( 0 -  3)
            5, 6, 7,  5, 7, 4, //上面 ( 4 -  7)
            8, 9,10,  8,10,11, //右面 ( 8 - 11)
           15,14,13, 15,13,12, //左面 (12 - 15)
           16,18,17, 16,19,18, //奥面 (16 - 19)
           23,20,21, 23,21,22, //下面 (20 - 23)
        };
        List<Color> colors = new List<Color>
        {
            Color.blue,
            Color.cyan,
            Color.gray,
            Color.green,
            Color.grey,
            Color.magenta,
            Color.red,
            Color.yellow,

            Color.blue,
            Color.cyan,
            Color.gray,
            Color.green,
            Color.grey,
            Color.magenta,
            Color.red,
            Color.yellow,

            Color.blue,
            Color.cyan,
            Color.gray,
            Color.green,
            Color.grey,
            Color.magenta,
            Color.red,
            Color.yellow,
        };
        

        Mesh mesh = new Mesh();             // メッシュを作成
        mesh.Clear();                       // メッシュ初期化
        mesh.SetVertices(vertices);         // メッシュに頂点を登録する
        mesh.SetColors(colors);             // 頂点カラーを登録
        mesh.SetTriangles(triangles, 0);    // メッシュにインデックスリストを登録する
        mesh.RecalculateNormals();          // 法線の再計算

        // 作成したメッシュをメッシュフィルターに設定する
        MeshFilter meshFilter = GetComponent<MeshFilter>();
        meshFilter.mesh = mesh;
    }
}

なお、動的にメッシュを作成するコードでは、以下の部分でメッシュにカラー情報を渡しているので注意してください。

Mesh mesh = new Mesh(); 
mesh.SetColors(colors);

カラー情報をシェーダー内で受け渡す

メッシュから渡ってきたカラー情報を、最終的にはフラグメントシェーダーに渡していきます。

struct appdata //メッシュデータが持つ情報
{
    float4 vertex : POSITION;
    float4 color : COLOR;
};

struct v2f //ラスタライズ後に格納される
{
    float4 vertex : SV_POSITION;
    float4 color : COLOR;
};

v2f vert (appdata v)
{
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex); //メッシュの頂点情報をMVP変換
    o.color = v.color; //メッシュのカラー情報を代入
    return o;
}

fixed4 frag (v2f i) : SV_Target
{
    return i.color; //渡ってきたカラー情報を表示
}

シェーダー全体

シェーダーの全容は以下のとおりです。

Shader "CAGraphicsAcademy/VertexColor"
{
    Properties
    {

	}
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
				float4 color : COLOR;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
				float4 color : COLOR;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
				o.color = v.color;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return i.color;
            }
            ENDCG
        }
    }
}

まとめ

頂点カラーを単純に表示するシェーダーの紹介でしたが、頂点カラーはそんなに使われないので、使いどころは限られるかもしれません。分かりきっていることかもしれませんが、メッシュに色を表示するならテクスチャを作ってください。

返信を残す

メールアドレスが公開されることはありません。