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

如何在SceneKit与SwiftUI中实现稳定的3D模型重置按钮?

问题描述

在SwiftUI开发的ModelViewer中,通过CustomSceneView展示3D模型,需实现重置按钮将模型及相机恢复至初始状态。当前实现存在以下问题:

  • 当模型处于运动状态时点击重置按钮,复位后的位置会随机偏移
  • 最初缩放后复位无法恢复缩放比例,添加self.view.pointOfView?.camera?.fieldOfView = camera.fieldOfView后缩放问题解决,但运动中复位偏移的问题仍存在
  • 限制条件:无法修改模型,只能通过相机和节点定位调整
修复方案

问题根源在于开启allowsCameraControl后,SceneKit内置相机控制逻辑会在后台持续修改相机节点属性,与复位事务产生冲突。以下是针对性修复:

  • 临时禁用相机控制:复位前关闭allowsCameraControl,避免内置逻辑干扰,复位完成后重新开启
  • 直接操作固定相机节点:使用预先创建的cameraNode而非view.pointOfView,避免引用不稳定的节点实例
  • 补充正交投影参数重置:正交模式下缩放依赖orthographicScale,需同步重置该参数
  • 清理未完成事务:复位前结束所有未完成的SCNTransaction,防止动画叠加导致偏移
修改后的代码

补充Camera结构体参数

struct Camera {
    static let `default` = Camera(
        position: SCNVector3(x: 0.805120, y: 0.057330, z: 1.4),
        rotation: SCNVector4(0, 0, 0, 0),
        orientation: SCNVector4(x: 0, y: 0, z: 0, w: 1.0),
        fieldOfView: 60,
        orthographicScale: 1.0
    )

    let position: SCNVector3
    let rotation: SCNVector4
    let orientation: SCNVector4
    let fieldOfView: CGFloat
    let orthographicScale: CGFloat

    init(position: SCNVector3, rotation: SCNVector4, orientation: SCNVector4, fieldOfView: CGFloat, orthographicScale: CGFloat) {
        self.position = position
        self.rotation = rotation
        self.orientation = orientation
        self.fieldOfView = fieldOfView
        self.orthographicScale = orthographicScale
    }

    init(from node: SCNNode) {
        let camera = node.camera ?? SCNCamera()
        self.init(
            position: node.position,
            rotation: node.rotation,
            orientation: node.orientation,
            fieldOfView: camera.fieldOfView,
            orthographicScale: camera.orthographicScale
        )
    }
}

修复CustomSceneView的Coordinator逻辑

class Coordinator: NSObject, SCNSceneRendererDelegate {
    // 原有初始化代码保持不变

    func set(camera: Camera?) {
        guard let camera else { return }
        
        // 清理未完成的事务,避免动画冲突
        SCNTransaction.flush()
        
        // 临时禁用相机控制,阻止内置逻辑干扰复位
        view.allowsCameraControl = false
        
        SCNTransaction.begin()
        SCNTransaction.animationDuration = 1
        
        // 直接操作预先创建的cameraNode,确保节点引用稳定
        cameraNode.position = camera.position
        cameraNode.rotation = camera.rotation
        cameraNode.orientation = camera.orientation
        
        // 重置相机的所有参数,包括正交缩放
        if let cameraComponent = cameraNode.camera {
            cameraComponent.fieldOfView = camera.fieldOfView
            cameraComponent.orthographicScale = camera.orthographicScale
        }
        
        // 动画完成后恢复相机控制
        SCNTransaction.completionBlock = { [weak self] in
            self?.view.allowsCameraControl = true
        }
        
        SCNTransaction.commit()
    }

    // 原有渲染代理方法保持不变
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 19:20:08