我很难解释这些情况所以请耐心等待。
我想要的是当用户点击白色注释时,该点将滚动到中心(与地球一起)
我还希望能够以编程方式执行此操作,滚动到我为地球提供x / y坐标时的某个点
我正在使用以下函数来计算基于x / y坐标的SCNVector3
func positionForCoordinates(coordinates: CGPoint, radius: CGFloat) -> SCNVector3 {
let s = coordinates.x
let t = coordinates.y
let r = radius
let x = r * cos(s) * sin(t)
let y = r * sin(s) * sin(t)
let z = r * cos(t)
return SCNVector3(x: Float(x), y: Float(y), z: Float(z))
}
它的数学实际上是在逃避我。
答案 0 :(得分:2)
让我们根据您的问题假设,我们知道以下
我们可以利用SCNNode
和SCNCamera
的动画属性,这样我们就可以更轻松地制作动画,而不是手动渲染渲染循环中的值。
func setupCamera(scene: SCNScene) {
cameraOrbit = SCNNode()
cameraNode = SCNNode()
camera = SCNCamera()
// camera stuff
camera.usesOrthographicProjection = true
camera.orthographicScale = 10
camera.zNear = 1
camera.zFar = 100
// initially position is far away as we will animate moving into the globe
cameraNode.position = SCNVector3(x: 0, y: 0, z: 70)
cameraNode.camera = camera
cameraOrbit = SCNNode()
cameraOrbit.addChildNode(cameraNode)
scene.rootNode.addChildNode(cameraOrbit)
}
Camera节点通过SCNCamera
属性设置为camera
实例,并被包装在另一个节点内,因为我们将用它来操纵它的旋转。
为了简洁,我留下了用于在类中定义这些变量的代码。
我们需要一种方法,将地图坐标(纬度/经度)转换为旋转角度,以便我们将其插入SCNNode.eulerAngles
,以便围绕地球模型旋转我们的相机。
/**
Get rotation angle of sphere along x and y direction from input map coordinate to show such location at the center of view.
- Parameter from: Map coordinate to get rotation angle for sphere
- Returns: Tuple of rotation angle in form (x:, y:)
*/
func rotationXY(from coordinate: CLLocationCoordinate2D) -> (x: Double, y: Double) {
// convert map coordiante to texture coordinate
let v = 0.5 - (coordinate.latitude / 180.0)
let u = (coordinate.longitude / 360.0) + 0.5
// convert texture coordinate to rotation angles
let angleX = (u-0.5) * 2 * Double.pi
let angleY = (0.5-v) * -Double.pi
return (x: angleX, y: angleY)
}
从代码中,我们需要将地图坐标转换为纹理坐标,其中放置纹理即。将纹理漫射到球体上以正常渲染而不修改球体节点的旋转角度,并且相机的位置沿z轴放置(即x = 0,y = 0,z = N),此类纹理的中心将是显示在相机上。因此,在等式中,我们考虑0.5
来适应这一点。
之后我们将结果转换为角度(弧度)。沿着x方向,我们可以将球体旋转360度以完全环绕它。对于y方向,需要180度环绕它。
请注意,我没有删除
0.5
这两种情况,因为它在每次转换中都是按原样进行,并且更清楚地看到解释。您可以通过删除代码来简化它。
另外,我还会包括缩放级别。
假设您允许放大0.0到10.0的级别。我们使用orthographicScale
SCNNode
属性来模拟我们上面设置的正交类型相机的放大。相反,orthographicScale
与正常理解中的缩放级别相反。因此,在缩放级别10.0时,orthographicScale
将为0.0,以实现放大效果。
/**
Rotate camera around globe to specified coordinate.
- Parameter to: Location in coordinate (latitude/longitude)
- Parameter zoomLevel: Zoom level in range 0.0 - 10.0.
- Parameter duration: Duration for rotation
- Parameter completion: Delegate when rotation completes to notify back to user
*/
func flyGlobeTo(to location: CLLocationCoordinate2D, zoomLevel: Double, duration: Double, completion: (()->Void)?=nil) {
// make a call to our conversion method
let rotation = self.rotationXY(from: location)
SCNTransaction.begin()
SCNTransaction.animationDuration = duration
SCNTransaction.completionBlock = {
completion?()
}
self.cameraOrbit.eulerAngles.x = Float(rotation.y)
self.cameraOrbit.eulerAngles.y = Float(rotation.x)
self.camera.orthographicScale = 10.0 - zoomLevel // calculate value from inverse from orthographicScale
SCNTransaction.commit()
}
就是这样。每当您需要飞到地图上的目标坐标时,只需使用flyGlobeTo()
方法。确保在主线程中调用它。动画是通过SCNTransaction
完成的,而不是通过UIView.animate
完成的,显然它是不同的技术,但我在这里也注意到它是我第一次使用后者。