こんにちわ、Unityエンジニアのオオバです。

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

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

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

using UnityEngine;  
using System.Collections;  

///  
/// 頂点カラーで三角形を描画します  
///  
[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 ();  
        filter.sharedMesh = mesh;  

        var renderer = GetComponent ();  
        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座標を以前の状態に戻しただけ、以下大きく変わったのはシェーダーのソースです。

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

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

Unity 動的にメッシュを生成して頂点カラーとテクスチャを描画する_154

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

シェーダー上でこのテクスチャを使用するためには、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"

参考 : What is _MainTex_ST ? - Unity Forum

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

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

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

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

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

Unity 動的にメッシュを生成して頂点カラーとテクスチャを描画する_211

まとめ

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

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

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

👉 オススメ記事

2021秋 Asset Refreshセール
100以上のアセットがなんと50%OFF!!オオバもいくつか買いました!
期間 : 10月2日午後3時59分まで

👩‍💻 検証環境