Ios Scenekit平移二维到仅正交三维的水平平移

Ios Scenekit平移二维到仅正交三维的水平平移,ios,math,3d,translation,scenekit,Ios,Math,3d,Translation,Scenekit,我有一个关于3D编程的数学问题,我希望你能帮助我 我正试图创建一个三维游戏使用Scenekit等轴测角度 此代码创建我的正交摄影机: var cameraNode = SCNNode() cameraNode.camera = SCNCamera() cameraNode.name = "Camera" cameraNode.position = SCNVector3Make(-5.0, -5.0, 10.0) cameraNode.eulerAngles = SCNVector3Make(PI

我有一个关于3D编程的数学问题,我希望你能帮助我

我正试图创建一个三维游戏使用Scenekit等轴测角度

此代码创建我的正交摄影机:

var cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.name = "Camera"
cameraNode.position = SCNVector3Make(-5.0, -5.0, 10.0)
cameraNode.eulerAngles = SCNVector3Make(PI / 3.0, 0.0, -PI / 4.0)
cameraNode.camera?.usesOrthographicProjection = true
cameraNode.camera?.orthographicScale = 7.0
scene.rootNode.addChildNode(cameraNode)
现在我想使用平移手势移动相机,产生滚动的感觉。要做到这一点,相机不应该垂直移动,而应该水平移动。屏幕上的触摸位置和3D世界中未投影的位置在移动时应保持不变

我考虑将二维转换计算为三维差分,忽略垂直分量。这段代码实际上可以工作,几乎可以产生所需的结果,但速度不正确。如果我摇摄,相机似乎会加速,并且反应不正确:

var previousTranslation = CGPointMake(0.0, 0.0)

func pan(gesture: UIPanGestureRecognizer)
{
    let view = self.view as SCNView
    let translation = gesture.translationInView(view)
    let location = gesture.locationInView(view)

    let diffTrans = translation - previousTranslation
    previousTranslation = translation

    let cameraNode = scene.rootNode.childNodeWithName("Camera", recursively: false)

    let worldPointTrans = view.unprojectPoint(SCNVector3Make(-Float(diffTrans.x), -Float(diffTrans.y), 0.0))
    let worldPoint0 = view.unprojectPoint(SCNVector3Make(0.0, 0.0, 0.0))

    var diff = worldPointTrans - worldPoint0
    diff.x = diff.x / Float(cameraNode!.camera!.orthographicScale)
    diff.y = diff.y / Float(cameraNode!.camera!.orthographicScale)
    diff.z = 0
    cameraNode?.position += diff
}
有人知道一种复杂的方法,可以忽略垂直轴,将屏幕平移计算成水平三维平移吗

提前感谢:)

编辑:
pan现在可以进行水平翻译。但不是垂直方向,因为我将z轴上的差值设置为零。

我找到了自己的解决方案

我正在计算手势开始位置(P1-P2)处的光线和平移位置(Q1-Q2)处的光线。现在我有两条光线,让它们都与XY平面相交,以接收点P0和Q0

P0和Q0的差异是未投影的翻译

这种技术应该也适用于非正交相机,但我还没有测试过

在我看来,这是可行的,但如果有人能从数学上证实这一假设,我会很高兴读到:)

代码如下:

 var previousLocation = SCNVector3(x: 0, y: 0, z: 0)

