Unity Term Book
グラフィックスとエフェクト

Mesh Renderer & Filter

Mesh Filter と Mesh Renderer が 3D 形状を表示します——Filter がメッシュデータを供給し、Renderer が Material・影・ライティングで描画します。手続きメッシュ、バッチ、PropertyBlock の基礎を学べます。図解とシミュレーターで構造を確認できます。

想像してみてください...

Mesh Filter は型——3D 形状(頂点、辺、面)を保持します。 Mesh Renderer は塗り手——その型に Material(塗料・テクスチャ)を載せ GPU に送ります。 対で動きます:Mesh Filter がなければ Renderer は描くものがなく、Renderer がなければメッシュは見えません。 ビルド時、Unity は何千もの Mesh Renderer を draw call batches にまとめ GPU を効率よく保ちます。

概念の詳細

MeshFilter は Mesh アセットへの参照——形状データ: vertices、triangles(インデックス三つ組)、normals(ライティング用)、 UVs(テクスチャマッピング)、任意で tangents と colors。メッシュは インポート資産(.fbx/.obj)でも、コードから手続き的に作っても構いません。

MeshRenderer は Materials 配列(サブメッシュごと)、Shadow Casting/Receiving、Lightmap baking、Probe Anchor、そして重要な Layer と Rendering Layer Mask(URP ライティング)を持ちます。bounds(境界ボックス)が 視錐台カリングを駆動——境界がカメラ視錐台の外なら描画をスキップします。

Unity のバッチ手法:Static Batching(物体を “Static” に)、 Dynamic Batching(300 頂点未満の移動物体)、 GPU Instancing(同じメッシュ + 同じマテリアルで多数を一つのドローコール)。 Material で GPU Instancing を有効にします。

Unity 2022+ では Mesh API 2.0 でボクシングなしに手続きメッシュを作成・編集できます: Mesh.SetVertexBufferData、Mesh.SetIndexBufferData — マネージ配列を飛ばして GPU バッファへ直接書き込み。

Mesh から画面へ

MeshFilter

Mesh Asset
vertices, triangles
normals, UVs

+

MeshRenderer

Materials[ ]
Shadow settings
Lightmap/Probe

→

Batching / Culling

Static/Dynamic Batch
Frustum Culling
Occlusion Culling

→

GPU Draw Calls

Vertex Shader
Fragment Shader
→ Pixels

Sub-mesh & Materials

Mesh (2 sub-mesh)

→

Materials[ ]

Materials[0] = Body_Mat
Materials[1] = Window_Mat

ハンズオン手順

1

モデルをインポート——MeshFilter は自動追加

.fbx/.obj を Project に入れ、Scene へ——Unity が MeshFilter + MeshRenderer と Material スロットを作ります。

2

Shadow Casting を設定

MeshRenderer → Cast Shadows: On/Off/Two Sided。他の影を受ける床は Receive Shadows をオン。

3

静的環境に Static Batching

Inspector → Static ドロップダウン → Batching Static。同じ Material を共有する静的物体が一つのドローコールにまとまります。

4

手続き的にメッシュを構築

new Mesh()、vertices[]、triangles[]、normals[]、uv[] を設定 → GetComponent<MeshFilter>().mesh に割り当て。

5

Frame Debugger でドローコールを数える

Window → Analysis → Frame Debugger:各ドローコールを検査し、コストの高い物体を確認。

インタラクティブシミュレーター

手続き的にメッシュを構築——トポロジを選び、ワイヤーフレーム / 法線を検査。

Vertices: 24Triangles: 12Draw Calls: 1

コード例

基本

三角形メッシュを手続き的に作り、MeshFilter + MeshRenderer で表示。

using UnityEngine;

[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class ProceduralTriangle : MonoBehaviour
{
  void Start()
  {
      Mesh mesh = new Mesh();
      mesh.name = "Procedural Triangle";

      // 3 vertices of the triangle
      mesh.vertices = new Vector3[] {
          new Vector3(0f, 0f, 0f),
          new Vector3(1f, 0f, 0f),
          new Vector3(0.5f, 1f, 0f)
      };

      // Clockwise indices (viewed from the front)
      mesh.triangles = new int[] { 0, 1, 2 };

      // UV mapping: one texture coord per vertex
      mesh.uv = new Vector2[] {
          new Vector2(0f, 0f),
          new Vector2(1f, 0f),
          new Vector2(0.5f, 1f)
      };

      mesh.RecalculateNormals(); // Compute normals automatically

      GetComponent<MeshFilter>().mesh = mesh;
  }
}

コード例

上級

実行時に Material を差し替え、MaterialPropertyBlock でバッチを崩さずに色付け。

using UnityEngine;

public class MeshRendererUtils : MonoBehaviour
{
  MeshRenderer rend;
  MaterialPropertyBlock mpb;

  void Awake()
  {
      rend = GetComponent<MeshRenderer>();
      mpb = new MaterialPropertyBlock();
  }

  // Read mesh bounds in world space
  void LogMeshInfo()
  {
      Mesh mesh = GetComponent<MeshFilter>().sharedMesh;
      Debug.Log($"Vertices: {mesh.vertexCount}");
      Debug.Log($"Triangles: {mesh.triangles.Length / 3}");
      Debug.Log($"Bounds: {rend.bounds.size}");
  }

  // Swap the Material on a specific sub-mesh (index 1 = window glass)
  public void SwapSubMesh(int index, Material mat)
  {
      Material[] mats = rend.materials; // Get a copy
      mats[index] = mat;
      rend.materials = mats;            // Assign back
  }

  // Per-instance color via PropertyBlock — keeps GPU Instancing
  public void SetInstanceColor(Color c)
  {
      rend.GetPropertyBlock(mpb);
      mpb.SetColor("_BaseColor", c);
      rend.SetPropertyBlock(mpb);
  }
}

📌 要点

  • ▸MeshFilter = 形、MeshRenderer = 描き方
  • ▸sharedMesh はクローンしない;.mesh は私有コピーを作る
  • ▸Static + 同じ Material → Static Batching
  • ▸triangles[] は正面から見て時計回り(CW)
  • ▸頂点変更後は RecalculateNormals()

⚠️ よくあるミス

  • ❌ メッシュが裏返り(面がカリングされる)

    三角形インデックスが反時計回り → Unity がその面をカリング

    ✅ インデックス順を反転:{0,1,2} → {0,2,1}、または Double Sided シェーダー

  • ❌ Play Mode で meshFilter.mesh を何度も代入

    毎回新しい Mesh → メモリリーク

    ✅ Awake() で一度作り、Update() では頂点だけ更新