You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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)
        }
}

关键细节说明

  1. 为什么要类型转换?:model.materials.first返回的是遵循Material协议的实例,该协议没有暴露具体材质的属性(比如baseColor),必须转换为PhysicallyBasedMaterial才能访问这些属性。
  2. 为什么需要makeMutable()?:RealityKit中从Reality Composer Pro加载的材质默认是不可变的,直接修改会触发编译错误,必须生成可变副本才能修改属性。
  3. 为什么要重新设置ModelComponent?:ModelComponent是值类型,内部材质数组的修改不会自动同步到实体,必须将更新后的组件重新设置回实体才能生效。

内容的提问来源于stack exchange,提问作者radicalappdev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 00:05:00