每个 SCNNode 都有一个 boundingBox 属性,即:
物体边界框的最小和最大角点。
所以这意味着:
Scene Kit 在局部坐标空间中定义了一个边界框,它使用两个点来标识其角,这隐含地确定了六个轴对齐的平面来标记其边界。例如,如果几何的边界框具有最小角 {-1, 0, 2} 和最大角 {3, 4, 5},则几何顶点数据中的所有点的 x 坐标值都在 -1.0 和 3.0 之间, 包括在内。
如果您在 SceneKit 编辑器中查看,您还可以看到模型的尺寸(以米为单位)(我只是说您可以参考这一点来检查计算):
在我的示例中,我使用的是上述尺寸的口袋妖怪模型。
我对模型进行了缩放(您可能也这样做了)例如:
pokemonModel.scale = SCNVector3(0.01, 0.01, 0.01)
所以为了得到SCNNode 的boundingBox,我们可以这样做:
/// Returns The Original Width & Height Of An SCNNode
///
/// - Parameter node: SCNNode
func getSizeOfModel(_ node: SCNNode){
//1. Get The Size Of The Node Without Scale
let (minVec, maxVec) = node.boundingBox
let unScaledHeight = maxVec.y - minVec.y
let unScaledWidth = maxVec.x - minVec.x
print("""
UnScaled Height = \(unScaledHeight)
UnScaled Width = \(unScaledWidth)
""")
}
这样称呼它:
getSizeOfModel(pokemonModel)
当然,既然我们的 SCNNode 已经被缩放,这并没有太大帮助,所以显然我们需要通过重写函数来考虑这一点:
/// Returns The Original & Scaled With & Height On An SCNNode
///
/// - Parameters:
/// - node: SCNode
/// - scalar: Float
func getOriginalAndScaledSizeOfNode(_ node: SCNNode, scalar: Float){
//1. Get The Size Of The Node Without Scale
let (minVec, maxVec) = node.boundingBox
let unScaledHeight = maxVec.y - minVec.y
let unScaledWidth = maxVec.x - minVec.x
print("""
UnScaled Height = \(unScaledHeight)
UnScaled Width = \(unScaledWidth)
""")
//2. Get The Size Of The Node With Scale
let max = node.boundingBox.max
let maxScale = SCNVector3(max.x * scalar, max.y * scalar, max.z * scalar)
let min = node.boundingBox.min
let minScale = SCNVector3(min.x * scalar, min.y * scalar, min.z * scalar)
let heightOfNodeScaled = maxScale.y - minScale.y
let widthOfNodeScaled = maxScale.x - minScale.x
print("""
Scaled Height = \(heightOfNodeScaled)
Scaled Width = \(widthOfNodeScaled)
""")
}
会这样称呼:
getOriginalAndScaledSizeOfNode(pokemonModel, scalar: 0.01)
完成此操作后,您说您想在模型上方放置一个“气泡”,然后可以这样做:
func getSizeOfNodeAndPositionBubble(_ node: SCNNode, scalar: Float){
//1. Get The Size Of The Node Without Scale
let (minVec, maxVec) = node.boundingBox
let unScaledHeight = maxVec.y - minVec.y
let unScaledWidth = maxVec.x - minVec.x
print("""
UnScaled Height = \(unScaledHeight)
UnScaled Width = \(unScaledWidth)
""")
//2. Get The Size Of The Node With Scale
let max = node.boundingBox.max
let maxScale = SCNVector3(max.x * scalar, max.y * scalar, max.z * scalar)
let min = node.boundingBox.min
let minScale = SCNVector3(min.x * scalar, min.y * scalar, min.z * scalar)
let heightOfNodeScaled = maxScale.y - minScale.y
let widthOfNodeScaled = maxScale.x - minScale.x
print("""
Scaled Height = \(heightOfNodeScaled)
Scaled Width = \(widthOfNodeScaled)
""")
//3. Create A Buubble
let pointNodeHolder = SCNNode()
let pointGeometry = SCNSphere(radius: 0.04)
pointGeometry.firstMaterial?.diffuse.contents = UIColor.cyan
pointNodeHolder.geometry = pointGeometry
//4. Place The Bubble At The Origin Of The Model, At The Models Origin + It's Height & At The Z Position
pointNodeHolder.position = SCNVector3(node.position.x, node.position.y + heightOfNodeScaled, node.position.z)
self.augmentedRealityView.scene.rootNode.addChildNode(pointNodeHolder)
}
这会产生以下结果(我也在其他一些不幸的口袋妖怪上进行了测试):
您可能还想在计算中添加一些“填充”,以便节点比模型顶部高一点,例如:
pointNodeHolder.position = SCNVector3(node.position.x, node.position.y + heightOfNodeScaled + 0.1, node.position.z)
我的数学不太好,它使用 SCNNode 作为气泡而不是 SKScene,但希望它会为您指明正确的方向...