Unity ECS:如何在SystemBase的OnUpdate中修改单个实体的材质颜色
解决方案
方法一:使用MaterialPropertyBlock(推荐,低性能开销)
这是ECS中实现单个实体改色的最优方案,它不需要复制材质,只是临时覆盖单个实体渲染器的颜色属性,不会影响共享同一材质的其他实体。
修改你的System代码如下:
[UpdateAfter(typeof(CityStageSpawnSystem))] public partial class ApplyColorSystem : SystemBase { protected override void OnUpdate() { var propertyBlock = new MaterialPropertyBlock(); Entities.ForEach((RenderMeshProxy renderProxy, ref ChangeColorComponent colorComponent) => { if (!colorComponent.changeIt) return; // 获取当前渲染器的属性块 renderProxy.Renderer.GetPropertyBlock(propertyBlock); // 设置颜色("_Color"是Unity标准材质的颜色属性名,自定义材质需替换为对应属性名,比如"_BaseColor") propertyBlock.SetColor("_Color", new Color( colorComponent.NewColor.x, colorComponent.NewColor.y, colorComponent.NewColor.z, colorComponent.NewColor.w )); // 把修改后的属性块赋值回去 renderProxy.Renderer.SetPropertyBlock(propertyBlock); // 标记为已处理,避免重复执行 colorComponent.changeIt = false; }) .WithoutBurst().Run(); } }
注意:确保你的实体带有RenderMeshProxy组件(生成带RenderMesh的实体时通常会自动添加)。
方法二:创建独立材质(适合持久修改场景)
如果需要永久替换实体的材质(后续修改原始材质不会影响该实体),可以复制原始材质并重新分配给单个实体,但这种方法会增加内存开销,不建议大量使用。
代码示例:
[UpdateAfter(typeof(CityStageSpawnSystem))] public partial class ApplyColorSystem : SystemBase { protected override void OnUpdate() { Entities.ForEach((Entity entity, ref ChangeColorComponent colorComponent, in RenderMeshArray renderMeshArray, in MaterialMeshInfo materialMeshInfo) => { if (!colorComponent.changeIt) return; // 复制原始材质并修改颜色 var originalMaterial = renderMeshArray.GetMaterial(materialMeshInfo); var newMaterial = Object.Instantiate(originalMaterial); newMaterial.color = new Color( colorComponent.NewColor.x, colorComponent.NewColor.y, colorComponent.NewColor.z, colorComponent.NewColor.w ); // 移除共享的渲染组件,添加独立的RenderMesh EntityManager.RemoveComponent<RenderMeshArray>(entity); EntityManager.RemoveComponent<MaterialMeshInfo>(entity); var renderMesh = RenderMesh.FromComponents( renderMeshArray.GetMesh(materialMeshInfo), newMaterial, renderMeshArray.GetSubmeshIndex(materialMeshInfo) ); EntityManager.AddComponentData(entity, renderMesh); // 标记为已处理 colorComponent.changeIt = false; }) .WithoutBurst().Run(); } }
内容的提问来源于stack exchange,提问作者MGodoy BR
相关产品推荐
相关产品推荐

