如何调整SK3DNode内相机位置,使3D模型居中适配视口
如何调整SK3DNode内相机位置,使3D模型居中适配视口
我完全懂你的需求——就是要让3D模型不管在宽屏还是竖屏的SK3DNode视口里,都能完整、居中地显示出来,对吧?你之前的计算思路是对的,但确实没把视口的宽高比考虑进去,这就会导致在不同比例的视口里,模型要么超出范围要么留太多空白。我来帮你完善这个逻辑。
问题核心
相机的实际视野范围不仅由垂直FOV决定,还会被视口的宽高比影响。比如同样的垂直FOV,宽屏视口的水平视野会更宽。所以我们需要同时计算水平和垂直两个方向上,让模型完整显示所需的相机距离,然后取较大的那个距离,这样就能保证模型在两个维度都不会超出视口。
完整实现代码
我把调整后的逻辑整合到你的SK3DNode扩展里了,替换掉原来的TODO部分:
public extension SK3DNode { static func forModel(_ model: SCNNode, size: CGSize) -> SK3DNode { let scene = SCNScene() let node3D = SK3DNode() node3D.scnScene = scene node3D.viewportSize = size scene.rootNode.addChildNode(model) let camera = SCNCamera() let cameraNode = SCNNode() cameraNode.camera = camera node3D.pointOfView = cameraNode // 1. 获取模型的包围盒尺寸与中心(确保基于模型整体大小计算) let boundingBox = model.boundingBox let modelSize = SCNVector3( x: boundingBox.max.x - boundingBox.min.x, y: boundingBox.max.y - boundingBox.min.y, z: boundingBox.max.z - boundingBox.min.z ) let modelCenter = SCNVector3( x: (boundingBox.min.x + boundingBox.max.x) / 2, y: (boundingBox.min.y + boundingBox.max.y) / 2, z: (boundingBox.min.z + boundingBox.max.z) / 2 ) // 2. 计算视口的宽高比 let viewportAspect = size.width / size.height // 3. 计算相机所需的距离(同时考虑水平和垂直视野) let verticalFOV = camera.fieldOfView let verticalFOVRad = NumberUtil.degreeToRadian(degree: verticalFOV) // 根据视口宽高比推导水平FOV弧度 let horizontalFOVRad = 2 * atan(tan(verticalFOVRad / 2) * viewportAspect) // 分别计算垂直、水平方向完整显示模型所需的相机距离 let requiredVerticalDistance = (modelSize.y / 2) / tan(verticalFOVRad / 2) let requiredHorizontalDistance = (modelSize.x / 2) / tan(horizontalFOVRad / 2) // 取最大距离,确保模型在两个方向都能完整显示 var cameraDistance = max(requiredVerticalDistance, requiredHorizontalDistance) // 可选:如果需要容纳模型的深度(Z方向尺寸),可以加上深度的一半 cameraDistance += modelSize.z / 2 // 4. 设置相机位置与看向约束 cameraNode.position = SCNVector3(x: modelCenter.x, y: modelCenter.y, z: modelCenter.z + cameraDistance) let lookAtConstraint = SCNLookAtConstraint(target: model) lookAtConstraint.isGimbalLockEnabled = true // 避免相机旋转问题 cameraNode.constraints = [lookAtConstraint] return node3D } }
关键细节说明
- 包围盒与模型中心:用
model.boundingBox获取模型的完整包围盒,计算出实际尺寸和中心位置,确保相机是对着模型的中心,而不是默认原点。 - 视口宽高比适配:通过视口的宽高比推导相机的实际水平FOV,这样计算出来的距离会完全匹配当前视口的比例。
- 取最大距离:如果只按垂直方向计算,宽屏视口里模型的左右部分可能会超出;只按水平方向计算,竖屏视口里模型的上下部分可能会被切掉。取最大距离能保证两个方向都覆盖到。
- 深度适配(可选):如果你的模型有明显的Z方向厚度,可以把模型深度的一半加到相机距离上,这样模型的前后端都能完整显示在视口里。
这样调整后,不管你的SK3DNode是宽的还是竖的,3D模型都会完美居中适配,不会出现部分被截断或者留白过多的情况。
备注:内容来源于stack exchange,提问作者OMGPOP
相关产品推荐
相关产品推荐

