对 SceneKit 中相机的正交投影感到困惑

Posted

技术标签:

【中文标题】对 SceneKit 中相机的正交投影感到困惑【英文标题】:Confused about Orthographic Projection of camera in SceneKit 【发布时间】:2019-02-24 23:00:33 【问题描述】:

我想使用正交投影在我的应用中显示 3D 场景。在我的代码中,我在场景中放置了一个框,并设置了视点的正交投影,如打击。 (0,0,500) 处的相机看 -z 方向,并在世界的原点框。所以相机应该能够捕捉到盒子。

let cameraNode = SCNNode()
let pov = SCNCamera()
pov.usesOrthographicProjection = true
let width = UISreen.main.bounds.size.width
let glMat = GLKMatrix4MakeOrtho(-width/2, width/2, -width/2, width/2, 1, 1000)
pov.projectionTransform = SCNMatrix4FromGLKMatrix4(glMat)
cameraNode.camera = pov
cameraNode.position = SCNVector3.init(0, 0, 500)
scene.rootNode.addChildNode(cameraNode)

let boxGeo = SCNBox.init(width: 100, height: 100, length: 1, chamferRadius: 0)
let box = SCNNode.init(geometry: boxGeo)
scene.rootNode.addChildNode(box)

但我什么也看不见。我发现如果将orthographicScale 设置为width/2.0 将正常工作。

pov.orthographicScale = Double(width/2);

问题 1:我不知道为什么会这样。我阅读了苹果的文档,但仍然感到困惑。 https://developer.apple.com/documentation/scenekit/scncamera/1436612-orthographicscale?language=objc

正交比例

在使用正交投影时指定相机的放大系数。

为什么需要放大正交投影?我已经通过GLKMatrix4MakeOrtho设置了它的尺寸。

我不确定它是否与视口变换有关?因为 OpenGL 中的视口变换计算如下:https://docs.microsoft.com/en-us/windows/desktop/opengl/glviewport

问题 2: 我还发现如果我创建像 Blow 这样的投影矩阵,它的工作原理与以前相同。

let glMat = GLKMatrix4MakeOrtho(0, width, 0, width, 1, 1000)

在OpenGL中表示不同的观察框,会显示不同的场景分区。

感谢任何帮助!

【问题讨论】:

你的相机在哪里看?你设置视口了吗? 相机看-z方向。我没有在 SceneKit 中明确设置视口。 【参考方案1】:

我想,你不能使用GLKMatrix4MakeOrtho 在场景中看到你的 3D 对象,因为现在很多用于 ios 和 macOS 的 GLKit 类已被弃用。

为了看到您的 3D 对象,您需要在 Attributes Inspector 中手动设置 Far Z Clipping 参数。这两个字段是正交相机截头体的 nearfar 剪切平面。默认值 Far=100 不允许您看到 100 单位以外的场景。

然后使用Scale 属性为正交视图中的对象设置比例因子。

为了通过GLKMatrix4MakeOrtho 以编程方式使用它,您首先需要将GLKitOpenGL 模块(以及所有必要的委托协议)导入到您的项目中。

import GLKit
import OpenGL

// Obj-C GLKMatrix4

GLK_INLINE GLKMatrix4 GLKMatrix4MakeOrtho(float left, 
                                          float right,
                                          float bottom, 
                                          float top,
                                          float nearZ, 
                                          float farZ) 
    float ral = right + left;
    float rsl = right - left;
    float tab = top + bottom;
    float tsb = top - bottom;
    float fan = farZ + nearZ;
    float fsn = farZ - nearZ;

    GLKMatrix4 m =  2.0f / rsl, 0.0f, 0.0f, 0.0f,
                     0.0f, 2.0f / tsb, 0.0f, 0.0f,
                     0.0f, 0.0f, -2.0f / fsn, 0.0f,
                     -ral / rsl, -tab / tsb, -fan / fsn, 1.0f ;

    return m;

此外,在 iOS 上,GLKit 需要 OpenGL ES 2.0 上下文。在 macOS 中,GLKit 需要支持 OpenGL 3.2 Core Profile 的 OpenGL 上下文。

但请记住!许多 GL 功能已被弃用,因此您最好使用 Metal 框架。 Look at deprecated classes of GLKit.

【讨论】:

是的,它有效。那么正交投影的zNear和zFar与相机的zNear和zFar没有关系? 在相机上设置 zNear 和 zFar 是相机如何计算自己的透视投影矩阵的一部分。如果您使用的是正射投影,剪裁距离是您自己计算的矩阵的一部分。 @AndyFedoroff 嗨,你能看看我的 ARKit 相关问题***.com/questions/62783206/… 吗?感谢您的宝贵时间! 嗨@swiftlearneer!我不擅长金属,但我会尝试。 嗨@AndyFedoroff!感谢您的答复!我只是想知道我的帖子可能有点混乱。我已经在 GitHub 上发布了代码。所以这种方式对于我的问题可能更容易理解:github.com/andrewcccc/Ftrack/tree/master/FaceCapturedata-master?

以上是关于对 SceneKit 中相机的正交投影感到困惑的主要内容,如果未能解决你的问题,请参考以下文章

three.js正交投影照相机

使用 OpenGL 进行正交投影以及如何实现相机或物体在空间中的移动

Unity3D Camera透视相机到正交相机插值

《Three.js 入门指南》2.3.1- 照相机 - 正交投影demo

使用几何的正交投影被远平面剪裁

opengl中的正交投影和纹理坐标