文档目标:详解如何在 Unity 中实现海量同屏单位的高效渲染,从 MaterialPropertyBlock 到 DrawMeshInstancedIndirect 的完整技术路线。
当屏幕上有 1000 个相同的史莱姆时,传统的渲染流程是:
问题:CPU 和 GPU 之间的通讯(Draw Call)太慢了。GPU 可以在 1 毫秒内画完 1000 个史莱姆,但 CPU 发送 1000 条指令需要 10 毫秒。 解法:CPU 打包数据:“这里有一堆位置列表,都是史莱姆,一次画完!”(GPU Instancing)。
最简单的优化,不需要改 Shader(如果是 Standard Shader)或仅需少量改动。
// ❌ 错误做法:renderer.material.color = Color.red; (会创建材质副本,破坏合批)
// ✅ 正确做法:使用 MaterialPropertyBlock
private MaterialPropertyBlock _propBlock;
private Renderer _renderer;
void Start() {
_propBlock = new MaterialPropertyBlock();
_renderer = GetComponent<Renderer>();
}
void UpdateColor(Color newColor) {
_renderer.GetPropertyBlock(_propBlock);
_propBlock.SetColor("_Color", newColor);
_renderer.SetPropertyBlock(_propBlock);
}
Shader 设置:确保材质勾选了 Enable GPU Instancing。
当不需要 GameObject,只需要纯粹的渲染时(例如弹幕、掉落物)。
public class BulletRenderer : MonoBehaviour
{
public Mesh bulletMesh;
public Material bulletMat;
// 每次最多画 1023 个,所以需要切分数组
private List<Matrix4x4[]> _batches = new List<Matrix4x4[]>();
void Update() {
// 假设 _batches 已经填满了位置数据
foreach (var batch in _batches) {
Graphics.DrawMeshInstanced(bulletMesh, 0, bulletMat, batch);
}
}
}
限制:仍然需要在每一帧由 CPU 整理 Matrix4x4 数组并上传,带宽压力依然存在。
Indirect 的意思是:CPU 甚至不知道要画多少个,数量由 GPU (Compute Shader) 决定,或者参数直接存在 GPU 显存里(ComputeBuffer)。
// 声明缓冲区
StructuredBuffer<float4x4> _LocalToWorldBuffer;
StructuredBuffer<float4> _ColorBuffer;
void vert(inout appdata_full v, uint instanceID : SV_InstanceID) {
// 直接从显存读取矩阵
float4x4 mat = _LocalToWorldBuffer[instanceID];
v.vertex = mul(mat, v.vertex);
v.normal = mul((float3x3)mat, v.normal);
}
void Update() {
// 将计数重置,或由 Compute Shader 计算可见数量
argsBuffer.SetData(args);
// 绑定数据
instanceMaterial.SetBuffer("_LocalToWorldBuffer", positionBuffer);
instanceMaterial.SetBuffer("_ColorBuffer", colorBuffer);
// 一次调用,画 15,000 个
Graphics.DrawMeshInstancedIndirect(mesh, 0, instanceMaterial, bounds, argsBuffer);
}
| 方法 | Draw Calls | FPS (PC) | CPU 开销 |
|---|---|---|---|
| GameObjects | ~10,000 | 4 fps | 100% (Main Thread) |
| Static Batching | ~50 | 15 fps | High (Memory Overhead) |
| GPU Instancing | ~10 | 45 fps | Medium (Matrix Upload) |
| Indirect | 1 | 120+ fps | Zero |
SHADOW_CASTER pass 并支持 Instancing 宏,否则阴影会消失或不跟随。对于 Vampirefall: