Unity优化 场景DrawCall千千万,血条就能占一半
前言
在战斗场景打开Frame Debug
窗口,发现场景中的血条绘制了100次,需要优化一下。
使用GPU Instancing
的好处
- 极低的DrawCall数量
- 高效的GPU利用率
- 支持大量实例同时渲染
- 内存占用较低
- 更新性能优秀
项目
场景布置
创建一个空物体
创建脚本并挂载赋值
创建一个材质球
这里使用ASE
创建一个简单的Shader
意思一下
编写代码
using UnityEngine;
using System.Collections.Generic;
public class CreateHPBar : MonoBehaviour
{
public GameObject hpBarPrefab;
public Material sharedMaterial;
private MaterialPropertyBlock propertyBlock;
private List<MeshRenderer> renderers = new List<MeshRenderer>();
void Awake()
{
propertyBlock = new MaterialPropertyBlock();
}
void Start()
{
// 1. 首先创建所有实例并收集渲染器引用
for (int i = 0; i < 10; i++)
{
GameObject hpb = Instantiate(hpBarPrefab, new Vector3(i * 2, 0, 0), Quaternion.identity);
MeshRenderer render = hpb.GetComponent<MeshRenderer>();
render.sharedMaterial = sharedMaterial;
renderers.Add(render);
}
// 2. 一次性设置所有属性
UpdateAllHPBars();
}
// 统一更新所有血条的方法
private void UpdateAllHPBars()
{
propertyBlock.Clear(); // 清除之前的属性设置
// 为每个渲染器设置相同的PropertyBlock
for (int i = 0; i < renderers.Count; i++)
{
propertyBlock.Clear();
propertyBlock.SetFloat("_FakeHpValue", 0.1f * i);
renderers[i].SetPropertyBlock(propertyBlock);
}
}
// 如果需要动态更新某个血条
public void UpdateSingleHPBar(int index, float value)
{
if (index >= 0 && index < renderers.Count)
{
propertyBlock.Clear();
propertyBlock.SetFloat("_FakeHpValue", value);
renderers[index].SetPropertyBlock(propertyBlock);
}
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Q))
{
UpdateSingleHPBar(2, 1.0f);
}
if (Input.GetKeyDown(KeyCode.W))
{
UpdateSingleHPBar(2, 0.0f);
}
}
}
使用GPU Instancing优化血条渲染
此时运行场景能够看到这些血条并没有合批
需要设置修改的值为Instanced Property
并且勾选Per Renderer Data
确保Shader
设置中勾选GPU Instancing
修改完成之后
总结
这种方案不适用于UGUI系统。
可以直接应用于此血条(需要修改Shader为URPUnLit)
Unity Shader分段式血条