如何在RealityView中运行时修改RealityKit材质颜色?
问题
在RealityView中从Reality Composer Pro加载场景后,交互实体使用的是带漫反射颜色的PhysicallyBasedMaterial,希望在长按事件触发时修改该颜色。已获取到实体及材质引用,但无法访问材质的属性(比如diffuseColor)进行修改。
用户提供的关键代码片段:
var longPress: some Gesture { LongPressGesture(minimumDuration: 0.5) .targetedToAnyEntity() .onEnded { value in value.entity.position.y = value.entity.position.y + 0.01 if var shadow = value.entity.components[GroundingShadowComponent.self] { shadow.castsShadow = true value.entity.components.set(shadow) } if let model = value.entity.components[ModelComponent.self] { print("material", model) if let mat = model.materials.first { print("material", mat) // I have a material here but I can't set any properties? // mat.diffuseColor does not exist } } } }
完整代码:
struct Lab5026: View { var body: some View { RealityView { content in if let root = try? await Entity(named: "GestureLab", in: realityKitContentBundle) { root.position = [0, -0.45, 0] if let subject = root.findEntity(named: "Cube") { subject.components.set(HoverEffectComponent()) subject.components.set(GroundingShadowComponent(castsShadow: false)) } content.add(root) } } .gesture(longPress.sequenced(before: dragGesture)) } var longPress: some Gesture { LongPressGesture(minimumDuration: 0.5) .targetedToAnyEntity() .onEnded { value in value.entity.position.y = value.entity.position.y + 0.01 if var shadow = value.entity.components[GroundingShadowComponent.self] { shadow.castsShadow = true value.entity.components.set(shadow) } if let model = value.entity.components[ModelComponent.self] { print("material", model) if let mat = model.materials.first { print("material", mat) // I have a material here but I can't set any properties? // mat.diffuseColor does not exist // PhysicallyBasedMaterial } } } } var dragGesture: some Gesture { DragGesture() .targetedToAnyEntity() .onChanged { value in let newPostion = value.convert(value.location3D, from: .global, to: value.entity.parent!) let limit: Float = 0.175 value.entity.position.x = min(max(newPostion.x, -limit), limit) value.entity.position.z = min(max(newPostion.z, -limit), limit) } .onEnded { value in value.entity.position.y = value.entity.position.y - 0.01 if var shadow = value.entity.components[GroundingShadowComponent.self] { shadow.castsShadow = false value.entity.components.set(shadow) } } } }
解决方案
要运行时修改PhysicallyBasedMaterial的颜色,需要遵循RealityKit的值类型修改规则,具体实现如下:
核心步骤
- 类型转换:将通用的
Material协议实例转换为具体的PhysicallyBasedMaterial类型,只有具体类型才暴露漫反射等可修改属性。 - 创建可变副本:RealityKit的材质是不可变值类型,必须调用
makeMutable()生成可变副本才能修改属性。 - 更新组件:修改完材质后,将更新后的
ModelComponent重新设置回实体,完成同步。
修改后的长按手势代码
var longPress: some Gesture { LongPressGesture(minimumDuration: 0.5) .targetedToAnyEntity() .onEnded { value in value.entity.position.y = value.entity.position.y + 0.01 // 原有阴影逻辑保留 if var shadow = value.entity.components[GroundingShadowComponent.self] { shadow.castsShadow = true value.entity.components.set(shadow) } // 修改材质颜色的核心逻辑 guard var modelComponent = value.entity.components[ModelComponent.self], let pbrMaterial = modelComponent.materials.first as? PhysicallyBasedMaterial else { return } // 创建可变材质副本,修改漫反射颜色(这里示例设为红色) var mutableMaterial = pbrMaterial.makeMutable() mutableMaterial.baseColor = .init(tint: .red) // 将修改后的材质替换回组件,并重新设置到实体 modelComponent.materials[0] = mutableMaterial value.entity.components.set(modelComponent) } }
关键细节说明
- 为什么要类型转换?:
model.materials.first返回的是遵循Material协议的实例,该协议没有暴露具体材质的属性(比如baseColor),必须转换为PhysicallyBasedMaterial才能访问这些属性。 - 为什么需要
makeMutable()?:RealityKit中从Reality Composer Pro加载的材质默认是不可变的,直接修改会触发编译错误,必须生成可变副本才能修改属性。 - 为什么要重新设置
ModelComponent?:ModelComponent是值类型,内部材质数组的修改不会自动同步到实体,必须将更新后的组件重新设置回实体才能生效。
内容的提问来源于stack exchange,提问作者radicalappdev
相关产品推荐
相关产品推荐

