iOS 17.2与16.1下SceneKit命中测试结果异常求助(OpenGLES2/Metal)
iOS 17.2 SceneKit 命中测试结果异常的解决办法
不少开发者都碰到过:在iOS 17.2上使用OpenGLES2或Metal引擎时,SceneKit的hitTest返回结果和iOS 16.1不一致,经常出现错误匹配或者找不到目标节点的情况,尤其像你这种点击3D模型放置节点的场景。
下面是几个实测有效的解决思路:
1. 显式设置命中测试选项
默认的hitTest参数在iOS 17.2里可能调整了优先级,强制指定精确测试的选项能改善结果:
let hitOptions: [SCNHitTestOption: Any] = [ .boundingBoxOnly: false, // 禁用仅包围盒测试,确保精确命中几何体 .firstFoundOnly: false, // 返回所有命中结果,方便筛选 .ignoreHiddenNodes: true ] let hitResults = sceneView.hitTest(pointInScene, options: hitOptions) return hitResults.first { $0.node.name?.compare("body") == .orderedSame }
2. 换用Raycast替代传统HitTest
iOS 11之后推出的raycast方法在新系统里稳定性更好,适配纯SceneKit和ARKit场景:
// 纯SceneKit场景写法 let raycastResults = sceneView.raycast(pointInScene, options: [ .ignoreHiddenNodes: true, .searchMode: SCNHitTestSearchMode.all ]) return raycastResults.first { $0.node.name?.compare("body") == .orderedSame }?.node // ARKit场景写法 guard let query = sceneView.raycastQuery(from: pointInScene, allowing: .geometry, alignment: .any) else { return nil } let raycastResults = sceneView.session.raycast(query) return raycastResults.compactMap { $0.node }.first { $0.name?.compare("body") == .orderedSame }
3. 补全模型的碰撞检测设置
iOS 17.2对几何体的碰撞精度要求变高,若模型面数过少或为开放网格,容易命中失败:
- 导出模型时专门生成碰撞网格(多数3D建模软件都支持该选项)
- 手动给目标节点添加物理体,用物理引擎的射线检测替代:
// 先为"body"节点添加静态物理体 if let bodyNode = scene.rootNode.childNode(withName: "body", recursively: true) { bodyNode.physicsBody = SCNPhysicsBody(type: .static, shape: SCNPhysicsShape(node: bodyNode, options: [.type: SCNPhysicsShapeType.concavePolyhedron])) } // 使用物理世界的射线检测 let rayStart = sceneView.unprojectPoint(SCNVector3(pointInScene.x, pointInScene.y, 0)) let rayEnd = sceneView.unprojectPoint(SCNVector3(pointInScene.x, pointInScene.y, 1)) let physicsHits = sceneView.scene.physicsWorld.rayTestWithSegment(from: rayStart, to: rayEnd) return physicsHits.first { $0.node.name?.compare("body") == .orderedSame }?.node
4. 切换渲染引擎(针对OpenGLES2用户)
有开发者反馈将渲染引擎从OpenGLES2切换到Metal后,命中测试的问题直接消失:
sceneView.renderingAPI = .metal
临时救急:校正点击坐标
如果上面的方法来不及调整,试试手动校正点击点坐标系——有时是屏幕坐标系翻转导致的偏移:
var fixedPoint = pointInScene fixedPoint.y = sceneView.bounds.height - fixedPoint.y // 翻转Y轴适配SceneKit坐标系 let hitResults = sceneView.hitTest(fixedPoint, options: nil) return hitResults.first { $0.node.name?.compare("body") == .orderedSame }
内容的提问来源于stack exchange,提问作者truongtho1603
相关产品推荐
相关产品推荐

