Ios Scenekit摄影机围绕对象旋转

Ios Scenekit摄影机围绕对象旋转,ios,swift,3d,scenekit,metal,Ios,Swift,3d,Scenekit,Metal,大家好, 我会回来告诉你我目前的问题。我已经问了一个问题,但是没有人能成功地帮助我。然后,我将解释我的全部问题,以及我如何试图解决它。(我试过几种方法) 因此,我需要编写一个库,添加许多函数,以便在3D世界中管理相机和对象。为此,我们选择了SceneKit框架来使用金属 我将发布一个非常简化的代码,但所有必要的东西都在这里 为了说明我的想法,这里有一个GIF,它解释了我希望我的相机是如何工作的: 这来自Stack问题(谢谢rickster): 目标是加载场景并处理用户平移动作,以在我的3D世界

大家好,

我会回来告诉你我目前的问题。我已经问了一个问题,但是没有人能成功地帮助我。然后,我将解释我的全部问题,以及我如何试图解决它。(我试过几种方法)

因此,我需要编写一个库,添加许多函数,以便在3D世界中管理相机和对象。为此,我们选择了SceneKit框架来使用金属

我将发布一个非常简化的代码,但所有必要的东西都在这里

为了说明我的想法,这里有一个GIF,它解释了我希望我的相机是如何工作的:

这来自Stack问题(谢谢rickster):

目标是加载场景并处理用户平移动作,以在我的3D世界中围绕3D对象的重心点移动摄影机。以下是我的基本简化代码:

import SceneKit
import UIKit

class SceneManager
{
    private let scene: SCNScene
    private let view: SCNView
    private let camera: SCNNode
    private let cameraOrbit: SCNNode

    init(view: SCNView, assetFolder: String, sceneName: String, cameraName: String, backgroundColor: UIColor) {
        self.view = view
        self.scene = SCNScene(named: (assetFolder + "/" + sceneName))!
        if (self.scene.rootNode.childNodeWithName(cameraName, recursively: true) == nil) {
            print("Fatal error: Cannot find camera in scene with name :\"", cameraName, "\"")
            exit(1)
        }
        self.camera = self.scene.rootNode.childNodeWithName(cameraName, recursively: true)! // Retrieve cameraNode created in scene file
        self.camera.removeFromParentNode()
        self.cameraOrbit = SCNNode()
        self.cameraOrbit.addChildNode(self.camera)
        self.scene.rootNode.addChildNode(self.cameraOrbit)
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(panHandler(_:)))
        panGesture.maximumNumberOfTouches = 1
        self.view.addGestureRecognizer(panGesture)
        self.view.backgroundColor = backgroundColor
        self.view.pointOfView = cameraNode
        self.view.scene = self.scene
    }

    @objc private func panHandler(sender: UIPanGestureRecognizer) {
        // some code here
    }
}
然后我探索了我在互联网上找到的许多可能的解决方案。我将介绍我所探索的主要解决方案

1)EulerAngle

Src:

我想在这个堆栈中应用rickster的方法。以下是我的代码:

@objc private func panHandler(sender: UIPanGestureRecognizer) {
    if (sender.state == UIGestureRecognizerState.Changed) {
        let scrollWidthRatio = Float(sender.velocityInView(sender.view!).x) / 10000 * -1
        let scrollHeightRatio = Float(sender.velocityInView(sender.view!).y) / 10000
        cameraOrbit.eulerAngles.y += Float(-2 * M_PI) * scrollWidthRatio
        cameraOrbit.eulerAngles.x += Float(-M_PI) * scrollHeightRatio
    }
}
这在Y轴上运行良好,但相机在X轴上围绕自身旋转。我不太明白什么是欧拉角,但我注意到Z轴从未改变。这就是为什么旋转不是球形的吗

2)自制解决方案

src:

这是一个关于worldPosition和localPosition的问题。但提出的解决方案不起作用。。。(或者我不明白)

这是我将主要使用的解决方案。但如果你有另一个解决方案,我准备探索和尝试它

