Я разрабатываю некоторый код, используя SceneKit для iOS, и в моем коде я хочу определить координаты x и y на глобальной плоскости z, где z равно 0.0, а x и y определяются по жестом касания. Моя настройка такова:
override func viewDidLoad() {
super.viewDidLoad()
// create a new scene
let scene = SCNScene()
// create and add a camera to the scene
let cameraNode = SCNNode()
let camera = SCNCamera()
cameraNode.camera = camera
scene.rootNode.addChildNode(cameraNode)
// place the camera
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
// create and add an ambient light to the scene
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light.type = SCNLightTypeAmbient
ambientLightNode.light.color = UIColor.darkGrayColor()
scene.rootNode.addChildNode(ambientLightNode)
let triangleNode = SCNNode()
triangleNode.geometry = defineTriangle();
scene.rootNode.addChildNode(triangleNode)
// retrieve the SCNView
let scnView = self.view as SCNView
// set the scene to the view
scnView.scene = scene
// configure the view
scnView.backgroundColor = UIColor.blackColor()
// add a tap gesture recognizer
let tapGesture = UITapGestureRecognizer(target: self, action: "handleTap:")
let gestureRecognizers = NSMutableArray()
gestureRecognizers.addObject(tapGesture)
scnView.gestureRecognizers = gestureRecognizers
}
func handleTap(gestureRecognize: UIGestureRecognizer) {
// retrieve the SCNView
let scnView = self.view as SCNView
// check what nodes are tapped
let p = gestureRecognize.locationInView(scnView)
// get the camera
var camera = scnView.pointOfView.camera
// screenZ is percentage between z near and far
var screenZ = Float((15.0 - camera.zNear) / (camera.zFar - camera.zNear))
var scenePoint = scnView.unprojectPoint(SCNVector3Make(Float(p.x), Float(p.y), screenZ))
println("tapPoint: (\(p.x), \(p.y)) scenePoint: (\(scenePoint.x), \(scenePoint.y), \(scenePoint.z))")
}
func defineTriangle() -> SCNGeometry {
// Vertices
var vertices:[SCNVector3] = [
SCNVector3Make(-2.0, -2.0, 0.0),
SCNVector3Make(2.0, -2.0, 0.0),
SCNVector3Make(0.0, 2.0, 0.0)
]
let vertexData = NSData(bytes: vertices, length: vertices.count * sizeof(SCNVector3))
var vertexSource = SCNGeometrySource(data: vertexData,
semantic: SCNGeometrySourceSemanticVertex,
vectorCount: vertices.count,
floatComponents: true,
componentsPerVector: 3,
bytesPerComponent: sizeof(Float),
dataOffset: 0,
dataStride: sizeof(SCNVector3))
// Normals
var normals:[SCNVector3] = [
SCNVector3Make(0.0, 0.0, 1.0),
SCNVector3Make(0.0, 0.0, 1.0),
SCNVector3Make(0.0, 0.0, 1.0)
]
let normalData = NSData(bytes: normals, length: normals.count * sizeof(SCNVector3))
var normalSource = SCNGeometrySource(data: normalData,
semantic: SCNGeometrySourceSemanticNormal,
vectorCount: normals.count,
floatComponents: true,
componentsPerVector: 3,
bytesPerComponent: sizeof(Float),
dataOffset: 0,
dataStride: sizeof(SCNVector3))
// Indexes
var indices:[CInt] = [0, 1, 2]
var indexData = NSData(bytes: indices, length: sizeof(CInt) * indices.count)
var indexElement = SCNGeometryElement(
data: indexData,
primitiveType: .Triangles,
primitiveCount: 1,
bytesPerIndex: sizeof(CInt)
)
var geo = SCNGeometry(sources: [vertexSource, normalSource], elements: [indexElement])
// material
var material = SCNMaterial()
material.diffuse.contents = UIColor.redColor()
material.doubleSided = true
material.shininess = 1.0;
geo.materials = [material];
return geo
}
Как вы можете видеть. У меня есть треугольник, который составляет 4 единицы на 4 единицы по ширине и установлен на плоскости z (z = 0) с центром в x, y (0.0, 0.0). Камера является SCNCamera по умолчанию, которая смотрит в направлении отрицательного z, и я разместил ее на (0, 0, 15). Значение по умолчанию для zNear и zFar равно 1.0 и 100.0 соответственно. В моем методе handleTap я беру координаты экрана x и y крана и пытаюсь найти координаты глобальной сцены x и y, где z = 0.0. Я использую вызов unprojectPoint.
Документы для unprojectPoint указывают
Непроектируя точку, z-координата которой равна 0.0, возвращает точку на вблизи плоскости отсечения; непроектируя точку, z-координата которой равна 1,0 возвращает точку на далекой плоскости отсечения.
Хотя конкретно не говорится, что для точек между ними существует связь между ближайшей и дальней плоскостью, я сделал это предположение и вычислил значение screenZ как процентное расстояние между ближней и дальней плоскостью, плоскость z = 0. Чтобы проверить мой ответ, я могу щелкнуть по углам треугольника, потому что знаю, где они находятся в глобальных координатах.
Моя проблема в том, что я не получаю правильные значения, и я не получаю согласованные значения, когда начинаю менять плоскости отсечения zNear и zFar на камере. Итак, мой вопрос: как я могу это сделать? В конце концов, я собираюсь создать новую часть геометрии и поместить ее на z-плоскость, соответствующую тому, где пользователь нажал.
Заранее благодарим за помощь.