2014-12-07 73 views
8

我有一个更多的数学问题与3D编程,我希望你能帮助我!场景套件平移二维平移到正确的三维只有水平

我想创建一个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 
} 

有谁知道计算屏幕转换成水平的3D转换,忽略了垂直轴的复杂的方法?

预先感谢您:)

编辑: 泛适用于水平翻译了。但不适用于垂直,因为我将z轴上的差异设置为零。

+0

你从不使用“diffTrans”。当你解除保护(而不是“翻译”)时,你不想使用“diffTrans”吗?否则,您将在每次迭代时积累翻译。 – Toyos 2014-12-07 22:19:55

+0

谢谢你指出这一点!我尝试了很多不同的方法,我没有看到那个错误。它解决了水平平移但不垂直的问题,因为世界翻译中不需要的垂直分量 – 2014-12-09 06:03:25

+0

检查出答案rickster答案在这里:http://stackoverflow.com/questions/25150737/how-to-use- ios-swift-scenekit-scnscenerenderer-unprojectpoint-properly 在最后关于处理未投影时,他的相机与“世界”不一样。这可能是一个有用的起点。 – 2014-12-15 23:51:17

回答

9

我找到了我自己的解决方案。

我正在计算手势开始位置(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; 
    } 
} 

Red is screen translation, Blue is world translation

1

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

//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; 
    } 
} 

为了得到正确的缩放比例,您需要使用screenheight作为orthographicScale的变量。我在这里使用的缩放比例是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)