SCNNode 边界框在 SceneKit 中缩放或旋转后未更新

问题描述 投票:0回答:1

我有这个代码:

    let box = SCNBox(width: 1, height: 2, length: 4, chamferRadius: 0.2)
    box.firstMaterial?.diffuse.contents = UIColor.yellow
    box.firstMaterial?.emission.contents = UIColor.green
    let boxNode = SCNNode(geometry: box)
    print(boxNode.boundingBox)
    boxNode.eulerAngles = SCNVector3(0.785, 0.5, 0.5)
    print(boxNode.boundingBox)
    boxNode.scale = SCNVector3(1.3, 2.3, 3.3)
    print(boxNode.boundingBox)
    scene.rootNode.addChildNode(boxNode)

我得到了这个:

(min: __C.SCNVector3(x: -0.5, y: -1.0, z: -2.0), max: __C.SCNVector3(x: 0.5, y: 1.0, z: 2.0))
(min: __C.SCNVector3(x: -0.5, y: -1.0, z: -2.0), max: __C.SCNVector3(x: 0.5, y: 1.0, z: 2.0))
(min: __C.SCNVector3(x: -0.5, y: -1.0, z: -2.0), max: __C.SCNVector3(x: 0.5, y: 1.0, z: 2.0))

事实证明,即使在应用旋转或缩放之后,边界框也没有更新。这与 SpriteKit 的行为不同。我想知道如何获得更新的边界框?

ios swift scenekit
1个回答
0
投票

发生这种情况是因为

boxNode.boundingBox
返回的边界框值代表 SCNNode
局部边界框
(当您最初创建几何图形时),它不会自动考虑诸如
rotation
 等变换scaling
translation
应用于节点。

要获取世界空间中的实际边界框尺寸,您需要应用转换来获取世界坐标中的边界框,如果我正确理解您的问题,这就是您所期望的:

添加这个新功能:

func getWorldSpaceBoundingBox(of node: SCNNode) -> (min: SCNVector3, max: SCNVector3) {
    let (min, max) = node.boundingBox
    let corners = [
        SCNVector3(min.x, min.y, min.z),
        SCNVector3(max.x, min.y, min.z),
        SCNVector3(min.x, max.y, min.z),
        SCNVector3(max.x, max.y, min.z),
        SCNVector3(min.x, min.y, max.z),
        SCNVector3(max.x, min.y, max.z),
        SCNVector3(min.x, max.y, max.z),
        SCNVector3(max.x, max.y, max.z)
    ]

    // Transform each corner to world space
    let transformedCorners = corners.map { node.convertPosition($0, to: nil) }
    
    // Initialize min and max points
    var worldMin = transformedCorners[0]
    var worldMax = transformedCorners[0]
    
    // Find min and max points among transformed corners
    for corner in transformedCorners {
        worldMin = SCNVector3(
            x: Swift.min(worldMin.x, corner.x),
            y: Swift.min(worldMin.y, corner.y),
            z: Swift.min(worldMin.z, corner.z)
        )
        worldMax = SCNVector3(
            x: Swift.max(worldMax.x, corner.x),
            y: Swift.max(worldMax.y, corner.y),
            z: Swift.max(worldMax.z, corner.z)
        )
    }
    
    return (min: worldMin, max: worldMax)
}

然后您可以像这样使用示例框设置:

func testBox() {
    let box = SCNBox(width: 1.0, height: 2.0, length: 4.0, chamferRadius: 0.2)
    box.firstMaterial?.diffuse.contents = UIColor.yellow
    box.firstMaterial?.emission.contents = UIColor.green
    let boxNode = SCNNode(geometry: box)
    sceneView.scene?.rootNode.addChildNode(boxNode)
    
    print("Original bounding box (local):", boxNode.boundingBox)
    
    // Apply transformations
    boxNode.eulerAngles = SCNVector3(0.785, 0.5, 0.5)
    boxNode.scale = SCNVector3(1.3, 2.3, 3.3)
    
    // Get transformed bounding box in world space
    let worldBoundingBox = getWorldSpaceBoundingBox(of: boxNode)
    print("Transformed bounding box (world):", worldBoundingBox)
}

这是调试器的打印输出:

原始边界框(局部):(最小值:__C.SCNVector3(x:-0.5,y:-1.0,z:-2.0),最大值:__C.SCNVector3(x:0.5,y:1.0,z:2.0) )

变换后的边界框(世界):(最小值:__C.SCNVector3(x:-4.7974877,y:-5.0958166,z:-5.835535),最大值:__C.SCNVector3(x:4.7974877,y:5.0958166,z:5.835535) )

© www.soinside.com 2019 - 2024. All rights reserved.