[Unity] 2D図形を指定した色で描画する

2Dゲームの制作などで単色の図形を描画する方法のメモ書きです。
主に塗りつぶし図形を表示させたい場合に使えます。

mesh-col

図形の描画色を変えるには専用のマテリアルを用意し、これにDiffuseシェーダーなどをセットして色を指定することで可能です。
しかし、この方法では異なる色の図形を用意するたびにその数分のマテリアルを用意せねばならず、多数の色のオブジェクトを描画したい場合には多大な労力がかかってしまいます。
また、動的に図形の色を変えるのも難しいです。
さらに、複数のマテリアルを用いるためDrawCallが増加してしまうこともデメリットです。

Unityで描画する図形はメッシュとして管理されています。
メッシュは頂点とそれを結ぶポリゴンによって構成されています。
頂点一つ一つには位置座標やテクスチャのUV座標、頂点色などが含まれます。

この頂点色を変更することで、ひとつのマテリアルだけでさまざまな塗りつぶし色の図形を描画することが可能です。
動的な色変えも可能です。

まず、メッシュ描画用のマテリアルを作成し、シェーダーをGUI/Text Shaderに設定します。

そして、以下の要領でメッシュオブジェクトを作成します。

 1.GameObjectをシーンに作成
 2.MeshFilter、MeshRendererをアタッチ
 3.MeshRendererのMaterialsを開き、Elementに前述のマテリアルを指定
 4.以下スクリプトをアタッチ

using UnityEngine;
using System.Collections;

// メッシュ色変更
public class SetMeshColor : MonoBehaviour {
    public Color color;    // 変更後のメッシュの色

    void Update() {
        // メッシュの色を変更
        var mesh = GetComponent<MeshFilter>().mesh;
        var colors = mesh.colors;

        for ( int i = 0 ; i < mesh.colors.Length ; ++i ) {
            colors[i] = color;
        }

        mesh.colors = colors;
    }
}

 5.SetMeshRendererのColorに指定したいメッシュの色を設定

これで5.のColorに指定した色でメッシュが描画されるようになります。

メッシュの色設定のポイントは以下の部分です。

    var mesh = GetComponent<MeshFilter>().mesh;
    var colors = mesh.colors;

    for ( int i = 0 ; i < mesh.colors.Length ; ++i ) {
        colors[i] = color;
    }

    mesh.colors = colors;

自身のGameObjectのMeshFilterコンポーネントのcolorsメンバに指定したいメッシュの色を上書きしています。
これにより、メッシュの色が反映されます。
注意点として、colorsメンバの各要素に直接色を指定しても反映されないということです。
なので、mesh.colorsを一時的にコピーし、色をセットした後にmesh.colorsに丸ごと代入しています。

このようなメッシュの色指定を逐次行うと、徐々にメッシュの色を変化させたりできるようになります。

上記スクリプトではUpdate()内で色の指定を随時行っていますが、メッシュの頂点数が多くなるほど処理が劇的に重くなるので、メッシュ色の動的変更をしない限りは以下のようにAwake()内で行うようにすれば良いでしょう。

using UnityEngine;
using System.Collections;

// メッシュ色変更
public class SetMeshColor : MonoBehaviour {
    public Color color;    // 変更後のメッシュの色

    void Awake() {
        // メッシュの色を変更
        var mesh = GetComponent<MeshFilter>().mesh;
        var colors = mesh.colors;

        for ( int i = 0 ; i < mesh.colors.Length ; ++i ) {
            colors[i] = color;
        }

        mesh.colors = colors;
    }
}