I have this code:
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)
I got this:
(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))
It turn out that the bounding box is not updated, even after applying rotation or scaling. This is different from SpriteKit behavior. I am wondering how can I get the updated bounding box?
This occurs because the bounding-box values returned by boxNode.boundingBox
represent the local bounding box of the SCNNode
(as you initially created the geometry), which doesn’t automatically account for transformations such as rotation
, scaling
, or translation
applied to the node.
To get the actual bounding-box dimensions in world space, you need to apply transformations to get the bounding-box in world coordinates, which is what you expect, if I understood your question correctly:
Add this new function:
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)
}
You can then use your example box-setup like so:
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)
}
This are the print-outs from the debugger:
Original bounding box (local): (min: __C.SCNVector3(x: -0.5, y: -1.0, z: -2.0), max: __C.SCNVector3(x: 0.5, y: 1.0, z: 2.0))
Transformed bounding box (world): (min: __C.SCNVector3(x: -4.7974877, y: -5.0958166, z: -5.835535), max: __C.SCNVector3(x: 4.7974877, y: 5.0958166, z: 5.835535))