不使用MeshRenderer去绘制Mesh【翻译】
Table of Contents
请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com
在 Unity 中不使用 MeshRenderer 渲染网格
1. 概述
- 目的:使用
DrawMesh
系列方法在 Unity 中渲染大量网格,而无需创建和管理 GameObject。 - 特点:
- 网格会受到光照影响,可以投射和接收阴影。
- 可以针对所有相机或特定相机渲染。
- 支持 GPU 实例化和 Compute Shader。
2. 常用方法
DrawMesh
:最简单的渲染方法,使用指定材质渲染网格。DrawMeshInstanced
:通过 GPU 实例化渲染大量相同网格,支持小规模变化(如颜色)。DrawMeshInstancedIndirect
:通过 ComputeBuffer 传递实例数量和位置等数据,适用于大规模实例化。DrawMeshInstancedProcedural
:与DrawMeshInstancedIndirect
类似,但实例数量可以直接从 C# 传递。DrawProcedural
:在 GPU 上执行绘制调用,无需顶点或索引缓冲区,适用于 Compute Shader。DrawProceduralIndirect
:与DrawProcedural
类似,但实例数量等数据从 ComputeBuffer 传递。
3. 代码示例
DrawMesh
:public class ExampleDrawMesh : MonoBehaviour { public Mesh mesh; public Material material; void Update() { Graphics.DrawMesh(mesh, Vector3.zero, Quaternion.identity, material, 0); } }
DrawMeshNow
:public class ExampleDrawMeshNow : MonoBehaviour { public Mesh mesh; public Material material; public void OnPostRender() { material.SetPass(0); Graphics.DrawMeshNow(mesh, Vector3.zero, Quaternion.identity); } }
DrawMeshInstanced
:public class ExampleDrawMeshInstanced : MonoBehaviour { public Mesh mesh; public Material material; Matrix4x4[] matrices; void OnEnable() { matrices = new Matrix4x4[10]; for (int i = 0; i < 10; i++) { Vector3 position = new Vector3(0, 0, i); Quaternion rotation = Quaternion.identity; Vector3 scale = new Vector3(0.3f, 0.3f, 0.3f); matrices[i] = Matrix4x4.TRS(position, rotation, scale); } } void Update() { Graphics.DrawMeshInstanced(mesh, 0, material, matrices); } }
DrawMeshInstancedIndirect
:public class ExampleDrawMeshInstancedIndirect : MonoBehaviour { public Mesh mesh; public Material material; ComputeBuffer argsBuffer; ComputeBuffer matricesBuffer; Bounds bounds; void Start() { argsBuffer = new ComputeBuffer(1, 5 * sizeof(uint), ComputeBufferType.IndirectArguments); argsBuffer.SetData(new uint[] { (uint)mesh.GetIndexCount(0), (uint)instanceCount, (uint)mesh.GetIndexStart(0), (uint)mesh.GetBaseVertex(0), 0 }); bounds = new Bounds(Vector3.zero, new Vector3(10.0f, 10.0f, 10.0f)); Matrix4x4[] matrices = new Matrix4x4[instanceCount]; for (int i = 0; i < instanceCount; i++) { Vector3 offset = new Vector3(i * 0.3f, Mathf.Sin(i / 3f), 0); matrices[i] = Matrix4x4.TRS(transform.position + offset, Quaternion.identity, new Vector3(0.3f, 0.3f, 0.3f)); } matricesBuffer = new ComputeBuffer(instanceCount, sizeof(float) * 4 * 4); matricesBuffer.SetData(matrices); material.SetBuffer("matricesBuffer", matricesBuffer); } void Update() { Graphics.DrawMeshInstancedIndirect(mesh, 0, material, bounds, argsBuffer); } void OnDisable() { matricesBuffer?.Release(); matricesBuffer = null; argsBuffer?.Release(); argsBuffer = null; } }
4. 使用场景
- 动态更新位置:在每帧更新网格位置,如波浪运动。
- 复杂模拟:使用 Compute Shader 进行网格位置的复杂计算(如群体模拟)。
- 大规模实例化:通过
DrawMeshInstancedIndirect
实现高效的大规模实例化渲染。
5. 文件下载
- 包含内容:
DrawMesh
、DrawMeshInstanced
、DrawMeshInstancedIndirect
的脚本。- 两个着色器(基础着色器和 PBR 表面着色器)。
- 使用 Compute Shader 移动网格的示例。
- 示例场景展示脚本使用方法。
总结
- 核心方法:
DrawMesh
系列方法提供了灵活的网格渲染方式,支持 GPU 实例化和 Compute Shader。 - 性能优化:通过
DrawMeshInstancedIndirect
和 Compute Shader,可以将计算任务卸载到 GPU,提升性能。 - 适用场景:适用于大规模实例化、动态位置更新和复杂模拟的渲染需求。