SceneKit + ARKit:不用相机滚动的广告牌
SceneKit + ARKit: Billboarding without rolling with camera
我正在尝试使用 SceneKit 和 ARKit 绘制广告牌四边形。我有基本的广告牌工作,但是当我转动相机时,广告牌也会原地旋转。该视频展示了我将相机向左滚动时的实际效果(笑脸是广告牌):
相反,我希望广告牌仍然面向相机,但在场景中保持垂直方向,无论相机在做什么
这是我计算广告牌的方法:
// inside frame update function
struct Vertex {
var position: SIMD3<Float>
var texCoord: SIMD2<Float>
}
let halfSize = Float(0.25)
let cameraNode = sceneView.scene.rootNode.childNodes.first!
let modelTransform = self.scnNode.simdWorldTransform
let viewTransform = cameraNode.simdWorldTransform.inverse
let modelViewTransform = viewTransform * modelTransform
let right = SIMD3<Float>(modelViewTransform[0][0], modelViewTransform[1][0], modelViewTransform[2][0]);
let up = SIMD3<Float>(modelViewTransform[0][1], modelViewTransform[1][1], modelViewTransform[2][1]);
// drawBuffer is a MTL buffer of vertex data
let data = drawBuffer.contents().bindMemory(to: ParticleVertex.self, capacity: 4)
data[0].position = (right + up) * halfSize
data[0].texCoord = SIMD2<Float>(0, 0)
data[1].position = -(right - up) * halfSize
data[1].texCoord = SIMD2<Float>(1, 0)
data[2].position = (right - up) * halfSize
data[2].texCoord = SIMD2<Float>(0, 1)
data[3].position = -(right + up) * halfSize
data[3].texCoord = SIMD2<Float>(1, 1)
这再次使广告牌正确面向相机,但是当我转动相机时,广告牌会随之旋转。
我想要的是让广告牌指向相机但保持其在世界中的方向。关于如何解决这个问题有什么建议吗?
请注意,我的代码示例已简化,因此我不能使用 SCNBillboardConstraint
或类似的东西;我需要能够自己计算广告牌
这是我想出的解决方案:创建一个与相机的位置和旋转相匹配的新节点,但没有任何滚动:
let tempNode = SCNNode()
tempNode.simdWorldPosition = cameraNode.simdWorldPosition
// This changes the node's pitch and yaw, but not roll
tempNode.simdLook(at: cameraNode.simdConvertPosition(SIMD3<Float>(0, 0, 1), to: nil))
let view = tempNode.simdWorldTransform.inverse
let modelViewTransform = view * node.simdWorldTransform
这使广告牌在世界 space 中保持向上,即使相机滚动也是如此。
实际上我早些时候曾尝试通过设置 tempNode.eulerAngles.z = 0
来做到这一点,但这似乎以意想不到的方式影响了变换矩阵的其余部分
可能有一种方法可以在不创建临时节点的情况下执行此操作,但这对我来说效果很好
我正在尝试使用 SceneKit 和 ARKit 绘制广告牌四边形。我有基本的广告牌工作,但是当我转动相机时,广告牌也会原地旋转。该视频展示了我将相机向左滚动时的实际效果(笑脸是广告牌):
相反,我希望广告牌仍然面向相机,但在场景中保持垂直方向,无论相机在做什么
这是我计算广告牌的方法:
// inside frame update function
struct Vertex {
var position: SIMD3<Float>
var texCoord: SIMD2<Float>
}
let halfSize = Float(0.25)
let cameraNode = sceneView.scene.rootNode.childNodes.first!
let modelTransform = self.scnNode.simdWorldTransform
let viewTransform = cameraNode.simdWorldTransform.inverse
let modelViewTransform = viewTransform * modelTransform
let right = SIMD3<Float>(modelViewTransform[0][0], modelViewTransform[1][0], modelViewTransform[2][0]);
let up = SIMD3<Float>(modelViewTransform[0][1], modelViewTransform[1][1], modelViewTransform[2][1]);
// drawBuffer is a MTL buffer of vertex data
let data = drawBuffer.contents().bindMemory(to: ParticleVertex.self, capacity: 4)
data[0].position = (right + up) * halfSize
data[0].texCoord = SIMD2<Float>(0, 0)
data[1].position = -(right - up) * halfSize
data[1].texCoord = SIMD2<Float>(1, 0)
data[2].position = (right - up) * halfSize
data[2].texCoord = SIMD2<Float>(0, 1)
data[3].position = -(right + up) * halfSize
data[3].texCoord = SIMD2<Float>(1, 1)
这再次使广告牌正确面向相机,但是当我转动相机时,广告牌会随之旋转。
我想要的是让广告牌指向相机但保持其在世界中的方向。关于如何解决这个问题有什么建议吗?
请注意,我的代码示例已简化,因此我不能使用 SCNBillboardConstraint
或类似的东西;我需要能够自己计算广告牌
这是我想出的解决方案:创建一个与相机的位置和旋转相匹配的新节点,但没有任何滚动:
let tempNode = SCNNode()
tempNode.simdWorldPosition = cameraNode.simdWorldPosition
// This changes the node's pitch and yaw, but not roll
tempNode.simdLook(at: cameraNode.simdConvertPosition(SIMD3<Float>(0, 0, 1), to: nil))
let view = tempNode.simdWorldTransform.inverse
let modelViewTransform = view * node.simdWorldTransform
这使广告牌在世界 space 中保持向上,即使相机滚动也是如此。
实际上我早些时候曾尝试通过设置 tempNode.eulerAngles.z = 0
来做到这一点,但这似乎以意想不到的方式影响了变换矩阵的其余部分
可能有一种方法可以在不创建临时节点的情况下执行此操作,但这对我来说效果很好