如何解决使用LiDAR网格碰撞RealityKit 3D模型
我花了很多天试图理解和遵循示例,但没有成功。
我的目标是将虚拟AR对象放置到先前使用LiDAR扫描的真实世界中。使用showSceneUnderstanding
,我可以看到创建的实时网格就可以了。
使用点击功能,我可以插入一个usdz文件,也可以。
因为我有toyModel.physicsBody?.mode = .kinematic
和self.arView.installGestures(for: toyRobot)
,所以我可以移动/缩放模型。
现在希望能够移动模型并与LiDAR生成的网格碰撞。例如,当我将模型移动到扫描的墙上时,网格就停止了。
这是我完整的代码:
import UIKit
import RealityKit
import ARKit
class ViewController: UIViewController,ARSessionDelegate {
@IBOutlet var arView: ARView!
var tapRecognizer = UITapGestureRecognizer()
override func viewDidLoad() {
super.viewDidLoad()
self.arView.session.delegate = self
//Scene Understanding options
self.arView.environment.sceneUnderstanding.options.insert([.physics,.collision,.occlusion])
//Only for dev
self.arView.debugOptions.insert(.showSceneUnderstanding)
self.tapRecognizer = UITapGestureRecognizer(target: self,action: #selector(placeObject(_:)))
self.arView.addGestureRecognizer(self.tapRecognizer)
}
@objc func placeObject(_ sender: UITapGestureRecognizer) {
// Perform a ray cast against the mesh (sceneUnderstanding)
// Note: Ray-cast option ".estimatedPlane" with alignment ".any" also takes the mesh into account.
let tapLocation = sender.location(in: arView)
if let result = arView.raycast(from: tapLocation,allowing: .estimatedPlane,alignment: .any).first {
// Load the "Toy robot"
let toyRobot = try! ModelEntity.loadModel(named: "toy_robot_vintage.usdz")
// Add gestures to the toy (only available is physicsBody mode == kinematic)
self.arView.installGestures(for: toyRobot)
// Toy Anchor to place the toy on surface
let toyAnchor = AnchorEntity(world: result.worldTransform)
toyAnchor.addChild(toyRobot)
// Create a "Physics" model of the toy in order to add physics mode
guard let toyModel = toyAnchor.children.first as? HasPhysics else {
return
}
// Because toyModel is a fresh new model we need to init physics
toyModel.generateCollisionShapes(recursive: true)
toyModel.physicsBody = .init()
// Add the physics body mode
toyModel.physicsBody?.mode = .kinematic
let test = ShapeResource.generateConvex(from: toyRobot.model!.mesh)
toyModel.components[CollisionComponent] = CollisionComponent(shapes: [test],mode: .default,filter: .default)
// Finally add the toy anchor to the scene
self.arView.scene.addAnchor(toyAnchor)
}
}
}
有人知道是否有可能实现这一目标?提前非常感谢!
解决方法
尝试向下广播到Entity & HasPhysics
:
guard let model = anchor.children.first as? (Entity & HasPhysics)
else { return }
model.generateCollisionShapes(recursive: true)
model.physicsBody = PhysicsBodyComponent(shapes: [.generateBox(size: .one)],mass: 1.0,material: .default,mode: .kinematic)
官方文档says:
,对于非模型实体 ,
generateCollisionShapes(recursive:)
方法无效。不过,该方法是为所有实体定义的,因此您可以在任何实体上调用该方法,并使计算以递归方式传播到该实体的所有后代。
在前面使用@AndyFedoroff进行讨论之后,我添加了凸光线射线投射,以便始终将放置的3d对象与LiDAR创建的网格碰撞。这是我的完整代码。我不知道我是否做得很好...无论如何仍然无法正常工作。
import UIKit
import RealityKit
import ARKit
class ViewController: UIViewController,ARSessionDelegate {
@IBOutlet var arView: ARView!
var tapRecognizer = UITapGestureRecognizer()
var panGesture = UIPanGestureRecognizer()
var panGestureEntity: Entity? = nil
override func viewDidLoad() {
super.viewDidLoad()
self.arView.session.delegate = self
//Scene Understanding options
self.arView.environment.sceneUnderstanding.options.insert([.physics,.collision,.occlusion])
//Only for dev
self.arView.debugOptions.insert(.showSceneUnderstanding)
self.tapRecognizer = UITapGestureRecognizer(target: self,action: #selector(self.placeObject))
self.arView.addGestureRecognizer(self.tapRecognizer)
self.panGesture = UIPanGestureRecognizer(target: self,action: #selector(self.didPan))
self.arView.addGestureRecognizer(self.panGesture)
}
@objc func placeObject(_ sender: UITapGestureRecognizer) {
// Perform a ray cast against the mesh (sceneUnderstanding)
// Note: Ray-cast option ".estimatedPlane" with alignment ".any" also takes the mesh into account.
let tapLocation = sender.location(in: arView)
if let result = self.arView.raycast(from: tapLocation,allowing: .estimatedPlane,alignment: .any).first {
// Load the "Toy robot"
let toyRobot = try! ModelEntity.loadModel(named: "toy_robot_vintage.usdz")
// Add gestures to the toy (only available is physicsBody mode == kinematic)
self.arView.installGestures(for: toyRobot)
// Toy Anchor to place the toy on surface
let toyAnchor = AnchorEntity(world: result.worldTransform)
toyAnchor.addChild(toyRobot)
// Create a "Physics" model of the toy in order to add physics mode
guard let model = toyAnchor.children.first as? (Entity & HasPhysics)
else { return }
model.generateCollisionShapes(recursive: true)
model.physicsBody = PhysicsBodyComponent(shapes: [.generateBox(size: .one)],mode: .kinematic)
// Finally add the toy anchor to the scene
self.arView.scene.addAnchor(toyAnchor)
}
}
@objc public func didPan(_ sender: UIPanGestureRecognizer) {
print(sender.state)
let point = sender.location(in: self.arView)
switch sender.state {
case .began:
if let entity = self.arView.hitTest(point).first?.entity {
self.panGestureEntity = entity
} else {
self.panGestureEntity = nil
}
case .changed:
if let entity = self.panGestureEntity {
if let raycast = arView
.scene
.raycast(origin: .zero,direction: .one,length: 1,query: .all,mask: .all,relativeTo: entity)
.first
{
print("hit",raycast.entity,raycast.distance)
}
}
case .ended:
self.panGestureEntity = nil
default: break;
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。