我使用 SK3DNode 在屏幕上显示一些 3D 模型文件。它们的尺寸不同,但我想在屏幕上显示它们或多或少相同的尺寸。
我有以下代码:
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
cameraNode.constraints = [SCNLookAtConstraint(target: model)]
// TODO: adjust position so that it takes 90% of the viewport size.
cameraNode.position = VEC3(0, 0, 4)
return node3D
}
}
我已经完成了以下操作(假设我想要 90% 的大小):
let planeX = model.boundingSize.x / 0.9
let planeY = model.boundingSize.y / 0.9
let planeLength = max(planeX, planeY)
let angleInRadian = NumberUtil.degreeToRadian(degree: camera.fieldOfView)
let distance = planeLength / 2 / tan(angleInRadian/2)
我根据这个答案中的图片得到了上述计算:基于模型尺寸的相机位置?
这似乎很接近我想要的,但它在计算时没有考虑视口的大小和长宽比,所以我认为它不正确。有没有更好的方法来计算这个?
在计算从相机到模型的距离时,您需要考虑 3D 模型的深度,否则将计算从模型中心(或原点)到相机的距离,这样就可以解决所有问题。
// get the boundingBox aka maximun size of X Y Z of the model
let planeX = model.boundingBox.max.x
let planeY = model.boundingBox.max.y
// you need planZ to get the depth of the 3d model for accurate
// distance calculation
let planeZ = model.boundingBox.max.z
let planeLength = max(planeX, planeY)
// to convert to radian you can multiply the angle to (.pi/180)
let angleInRadian = cameraNode.camera!.fieldOfView * (.pi/180)
// this is the distance from the center of the 3d model to the camera
let distance = planeLength / 2 / tan(angleInRadian/2)
// you have to add half the depth of the 3d model to it
let actualDistance = distance + (planeZ/2)
cameraNode.position = SCNVector3(x: 0, y: 0, z: actualDistance)