围绕对象

时间:2016-07-26 09:41:11

标签: ios swift 3d scenekit metal

大家好,

我回答你关于我当前的问题。我已经问了一个关于这个的问题,但没有人能成功帮助我。然后我将解释我的完整问题以及我是如何尝试解决它的。 (我尝试了几件事)

因此,我需要编写一个lib,它可以添加许多功能,以便管理3D世界中的摄像机和对象。为此,我们选择了SceneKit Framework来使用Metal。

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

为了说明我的想法,一个GIF解释了我希望我的相机如何表现如下: http://i.stack.imgur.com/5tHUl.gif

这来自Stack问题(谢谢rickster):Rotate SCNCamera node looking at an object around an imaginary sphere

目标是加载场景并处理用户平移动作以在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:Rotate SCNCamera node looking at an object around an imaginary sphere

我想在此堆栈中应用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轴上旋转。我不太清楚是什么引用了eulerAngle,但我注意到Z轴永远不会改变。这就是旋转不是球形的原因吗?

2)自制解决方案

src:SceneKit Child node position not changed during Parent node rotation

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

这是我将主要使用的解决方案。但如果您有其他解决方案,我准备好探索并尝试一下!

理论上,var alpha是横坐标轴与三角圆中摄像机位置(2D(x,z))之间的角度。我用它来计算在X和Z旋转轴上应用的比率。 目标是在2D平面(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)
}

此方法也适用于Y轴。但是对象上方的旋转效果很差。我无法简单地解释它,但相机的旋转是这种理论运动的另一种选择。

我想我已经解释了所有重要的事情。如果您有任何想法或提示?

此致

0 个答案:

没有答案