SceneKit+ARKit 实现广告牌效果时避免随相机滚转旋转的问题咨询
问题根源
你当前的实现是完全对齐相机坐标系的全视角广告牌,会同步响应相机的滚转(Roll)动作。你需要的是轴向锁定的广告牌,固定垂直方向为世界空间的全局向上方向,不受相机滚转影响。
实现逻辑
- 固定全局垂直向上方向为
SIMD3<Float>(0, 1, 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 worldUp = SIMD3<Float>(0, 1, 0) // 取广告牌和相机的世界位置 let billboardPos = self.scnNode.simdWorldTransform.position let cameraPos = cameraNode.simdWorldTransform.position // 计算广告牌指向相机的前方向向量 let forward = normalize(cameraPos - billboardPos) // 推导广告牌右方向 let right = normalize(cross(worldUp, forward)) // 推导修正后的广告牌上方向,和全局上方向对齐 let up = cross(forward, right) // 计算四个顶点的世界位置 let data = drawBuffer.contents().bindMemory(to: ParticleVertex.self, capacity: 4) data[0].position = billboardPos + (right + up) * halfSize data[0].texCoord = SIMD2<Float>(0, 0) data[1].position = billboardPos + (-right + up) * halfSize data[1].texCoord = SIMD2<Float>(1, 0) data[2].position = billboardPos + (right - up) * halfSize data[2].texCoord = SIMD2<Float>(0, 1) data[3].position = billboardPos + (-right - up) * halfSize data[3].texCoord = SIMD2<Float>(1, 1)
补充说明
如果你的场景用的不是Y轴作为垂直向上方向,修改worldUp的取值即可适配。如果需要相对广告牌父节点的局部空间垂直固定,把worldUp转换为父节点的局部空间坐标即可。
内容的提问来源于stack exchange,提问作者Matt Bierner
相关产品推荐
相关产品推荐

