gpt4 book ai didi

ios - 如何在相机向下看的轴上旋转 SCNNode?

转载 作者:IT王子 更新时间:2023-10-29 05:30:00 28 4
gpt4 key购买 nike

我添加了一个 UIRotationGestureRecognizer 并想用它来旋转用户选择的节点。

当前,它围绕 z 轴旋转,如下所示:

private var startingRotation: CGFloat = 0
@objc private func handleRotation(_ rotation: UIRotationGestureRecognizer) {
guard let node = sceneView.hitTest(rotation.location(in: sceneView), options: nil).first?.node else {
return
}
if rotation.state == .began {
startingRotation = CGFloat(node.rotation.w)
}
node.rotation = SCNVector4(0, 0, 1, -Float(startingRotation + rotation.rotation))
}

如果自从放置节点后相机没有移动,这将正常工作。

enter image description here

但是,如果用户移动到节点的一侧,它就不再围绕相机所面对的轴旋转。

enter image description here

如何始终围绕相机的轴旋转它?

最佳答案

我想我理解你的问题,但你对 Xartec 回答的评论让我有点困惑,不知道我是否真的理解。

重述:

目标是围绕通过从相机原点“直通”对象绘制一条线形成的矢量旋转对象。这是垂直于相机平面的矢量,在本例中为手机屏幕。该矢量是相机的 -Z 轴。

解决方案

根据我对你的目标的理解,这就是你所需要的

private var startingOrientation = GLKQuaternion.identity
private var rotationAxis = GLKVector3Make(0, 0, 0)
@objc private func handleRotation(_ rotation: UIRotationGestureRecognizer) {
guard let node = sceneView.hitTest(rotation.location(in: sceneView), options: nil).first?.node else {
return
}
if rotation.state == .began {
startingOrientation = GLKQuaternion(boxNode.orientation)
let cameraLookingDirection = sceneView.pointOfView!.parentFront
let cameraLookingDirectionInTargetNodesReference = boxNode.convertVector(cameraLookingDirection,
from: sceneView.pointOfView!.parent!)

rotationAxis = GLKVector3(cameraLookingDirectionInTargetNodesReference)
} else if rotation.state == .ended {
startingOrientation = GLKQuaternionIdentity
rotationAxis = GLKVector3Make(0, 0, 0)
} else if rotation.state == .changed {

// This will be the total rotation to apply to the starting orientation
let quaternion = GLKQuaternion(angle: Float(rotation.rotation), axis: rotationAxis)

// Apply the rotation
node.orientation = SCNQuaternion((startingOrientation * quaternion).normalized())
}
}

说明

真正关键的部分是确定要围绕哪个向量旋转,幸运的是 SceneKit 提供了非常方便的方法。遗憾的是,它们并未提供您需要的所有方法。

首先,您需要表示相机正面的矢量(相机始终朝向其前轴)。 SCNNode.localFront是-Z轴(0, 0, -1),这只是SceneKit中的一个约定。但是您想要在相机的父坐标系中表示 Z 轴的轴。我发现我经常需要它,所以我创建了一个扩展来从 SCNNode 获取 parentFront

现在我们有了相机的前轴

let cameraLookingDirection = sceneView.pointOfView!.parentFront

要将其转换为目标的引用系,我们使用 convertVector(_,from:)得到一个我们可以应用旋转的向量。当场景首次启动时,此方法的结果将是盒子的 -Z 轴(就像在您的静态代码中一样,但您使用了 Z 轴并取反了角度)。

let cameraLookingDirectionInTargetNodesReference = boxNode.convertVector(cameraLookingDirection, from: sceneView.pointOfView!.parent!)

为了实现附加旋转,这是我不清楚您是否需要的部分,我使用了四元数而不是向量旋转。基本上,我在手势开始时采用方框的方向,并通过四元数乘法应用旋转。这两行:

let quaternion = GLKQuaternion(angle: Float(rotation.rotation), axis: rotationAxis)
node.orientation = SCNQuaternion((startingOrientation * quaternion).normalized())

这个数学也可以用旋转向量或变换矩阵来完成,但这是我熟悉的方法。

结果

enter image description here

扩展

extension SCNNode {

/// The local unit Y axis (0, 1, 0) in parent space.
var parentUp: SCNVector3 {

let transform = self.transform
return SCNVector3(transform.m21, transform.m22, transform.m23)
}

/// The local unit X axis (1, 0, 0) in parent space.
var parentRight: SCNVector3 {

let transform = self.transform
return SCNVector3(transform.m11, transform.m12, transform.m13)
}

/// The local unit -Z axis (0, 0, -1) in parent space.
var parentFront: SCNVector3 {

let transform = self.transform
return SCNVector3(-transform.m31, -transform.m32, -transform.m33)
}
}

extension GLKQuaternion {

init(vector: GLKVector3, scalar: Float) {

let glkVector = GLKVector3Make(vector.x, vector.y, vector.z)

self = GLKQuaternionMakeWithVector3(glkVector, scalar)
}

init(angle: Float, axis: GLKVector3) {

self = GLKQuaternionMakeWithAngleAndAxis(angle, axis.x, axis.y, axis.z)
}

func normalized() -> GLKQuaternion {

return GLKQuaternionNormalize(self)
}

static var identity: GLKQuaternion {

return GLKQuaternionIdentity
}
}

func * (left: GLKQuaternion, right: GLKQuaternion) -> GLKQuaternion {

return GLKQuaternionMultiply(left, right)
}

extension SCNQuaternion {

init(_ quaternion: GLKQuaternion) {

self = SCNVector4(quaternion.x, quaternion.y, quaternion.z, quaternion.w)
}
}

extension GLKQuaternion {

init(_ quaternion: SCNQuaternion) {

self = GLKQuaternionMake(quaternion.x, quaternion.y, quaternion.z, quaternion.w)
}
}

extension GLKVector3 {

init(_ vector: SCNVector3) {
self = SCNVector3ToGLKVector3(vector)
}
}

关于ios - 如何在相机向下看的轴上旋转 SCNNode?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48530159/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com