我有一个以编程方式创建的平面,我想获得该平面所具有的一个顶点的坐标。像这样:print(Plane.vertices[1].position)
它可能会打印如下:(x:1,y:1)和print(Plane.vertices[2].position)
打印(x - 1,y:1)
let positions = [SCNVector3Make( 0, -0.1, 0),
SCNVector3Make( 0.3, -0.1, 0),
SCNVector3Make( 0, 0.1, 0),
SCNVector3Make( 0.3, 0.1, 0),
]
let indices :[UInt16] = [
0, 1, 2,
1, 3, 2,
]
let vertexSource = SCNGeometrySource(vertices: positions, count: 4)
let indexData = NSData(bytes: indices, length: MemoryLayout<CInt>.size * indices.count)
let newElement = SCNGeometryElement(data: NSData(bytes: indices, length: indices.count * MemoryLayout<Int16>.size) as Data, primitiveType: .triangles , primitiveCount: 2, bytesPerIndex: MemoryLayout<Int16>.size)
let geometry = SCNGeometry(sources: [vertexSource], elements: [newElement])
custom = SCNNode(geometry: geometry)
scene.rootNode.addChildNode(custom!)
custom?.position = SCNVector3Make(0, 0, 0)
我认为这可以通过变换以某种方式完成,但是自定义变换有很多奇怪的东西,比如m11,m12,m13,我不明白。
答案 0 :(得分:6)
这是一个比初看起来更复杂的问题。
SceneKit将存储用于以原始比例/基础生成节点的几何体的坐标。一旦创建了对象,那些就不会改变。对于SCNPlane
或SCNBox
等基元,这些几何在场景中共享。因此,如果您有一堆不同的平面或方框,所有位于不同的位置,旋转和缩放,当您查询SCNGeometrySource
时,您将获得相同的顶点。这里有一个关于该检索的很好的讨论:Extracting vertices from scenekit。但是这种方法不会给你当地坐标空间的角落。
我们有两个适用于SCNNode
和SCNGeometry
的功能:boundingBox
和boundingSphere
(它们在协议SCNBoundingVolume
中定义)。 boundingBox
为您提供两点,最小值和最大值。从立方体的两个相对角,您可以找出平面的角顶点。但是,还有另一个复杂因素。这两个函数都在本地坐标(节点本身使用的坐标系)中返回它们的答案。所以我们仍然陷入困境:我的每一架飞机或箱子都有相同的边界框。
我想出的答案是使用SCNNode&#39; convertPosition(_, to: node)
,传递场景的根节点。这最终给了我在根节点的坐标空间中的边界框。
for node in [custom1, custom2, plainPlane1, plainPlane2] {
print(node.name!)
print(node.boundingBox.max)
print(node.boundingBox.min)
print(node.convertPosition(node.boundingBox.min, to: scene.rootNode))
print(node.convertPosition(node.boundingBox.max, to: scene.rootNode))
}
制造
custom 1 SCNVector3(x: 0.300000011920929, y: 0.100000001490116, z: 0.0) SCNVector3(x: 0.0, y: -0.100000001490116, z: 0.0) SCNVector3(x: 0.0, y: -0.100000001490116, z: -1.0) SCNVector3(x: 0.300000011920929, y: 0.100000001490116, z: -1.0) custom 2 SCNVector3(x: 0.300000011920929, y: 0.100000001490116, z: 0.0) SCNVector3(x: 0.0, y: -0.100000001490116, z: 0.0) SCNVector3(x: 0.200000002980232, y: 0.429289322037836, z: -1.07071067796216) SCNVector3(x: 0.500000014901161, y: 0.570710677962164, z: -0.929289322037836) plain plane 1 SCNVector3(x: 0.5, y: 1.0, z: 0.0) SCNVector3(x: -0.5, y: -1.0, z: 0.0) SCNVector3(x: -0.5, y: -1.0, z: -2.0) SCNVector3(x: 0.5, y: 1.0, z: -2.0) plain plane 2 SCNVector3(x: 0.5, y: 1.0, z: 0.0) SCNVector3(x: -0.5, y: -1.0, z: 0.0) SCNVector3(x: -9.18485139438876e-18, y: -0.300000011920929, z: -1.84999999403954) SCNVector3(x: 9.18485139438876e-18, y: 0.300000011920929, z: -2.15000000596046)
以下是完整的macOS游乐场:
//: Playground - noun: a place where people can play import Cocoa import SceneKit import PlaygroundSupport let positions = [SCNVector3Make( 0, -0.1, 0), SCNVector3Make( 0.3, -0.1, 0), SCNVector3Make( 0, 0.1, 0), SCNVector3Make( 0.3, 0.1, 0), ] let indices :[UInt16] = [ 0, 1, 2, 1, 3, 2, ] let vertexSource = SCNGeometrySource(vertices: positions, count: 4) let indexData = NSData(bytes: indices, length: MemoryLayout.size * indices.count) let newElement = SCNGeometryElement(data: NSData(bytes: indices, length: indices.count * MemoryLayout.size) as Data, primitiveType: .triangles , primitiveCount: 2, bytesPerIndex: MemoryLayout.size) let sceneView = SCNView(frame: CGRect(x: 0, y: 0, width: 600, height: 400)) sceneView.allowsCameraControl = true sceneView.autoenablesDefaultLighting = true sceneView.backgroundColor = NSColor.darkGray sceneView.showsStatistics = true PlaygroundPage.current.liveView = sceneView let scene = SCNScene() sceneView.scene = scene let geometry = SCNGeometry(sources: [vertexSource], elements: [newElement]) geometry.firstMaterial?.diffuse.contents = NSColor.red geometry.firstMaterial?.isDoubleSided = true let custom1 = SCNNode(geometry: geometry) custom1.position = SCNVector3Make(0, 0, -1) custom1.name = "custom 1" scene.rootNode.addChildNode(custom1) let custom2 = SCNNode(geometry: geometry) custom2.position = SCNVector3Make(0.2, 0.5, -1) custom2.rotation = SCNVector4Make(1, 0, 0, CGFloat(M_PI_4)) custom2.name = "custom 2" scene.rootNode.addChildNode(custom2) let plainPlaneGeometry = SCNPlane(width: 1, height: 2) plainPlaneGeometry.firstMaterial?.diffuse.contents = NSColor.yellow plainPlaneGeometry.firstMaterial?.isDoubleSided = true let plainPlane1 = SCNNode(geometry: plainPlaneGeometry) plainPlane1.position = SCNVector3Make(0, 0, -2) plainPlane1.name = "plain plane 1" scene.rootNode.addChildNode(plainPlane1) let plainPlane2 = SCNNode(geometry: plainPlaneGeometry) plainPlane2.position = SCNVector3Make(0, 0, -2) plainPlane2.rotation = SCNVector4Make(0, 1, 0, CGFloat(M_PI_2)) plainPlane2.scale = SCNVector3Make(0.3, 0.3, 0.3) plainPlane2.name = "plain plane 2" scene.rootNode.addChildNode(plainPlane2) for node in [custom1, custom2, plainPlane1, plainPlane2] { print(node.name!) print(node.boundingBox.max) print(node.boundingBox.min) // print(node.transform) print(node.convertPosition(node.boundingBox.min, to: scene.rootNode)) print(node.convertPosition(node.boundingBox.max, to: scene.rootNode)) }
您提到了转换矩阵。在Need better and simpler understanding of CATransform3D处可以很好地解释它的外观及其工作方式(引用两篇优秀的维基百科文章),以及http://sketchytech.blogspot.com/2014/12/explaining-catransform3d-matrix.html上易于理解的概述。