理论上,var alpha是横坐标轴和相机(2D(x,z))在三角圆中的位置之间的角度。我用它来计算在X和Z旋转轴上应用的比率。 目标是使旋转跟随二维平面(x,z)上的线段。 但这不起作用,因为self.camera.position是相对于cameraOrbit(父节点)进行协调的,它需要worldPosition属性

摄影机worldTransform的参数是一个我不了解的矩阵,因此我无法使用它。即使我可以使用worldPosition属性,我也不确定它是否能很好地工作,因为我的角度和比率应用于X轴和Z轴

你怎么看,也许我需要改变我的方法

@objc private func panHandler(sender: UIPanGestureRecognizer) {
    let cameraROrbitRadius = sqrt(pow(self.camera.position.x, 2) + pow(self.camera.position.y, 2))
    let alpha = cos(self.camera.position.z / self.cameraOrbitRadius) // Get angle of camera
    var ratioX = 1 - ((CGFloat)(alpha) / (CGFloat)(M_PI)) // Get the ratio with angle for apply to Z and X axes rotation
    var ratioZ =  ((CGFloat)(alpha) / (CGFloat)(M_PI))
    // Change direction of rotation depending camera's position in trigonometric circle
    if (self.camera.position.x > 0 && self.camera.position.z < 0) {
        ratioX *= -1
    } else if (self.camera.position.z < 0 && self.camera.position.x < 0) {
        ratioX *= -1
        ratioZ *= -1
    } else if (self.camera.position.z > 0 && self.camera.position.x > 0) {
        ratioZ *= -1
    }
    // Set the angle rotation to add at imaginary sphere (cameraOrbit)
    let xAngleToAdd = (sender.velocityInView(sender.view!).y / 10000) * ratioX
    let yAngleToAdd = (sender.velocityInView(sender.view!).x / 10000) * (-1)
    let zAngleToAdd = (sender.velocityInView(sender.view!).y / 10000) * ratioZ
    let rotation = SCNAction.rotateByX(xAngleToAdd, y: yAngleToAdd, z: zAngleToAdd, duration: 0.5)
    self.cameraOrbit.runAction(rotation)
}
@objc private func panHandler(发送方:UIPangestureRecognitizer){
让cameraROrbitRadius=sqrt(pow(self.camera.position.x,2)+pow(self.camera.position.y,2))
设alpha=cos(self.camera.position.z/self.cameraOrbitRadius)//获取摄像机的角度
var ratioX=1-((CGFloat)(alpha)/(CGFloat)(M_PI))//获取应用于Z轴和X轴旋转的角度比率
var比率=((CGFloat)(alpha)/(CGFloat)(M_-PI))
//根据相机在三角圆中的位置更改旋转方向
if(self.camera.position.x>0&&self.camera.position.z<0){
ratioX*=-1
}else if(self.camera.position.z<0&&self.camera.position.x<0){
ratioX*=-1
比率*=-1
}else if(self.camera.position.z>0&&self.camera.position.x>0){
比率*=-1
}
//设置要在虚拟球体处添加的角度旋转(cameraOrbit)
设xAngleToAdd=(sender.velocityview(sender.view!).y/10000)*ratioX
让YangletLoadd=(sender.velocityView(sender.view!).x/10000)*(-1)
让ZangleLoadd=(sender.velocityView(sender.view!).y/10000)*比率
让旋转=SCNAction.rotateByX(X角向上,y:yAngleToAdd,z:zAngleToAdd,持续时间:0.5)
self.cameraOrbit.runAction(旋转)
}
此方法也适用于Y轴。但物体上方的旋转效果不好。我不能简单地解释它,但相机的旋转是这种理论运动的另类

我想我已经解释了所有重要的事情。如果你有什么想法或建议


关于,

您是否希望始终具有相同的“向上”面?我的意思是:用户视图中的“向上”方向是否应该始终为正y?如果是这样的话,你就不会在物体的正上方做一个急促的运动(想想看)。你可以限制它,这样用户就不能“翻过”对象。我不理解你提交的所有内容,但我没有特别使用这两种方法的突然移动。你的意思是相机不能在Y轴的物体上方吗?我认为是的,因为即使移动不是很好,相机也会完全围绕物体移动。