开发者社区 问答 正文

是否有可能将重点放在选定的SCNNode上

我有以下情况。一个SCNView带着.scn一座桥的展示。在屏幕的左边,你可以看到桥的视觉表现形式。

我想做以下几件事。

在“模型浏览器”中选择左边的项 缩放到选定的项目并将焦点集中在它上。 https://i.stack.imgur.com/OBDbi.png

在提供的截图上。你可以看到我选择了Kist是黄色的SceneView现在我想放大并聚焦在选定的SCNNode

我已经试过用rayTestWithSegment若要找到要缩放的选定位置,请执行以下操作。但结果rayTestWithSegment总是[].

我也试过用SCNLookAtConstraint但这不管用。

var constraint: SCNLookAtConstraint!

    func handle(gesture: UIGestureRecognizer) {
        guard let result = hitTestResult(for: gesture), let world = sceneView?.scene?.physicsWorld else { return }
        let nodePosition = result.node.position
        let results = world.rayTestWithSegment(from: SCNVector3(0, 1, 0), to: nodePosition, options: nil)
        print(results)
        constraint = SCNLookAtConstraint(target: result.node)
        sceneView?.pointOfView?.constraints = [constraint]
    }

    func hitTestResult(for gesture: UIGestureRecognizer) -> SCNHitTestResult? {
        let location = gesture.location(in: sceneView)
        guard let hit = sceneView?.hitTest(location, options: nil), hit.count > 0, let result = hit.first else {
            return nil
        }
        return result
    }

我在用rayTestWithSegment因为有可能SCNNode我选择的不是完全可见的。例如,一个SCNNode它位于此透视图中的另一个节点后面。

提前谢谢,我希望有人能帮我解释我做错了什么。

展开
收起
游客5akardh5cojhg 2019-12-11 18:48:50 584 分享 版权
阿里云 AI 助理回答

根据你的描述,你希望在SceneKit中实现点击屏幕上的3D模型节点后,场景视图能够自动缩放并聚焦到被选中的节点上。从你的代码片段来看,有几个地方可能需要调整:

  1. 使用hitTest(_:options:)而非自定义的hitTestResult(for:): 你的hitTestResult(for:)方法看起来是正确的,但直接使用sceneView.hitTest(location, options: nil)应该已经足够处理触摸事件并获取到击中的节点。

  2. 理解rayTestWithSegment的用途: rayTestWithSegment用于物理检测,即判断射线与物理体的碰撞,而不是用于找到一个可见或不可见的SCNNode。如果你的目标是找到用户点击位置对应的节点,你应该继续使用hitTest(_:options:)

  3. 使用SCNLookAtConstraint正确聚焦: 你的SCNLookAtConstraint应用方式基本正确,但是确保以下几点:

    • 确保pointOfView不为nil。这是执行观察操作的虚拟相机节点。
    • 设置约束时考虑是否需要调整GAFFER_lookAtUp, GAFFER_lookAtRight等属性来微调视角。
    • 在每次选择新节点后,重新设置约束以更新目标。
  4. 缩放和平移场景: 要缩放和平移到选定节点,你可以直接修改cameraNode的位置和缩放属性,或者使用动画平滑过渡。例如,你可以计算从当前相机位置到目标节点的最佳距离和方向,然后用动画来实现这一变化。

修正后的代码示例(注意:此代码未经过实际测试,仅提供思路):

@objc func handleTap(_ gestureRecognizer: UITapGestureRecognizer) {
    let location = gestureRecognizer.location(in: sceneView)
    if let hit = sceneView.hitTest(location, options: [.searchMode: .allHierarchies]).first {
        // 获取点击的节点
        let selectedNode = hit.node
        
        // 使用SCNLookAtConstraint聚焦
        let constraint = SCNLookAtConstraint(target: selectedNode)
        constraint.isGimbalLockEnabled = true // 可选,防止旋转异常
        sceneView.pointOfView?.constraints = [constraint]
        
        // 动画平滑聚焦和缩放
        let distance = sceneView.pointOfView?.position.distance(to: selectedNode.position) ?? 0
        let newCameraPosition = SCNVector3(selectedNode.position.x, selectedNode.position.y + distance * 1.5, selectedNode.position.z) // 调整距离以适应视图
        
        let animation = CABasicAnimation(keyPath: "position")
        animation.fromValue = sceneView.pointOfView?.position
        animation.toValue = newCameraPosition
        animation.duration = 0.5
        sceneView.pointOfView?.addAnimation(animation, forKey: "focusOnNode")
    }
}

请根据你的具体需求调整上述代码,比如动画时间、相机的新位置计算逻辑等。希望这能帮助你解决问题!

有帮助
无帮助
AI 助理回答生成答案可能存在不准确,仅供参考
0 条回答
写回答
取消 提交回答
问答地址: