SceneKit固定位置相机场景下如何在屏幕边缘精准定位碰撞墙体
SceneKit固定相机下屏幕边缘碰撞墙体坐标计算方案
你判断的问题原因准确:SceneKit使用3D世界单位(默认为米),直接用屏幕像素尺寸定位3D节点必然出现坐标偏移,需要通过视图投影转换将2D屏幕边界映射到球体滚动所在平面的3D坐标。
推荐方案:使用内置反投影API计算(零参数误差,适配所有相机配置)
不需要手动计算视场角、宽高比,直接调用SCNView的反投影方法,就能拿到屏幕边缘在指定3D平面上的精确坐标,适配透视/正交相机、任意相机位置/视场角参数。
你的球体和地面都在z=0平面,相机在z=100位置朝向z轴负方向,默认配置下远裁剪面正好落在z=0平面,直接按以下步骤计算:
- 获取当前SCNView的视图尺寸
- 取视图端口四个角的坐标(注意SceneKit视图端口原点在左下角,y轴向上,和UIKit坐标系y方向相反)
- 调用
unprojectPoint方法将2D屏幕点反投影到z=0平面,得到世界坐标
代码示例:
let viewSize = scnView.bounds.size // 视图端口四个角点,z分量取1对应远裁剪面(即z=0平面位置) let viewPortCorners: [SCNVector3] = [ SCNVector3(0, 0, 1), // 屏幕左下角 SCNVector3(viewSize.width, 0, 1), // 屏幕右下角 SCNVector3(viewSize.width, viewSize.height, 1), // 屏幕右上角 SCNVector3(0, viewSize.height, 1) // 屏幕左上角 ] // 反投影得到z=0平面上四个角的世界坐标 let worldCorners = viewPortCorners.map { scnView.unprojectPoint($0) }
拿到四个世界坐标点后,即可生成对应墙体:
- 左右墙体:使用
SCNBox几何体,厚度设为0.2(避免高速球体穿模),高度为上下角点的y轴差值,x坐标分别取左右角点的x值,y坐标取上下边界中点,z=0 - 上下墙体:使用
SCNBox几何体,厚度设为0.2,宽度为左右角点的x轴差值,y坐标分别取上下角点的y值,x坐标取左右边界中点,z=0 - 墙体材质透明度设为0即可实现不可见效果,物理体类型设为
SCNPhysicsBodyType.static,碰撞掩码配置为和球体物理体匹配即可实现反弹。
手动计算方案(仅适用于你当前固定相机配置)
你当前使用默认SCNCamera(透视投影,垂直视场角60度),相机到z=0平面的距离为100米,可通过三角学直接计算可见范围:
- 垂直方向半高:
halfHeight = tan(30 * Double.pi / 180) * 100 ≈ 57.74米,即y轴可见范围为-57.74 ~ 57.74 - 水平方向半宽:
halfWidth = halfHeight * (viewSize.width / viewSize.height),即x轴可见范围为-halfWidth ~ halfWidth
计算出的x/y边界和反投影API结果一致,但修改相机参数后需要重新计算,因此优先使用反投影方案。
注意:所有墙体必须放置在z=0平面,和球体滚动的地面深度保持一致,否则会出现球体滚动时提前碰撞或者穿出屏幕的问题。
内容的提问来源于stack exchange,提问作者West1
相关产品推荐
相关产品推荐

