Culling
Culling はカメラに見えないものを描画しません——視錐台外や遮蔽された物体の draw call を削減します。Frustum Culling・Occlusion・LOD・layerCullDistances の使い分けを実践的に学べます。図解とシミュレーターで描画スキップを体感し、自学にも使えます。
想像してみてください...
Culling は賢い舞台監督です。舞台上のすべての役者に照明を当てる代わりに、 客席から見える役者だけを照らします。カーテンの裏?消灯。角度外?消灯。 GPU はそれらを知りません——毎フレーム何千ものドローコールが節約されます。
概念の詳細
Frustum Culling は基本——Unity はカメラ視錐台の六平面 (FOV と near/far clip から作る切頭錐体)を各 Renderer の境界ボックスと照合します。 境界が完全に外なら → ドローコールをスキップ。組み込み、常時オン、設定不要。
Occlusion Culling は次の段階——視錐台内でも完全に隠れた物体をスキップ。 Unity は Umbra で遮蔽データを事前計算(ベイク): Window → Rendering → Occlusion Culling → Bake。Static ドロップダウンで occluder / occludee をマーク。 屋内に強く、オープンワールドでは弱め。
LOD (Level of Detail) は関連——完全にカリングする代わりに、 LOD Group が距離に応じてメッシュ複雑度を下げます。LOD0 = フル詳細(近)、LOD1 = 中、LOD2 = 簡易、 LOD3 = ビルボード、Culled = 非表示。距離による品質/性能のトレードオフです。
Backface Culling は GPU レベル——カメラから見て法線が向こうを向く三角形を落とします。
すべてのシェーダーでデフォルトオン、閉じたメッシュのフラグメント作業を約 50% 節約。
Material の “Two Sided” または ShaderLab の Cull Off で無効化。
カリングの種類
Frustum Culling
カメラ視野外のオブジェクトは完全にスキップされる。 自動。セットアップ不要。すべてのプロジェクトで有効。
Camera.layerCullDistances[]
Occlusion Culling
壁や建物に隠れたオブジェクトはスキップされる。 ベイクが必要 で Static を指定。屋内シーンに最適。
Static → Occluder/Occludee
LOD Group
カメラから遠いほどポリゴン数を減らす。LOD0→LOD3→Culled。 準備が必要 な複数メッシュ。オープンワールド向き。
LODGroup component
ハンズオン手順
Frustum Culling:Camera Far Clip を締める
Camera → Far Clip Plane:1000 から 200–500 に下げて遠い物体をカリング。切れ目はフォグで隠す。
Occlusion Culling 用に Static をマーク
壁/床/天井を選択 → Inspector → Static → Occluder Static と Occludee Static。
遮蔽データをベイク
Window → Rendering → Occlusion Culling → Bake。Occlusion Area でベイク体積を制御。
LOD Group を追加
Add Component → LOD Group → 各スロットに LOD0/1/2 メッシュをドロップし、画面サイズ % を調整。
Rendering Statistics で計測
Game View → Stats:カメラを動かし "Batches" と "Tris" を観察。Scene ビューの Occlusion Culling Visualization も。
インタラクティブシミュレーター
カメラをシーン周りでオービットし、どの物体が視錐台カリング / 遮蔽カリングされるかを確認。
Visible: 0
Culled: 0
コード例
基本レイヤーごとのカリング距離を設定し、レンダラーの可視性を確認。
using UnityEngine;
public class CullingSetup : MonoBehaviour
{
void Start()
{
Camera cam = Camera.main;
// Per-layer cull distance
// 32 entries (32 layers) — 0 = use Far Clip
float[] distances = new float[32];
distances[8] = 50f; // Layer 8 "SmallProps": cull after 50m
distances[9] = 150f; // Layer 9 "MediumProps": cull after 150m
distances[10] = 0f; // Layer 10: use Camera.farClipPlane
cam.layerCullDistances = distances;
// Spherical culling: from camera center, not frustum planes
cam.layerCullSpherical = true;
}
// Is this renderer currently visible to a camera?
void CheckVisibility(Renderer rend)
{
if (rend.isVisible)
Debug.Log(rend.name + " is being rendered");
}
}コード例
上級コードから LOD Group を設定し、LOD レベルを強制(デバッグ / カットシーン)。
using UnityEngine;
public class DynamicLOD : MonoBehaviour
{
public Renderer[] lod0, lod1, lod2;
LODGroup group;
void Awake()
{
group = GetComponent<LODGroup>();
if (group == null)
group = gameObject.AddComponent<LODGroup>();
// Configure LOD levels from code
LOD[] lods = new LOD[3];
lods[0] = new LOD(0.5f, lod0); // 50%+ screen → LOD0
lods[1] = new LOD(0.15f, lod1); // 15-50% → LOD1
lods[2] = new LOD(0.03f, lod2); // <3% → LOD2, <0 → culled
group.SetLODs(lods);
group.RecalculateBounds();
}
// Force a specific LOD (debug or cutscene close-up)
public void ForceLOD(int level)
{
group.ForceLOD(level); // -1 = disable force, use automatic
}
}📌 要点
- ▸Frustum Culling: 自動、設定不要
- ▸Occlusion Culling: ベイクが必要、屋内向き
- ▸LOD Group: 距離でポリゴン数を下げる
- ▸layerCullDistances: レイヤーごとのカリング範囲
- ▸renderer.isVisible: 描画中なら true
⚠️ よくあるミス
❌ Occlusion をベイクしたのに何もカリングされない
Camera → Occlusion Culling = true を忘れた
✅ Camera Inspector → Rendering → Occlusion Culling にチェック
❌ LOD ポップ(ズーム時にメッシュが跳ぶ)
LOD 遷移が広すぎ、LOD Fade なし
✅ LOD Group で "Fade Mode = Cross Fade" を設定してブレンド