渋谷ほととぎす通信

完全趣味でやってるUnityメモ。説明できないところを説明できるようにするための個人ブログ。昨日の自分より少しでも大きくなれるように。。。 ※所属団体とは一切関係がありません

Unity 動的にメッシュを生成してゴニョゴニョする : 超基本編その3


f:id:esakun:20150730215258g:plain

前回動的生成した三角形メッシュを頂点カラーで描画しました。

今回は頂点カラーとテクスチャ両方描画してみます。

前回と前々回の合わせ技なので、さくっとやってみます。

using UnityEngine;
using System.Collections;

/// <summary>
/// 頂点カラーで三角形を描画します
/// </summary>
[RequireComponent (typeof(MeshRenderer))]
[RequireComponent (typeof(MeshFilter))]
public class DynamicCreateMesh : MonoBehaviour
{
    [SerializeField]
    private Material _mat;

    private void Start ()
    {
        var mesh = new Mesh ();
        mesh.vertices = new Vector3[] {
            new Vector3 (0, 1f),
            new Vector3 (1f, -1f),
            new Vector3 (-1f, -1f),
        };
        mesh.triangles = new int[] {
            0, 1, 2 
        };

        // 変更箇所 : UV座標を再設定
        mesh.uv = new Vector2[] {
            new Vector2 (0.5f, 1f),
            new Vector2 (1f, 0f),
            new Vector2 (0, 0),
        };

        mesh.colors = new Color[] {
            Color.white,
            Color.red,
            Color.green
        };

        var filter = GetComponent<MeshFilter> ();
        filter.sharedMesh = mesh;

        var renderer = GetComponent<MeshRenderer> ();
        renderer.material = _mat;
    }
}
Shader "Baobao/Unlit/SimpleVertexColorShader"
{
    Properties{
        // インスペクタからテクスチャをセットできるようにする
        _MainTex("Texture", 2D) = "white"{}
    }

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

        Pass
        {
            CGPROGRAM
           #pragma vertex vert
           #pragma fragment frag
            
           #include "UnityCG.cginc"

            // プロパティでセットされた画像が格納される(同じ変数名にする必要あり)
            sampler2D _MainTex;
            // どこからも参照していないように見えてUnityCG.cgincで使われています
            float4 _MainTex_ST;

            struct appdata
            {
                float4 vertex : POSITION;
                fixed3 color : COLOR0;
                // テクスチャのUV座標(複数テクスチャにより連番。例:TEXCOORD1,2)
                float2 uv:TEXCOORD0;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                fixed3 color : COLOR0;
                // テクスチャのUV座標(複数テクスチャにより連番。例:TEXCOORD1,2)
                float2 uv:TEXCOORD0;
            };

            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.color = v.color;
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 texCol = tex2D(_MainTex, i.uv);
                // 頂点カラーに対してテクスチャのカラーを乗算
                fixed4 o = fixed4(i.color, 1) * texCol;
                return o;
            }
            ENDCG
        }
    }
}

C#のソースはメッシュのUV座標を以前の状態に戻しただけ、以下大きく変わったのはシェーダのソースです。

  • 外部からテクスチャを設定できるようにする
  • Vertexシェーダから各頂点のテクスチャUV座標をFragmentシェーダに送るようにする
  • Fragmentシェーダで各ピクセルの色を頂点カラーとテクスチャのカラーを乗算関係にする

外部からテクスチャを設定できるようにする

Properties{
    // インスペクタからテクスチャをセットできるようにする
    _MainTex("Texture", 2D) = "white"{}
}

f:id:esakun:20151129214224p:plain
この部分で外部からテクスチャを設定できるようにします。
(上図のようにインスペクタから設定できるようになります)

シェーダ上でこのテクスチャを使用するためには、Propertiesで定義した_MainTexという名前と同じ変数名で定義する必要があります。

sampler2D _MainTex;

Vertexシェーダから各頂点のテクスチャUV座標をFragmentシェーダに送るようにする

o.uv = TRANSFORM_TEX(v.uv, _MainTex);

UnityCG.cgincに定義されているマクロTRANSFORM_TEXを使うことでテクスチャのスケール・オフセットが適用されます。

参考 : Unity - マニュアル: シェーダー: 頂点とフラグメントプログラム

ここで、サンプルを見ていると、次のコードがどこからも参照されていないように見えました。

float4 _MainTex_ST;

しかし、削除すると次のようなコンパイルエラーになります。

Shader error in 'Baobao/Unlit/SimpleVertexColorShader': undeclared identifier '_MainTex_ST' at line 47 (on glcore)

Compiling Vertex program
Platform defines: UNITY_NO_SCREENSPACE_SHADOWS UNITY_ENABLE_REFLECTION_BUFFERS UNITY_PBS_USE_BRDF1 UNITY_SPECCUBE_BOX_PROJECTION UNITY_SPECCUBE_BLENDING SHADER_API_DESKTOP UNITY_TEXTURE_ALPHASPLIT_ALLOWED

読み込んでいるライブラリ内で使用しているから定義してね。ということでした。テクスチャを使用するシェーダを書く際は気をつけたいところです。

#include "UnityCG.cginc"

参考 : Error | Unity Community

Fragmentシェーダで各ピクセルの色を頂点カラーとテクスチャのカラーを乗算関係にする

最後に頂点カラーとテクスチャのカラーを合成します。

fixed4 texCol = tex2D(_MainTex, i.uv);
// 頂点カラーに対してテクスチャのカラーを乗算
fixed4 o = fixed4(i.color, 1) * texCol;

ソースの通り、各ピクセル単位で頂点カラーとテクスチャのカラーを乗算します。

すると、こんな風に描画されます。

f:id:esakun:20151129213044p:plain

まとめ

シェーダは面白いですね。WebGLでならったことが役に立ちそうです。

しかし、本記事含めて過去3回3Dの知識としては超基本的なことをやってきました。
そろそろタイトルの「動的にメッシュを生成して」の内容に戻ってみようかなと思います(それでも超基本編かもしれません)。

「動的メッシュ生成」シリーズ記事

esakun.hateblo.jp esakun.hateblo.jp esakun.hateblo.jp esakun.hateblo.jp