func pan(gesture: UIPanGestureRecognizer)
{
    let view = self.view as SCNView
    let translation = gesture.translationInView(view)

    let location = gesture.locationInView(view)
    let secLocation = location + translation

    let P1 = view.unprojectPoint(SCNVector3(x: Float(location.x), y: Float(location.y), z: 0.0))
    let P2 = view.unprojectPoint(SCNVector3(x: Float(location.x), y: Float(location.y), z: 1.0))

    let Q1 = view.unprojectPoint(SCNVector3(x: Float(secLocation.x), y: Float(secLocation.y), z: 0.0))
    let Q2 = view.unprojectPoint(SCNVector3(x: Float(secLocation.x), y: Float(secLocation.y), z: 1.0))

    let t1 = -P1.z / (P2.z - P1.z)
    let t2 = -Q1.z / (Q2.z - Q1.z)

    let x1 = P1.x + t1 * (P2.x - P1.x)
    let y1 = P1.y + t1 * (P2.y - P1.y)

    let P0 = SCNVector3Make(x1, y1,0)

    let x2 = Q1.x + t1 * (Q2.x - Q1.x)
    let y2 = Q1.y + t1 * (Q2.y - Q1.y)

    let Q0 = SCNVector3Make(x2, y2, 0)

    var diffR = Q0 - P0
    diffR *= -1

    let cameraNode = view.scene!.rootNode.childNodeWithName("Camera", recursively: false)

    switch gesture.state {
    case .Began:
        previousLocation = cameraNode!.position
        break;
    case .Changed:
        cameraNode?.position = previousLocation + diffR
        break;
    default:
        break;
    }
}

我已经计算了等距平移的方程式,代码如下

//camera pan ISOMETRIC logic
func pan(gesture: UIPanGestureRecognizer) {
    let view = self.sceneView as SCNView
    let cameraNode = view.scene!.rootNode.childNode(withName: "Camera", recursively: false)
    let translation = gesture.translation(in: view)

    let constant: Float = 30.0
    var translateX = Float(translation.y)*sin(.pi/4.0)/cos(.pi/3.0)-Float(translation.x)*cos(.pi/4.0)
    var translateY = Float(translation.y)*cos(.pi/4.0)/cos(.pi/3.0)+Float(translation.x)*sin(.pi/4.0)
    translateX = translateX / constant
    translateY = translateY / constant

    switch gesture.state {
    case .began:
        previousLocation = cameraNode!.position
        break;
    case .changed:
        cameraNode?.position = SCNVector3Make((previousLocation.x + translateX), (previousLocation.y + translateY), (previousLocation.z))
        break;
    default:
        break;
    }
}
要正确缩放,需要使用屏幕高度作为正交缩放的变量。我在这里使用的缩放比例是30倍放大,注意30也用于上面代码中的常数

    let screenSize: CGRect = UIScreen.main.bounds
    let screenHeight = screenSize.height
    let cameraNode = SCNNode()
    cameraNode.camera = SCNCamera()
    cameraNode.name = "Camera"
    let cameraDist = Float(20.0)
    let cameraPosX = cameraDist*(-1.0)*cos(.pi/4.0)*cos(.pi/6.0)
    let cameraPosY = cameraDist*(-1.0)*sin(.pi/4.0)*cos(.pi/6.0)
    let cameraPosZ = cameraDist*sin(.pi/6)
    cameraNode.position = SCNVector3Make(cameraPosX, cameraPosY, cameraPosZ)
    cameraNode.eulerAngles = SCNVector3Make(.pi / 3.0, 0.0, -.pi / 4.0)
    cameraNode.camera?.usesOrthographicProjection = true
    cameraNode.camera?.orthographicScale = Double(screenHeight)/(2.0*30.0) //30x magnification constant. larger number = larger object
    scene.rootNode.addChildNode(cameraNode)

你从不使用“diffTrans”。当您取消保护(而不是“翻译”)时,您不想使用“diffTrans”吗?否则你会在每次迭代中积累翻译。谢谢你指出这一点!我尝试了很多不同的方法,但我没有看到那个错误。它解决了水平平移的问题,但没有解决垂直平移的问题,因为世界平移中不需要的垂直部分请查看答案rickster的答案:他在结尾有一条关于在相机平面与“世界”不同时处理非投影的注释。这可能是一个有用的起点。@MalcolmDwyer谢谢你的链接!我会尝试使用它,但它似乎不适用于我的情况,就像他在帖子末尾说的,如果相机旋转,这是不工作的!!如果你知道的话,你能帮我吗