這是一個比乍看起來更復雜的問題。
SceneKit將以原始比例/基礎存儲用於生成節點的幾何體座標。這些對象一旦創建就不會改變。對於像SCNPlane
或SCNBox
這樣的圖元,這些幾何圖形將在場景中共享。所以如果你有一堆不同的平面或者盒子,都在不同的位置,旋轉和縮放,當你查詢SCNGeometrySource
時,你會得到相同的頂點。這裏有一個很好的討論:Extracting vertices from scenekit。但是,這種方法不會給你在你的本地座標空間的角落。
我們有上SCNNode
和SCNGeometry
工作兩個功能:boundingBox
和boundingSphere
(他們在協議SCNBoundingVolume
定義)。 boundingBox
給你兩點,最小值和最大值。從立方體的兩個相對角落,您可以計算出您飛機的角落頂點。不過,還有另一個複雜因素。這兩個函數都以局部座標(節點本身使用的座標系)返回答案。所以我們仍然堅持:我的每一架飛機或箱子都會有相同的邊界框。
我想出的答案是使用SCNNode的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上易於摘要概述的文章中,有一個很好的解釋。
我把這個問題搜索了一遍,看了很多堆棧溢出的問題,但他們沒有解釋scnmatrix是什麼意思。這篇文章可能聽起來像我還沒有讀過關於scenekit的任何內容,因爲英語不是我的第一語言,很難用英語來形容一些東西。 – Asphys
從這個問題和另一個關於飛機頂點的問題,我仍然不明白你想看到什麼效果。你能畫一張粗略的鉛筆素描並上傳嗎? –
@HalMueller我認爲他是在創建他的平面物體的每個頂點的場景座標之後。 – Confused