Unity技术问询:未在层级面板的预制体如何通过按钮修改材质
解决AR预制体不在Hierarchy时的材质切换问题
我明白你的痛点——把模型留在Hierarchy里会一直显示在AR场景中,但移除后又没法通过Inspector绑定按钮的OnClick事件。用AddListener动态绑定事件确实是正确的思路,我们可以通过一个全局管理器来搞定这个问题,具体方案如下:
步骤1:整理模型预制体
先把你的模型做成预制体(拖到Project面板里,然后从Hierarchy中移除),保留原来的ChangeColor脚本挂载在预制体上,原有逻辑不用修改。
步骤2:创建全局管理器脚本
新建一个名为ARMaterialController的脚本,挂载到场景中全程存在的对象上(比如AR Session Origin,它会在AR场景运行期间一直存在)。这个管理器会负责:
- 引用你的UI按钮
- 保存实例化后的模型引用
- 动态给按钮绑定点击监听
管理器脚本代码:
using UnityEngine; using UnityEngine.UI; public class ARMaterialController : MonoBehaviour { // 引用你的三个颜色切换按钮 public Button greyBtn; public Button yellowBtn; public Button redBtn; // 你的模型预制体 public GameObject modelPrefab; // 保存实例化后模型上的ChangeColor组件引用 private ChangeColor modelColorHandler; void Start() { // 给按钮动态添加点击监听 greyBtn.onClick.AddListener(TriggerGreyMaterial); yellowBtn.onClick.AddListener(TriggerYellowMaterial); redBtn.onClick.AddListener(TriggerRedMaterial); } // 这个方法要在AR识别到目标后调用(比如AR Tracked Image的回调里) public void SpawnARModel(Vector3 spawnPos, Quaternion spawnRot) { GameObject spawnedModel = Instantiate(modelPrefab, spawnPos, spawnRot); // 获取模型上的ChangeColor组件 modelColorHandler = spawnedModel.GetComponent<ChangeColor>(); } // 按钮点击后的实际执行逻辑 private void TriggerGreyMaterial() { modelColorHandler?.GreyMaterial(); } private void TriggerYellowMaterial() { modelColorHandler?.YellowMaterial(); } private void TriggerRedMaterial() { modelColorHandler?.RedMaterial(); } }
步骤3:配置与使用
- 在Inspector面板给
ARMaterialController赋值:- 把三个颜色按钮分别拖入对应的Button字段
- 把你的模型预制体拖入
modelPrefab字段
- 在你的AR识别逻辑里(比如AR Tracked Image Manager的
OnTrackedImagesChanged回调),调用SpawnARModel方法实例化模型——这样模型只会在识别到目标后才出现,不会一直显示在场景里。 - 此时按钮的点击事件已经通过
AddListener动态绑定,完全不需要再通过Inspector设置OnClick,只要模型被实例化出来,就能正常触发材质切换。
可选优化:简化逻辑(去掉原ChangeColor脚本)
如果你觉得模型上挂额外脚本麻烦,也可以把材质切换逻辑直接整合到管理器里,这样模型上不需要任何额外脚本:
using UnityEngine; using UnityEngine.UI; public class ARMaterialController : MonoBehaviour { public Button greyBtn; public Button yellowBtn; public Button redBtn; public GameObject modelPrefab; // 直接在这里配置需要切换的材质数组 public Material[] materials; private Renderer modelRenderer; void Start() { greyBtn.onClick.AddListener(() => SwitchMaterial(0)); yellowBtn.onClick.AddListener(() => SwitchMaterial(1)); redBtn.onClick.AddListener(() => SwitchMaterial(2)); } public void SpawnARModel(Vector3 spawnPos, Quaternion spawnRot) { GameObject spawnedModel = Instantiate(modelPrefab, spawnPos, spawnRot); modelRenderer = spawnedModel.GetComponent<Renderer>(); modelRenderer.enabled = true; } private void SwitchMaterial(int materialIndex) { if (modelRenderer != null && materialIndex < materials.Length) { modelRenderer.sharedMaterial = materials[materialIndex]; } } }
这种方式把所有逻辑集中在管理器里,更简洁,适合简单的材质切换场景。
内容的提问来源于stack exchange,提问作者raspberry
相关产品推荐
相关产品推荐

