You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

SceneKit正交投影相机初始视图配置问题咨询

解决SceneKit正交投影下初始视图完整显示物体的问题

我明白你在SceneKit里切换到正交投影后遇到的麻烦——调整相机位置完全没效果,没法让飞船一开始就完整显示在视图里。这是因为正交投影和透视投影的工作逻辑完全不一样,咱们一步步来搞定这个问题:

为什么调整相机位置没用?

透视投影里,相机的z轴位置直接影响物体的视觉大小(远小近大),但在正交投影里,物体的大小和相机距离无关——不管相机离得远还是近,物体看起来都是一样大。真正控制可见范围的是相机的orthographicScale属性,而不是位置,所以你之前改position自然没效果。

正确的配置步骤

我们需要通过计算物体的包围盒尺寸,配合视图的宽高比,设置合适的orthographicScale,再把相机放到能覆盖物体的位置:

1. 开启正交投影

先确认已经开启正交投影:

cameraNode.camera?.usesOrthographicProjection = true

2. 计算物体的包围盒尺寸

先获取飞船的包围盒,算出它在x、y、z三个轴上的大小:

let minBounds = ship.boundingBox.min
let maxBounds = ship.boundingBox.max
let objectSize = SCNVector3(
    maxBounds.x - minBounds.x,
    maxBounds.y - minBounds.y,
    maxBounds.z - minBounds.z
)

3. 计算合适的orthographicScale

为了让物体刚好适配视图且不拉伸,需要结合视图的宽高比来计算:

let viewAspect = Float(sceneView.bounds.width / sceneView.bounds.height)
// 取x轴宽度和y轴宽度(适配视图比例)中的较大值,确保物体能完整显示
let maxVisibleDimension = max(objectSize.x, objectSize.y / viewAspect)
// orthographicScale是视锥体半宽,所以除以2
cameraNode.camera?.orthographicScale = maxVisibleDimension / 2

4. 设置相机位置

正交投影下,相机的z轴位置只要保证在物体的前方(比物体的最大z值大一点,确保物体在视锥体内)就行,同时让相机的x、y轴和物体中心对齐:

// 计算物体中心
let objectCenter = SCNVector3(
    (minBounds.x + maxBounds.x)/2,
    (minBounds.y + maxBounds.y)/2,
    (minBounds.z + maxBounds.z)/2
)
// 把相机放在物体中心的正前方,z轴偏移1个单位(只要在物体前面就行)
cameraNode.position = SCNVector3(objectCenter.x, objectCenter.y, maxBounds.z + 1)

5. 让相机始终看向物体(可选但推荐)

为了确保相机视角正确,给相机添加一个看向飞船的约束:

let lookAtConstraint = SCNLookAtConstraint(target: ship)
lookAtConstraint.isGimbalLockEnabled = true // 避免不必要的旋转
cameraNode.constraints = [lookAtConstraint]

关于GLKMatrix4MakeOrtho的说明

你之前尝试用这个方法自定义投影矩阵没效果,大概率是因为没有正确匹配视锥体的参数,或者覆盖了SceneKit的默认设置。其实SceneKit的orthographicScale已经封装了正交投影矩阵的计算,直接用这个属性会更简单,除非你需要非常自定义的视锥体范围(比如非对称的裁剪平面)。

额外注意点

如果你的视图会发生大小变化(比如屏幕旋转),记得在viewDidLayoutSubviews里重新计算orthographicScale,不然物体可能会被裁切或者显示不全。

内容的提问来源于stack exchange,提问作者Eddie

火山引擎 最新活动