gpt4 book ai didi

ios - 为什么 SCNNode "jiggling"掉落到 SCNPlane 上?

转载 作者:搜寻专家 更新时间:2023-10-31 19:32:26 25 4
gpt4 key购买 nike

我有一个 SCNPlane,当检测到水平表面有足够的区域时,它会添加到场景中。根据放置的地板/ table ,飞机似乎放置在正确的位置。问题是当我将一个 SCNNode(无论它是一个盒子、金字塔、3D 模型等,这一直是一致的)放到平面上时,它最终会找到一个着陆点并且 99% 的节点开始疯狂地摇晃。很少有几次它只是着陆而根本没有移动。我还认为这可能是由于节点掉落并稍微低于平面表面造成的。它既不在平面的“顶部”,也不在平面的“下方”。也许节点正在崩溃,因为它在两个级别之间摇摆不定?

这是一段视频,您可以在开始时看到盒子在平面下方和上方,橙色盒子在与深蓝色盒子碰撞时确实停止了,但又回到了摇晃的方式当绿色盒子最后与它碰撞时:

box jiggle

代码在github

我还将展示一些嵌入代码中的相关部分:

我只是创建一个 Plane 类以在需要时添加到场景中

class Plane: SCNNode {
var anchor :ARPlaneAnchor
var planeGeometry :SCNPlane!

init(anchor :ARPlaneAnchor) {
self.anchor = anchor
super.init()
setup()
}

func update(anchor: ARPlaneAnchor) {
self.planeGeometry.width = CGFloat(anchor.extent.x)
self.planeGeometry.height = CGFloat(anchor.extent.z)
self.position = SCNVector3Make(anchor.center.x, 0, anchor.center.z)
let planeNode = self.childNodes.first!
planeNode.physicsBody = SCNPhysicsBody(type: .static, shape: SCNPhysicsShape(geometry: self.planeGeometry, options: nil))
}

private func setup() {
//plane dimensions
self.planeGeometry = SCNPlane(width: CGFloat(self.anchor.extent.x), height: CGFloat(self.anchor.extent.z))
//plane material
let material = SCNMaterial()
material.diffuse.contents = UIImage(named: "tronGrid.png")
self.planeGeometry.materials = [material]
//plane geometry and physics
let planeNode = SCNNode(geometry: self.planeGeometry)
planeNode.physicsBody = SCNPhysicsBody(type: .static, shape: SCNPhysicsShape(geometry: self.planeGeometry, options: nil))
planeNode.physicsBody?.categoryBitMask = BodyType.plane.rawValue
planeNode.position = SCNVector3Make(anchor.center.x, 0, anchor.center.z)
planeNode.transform = SCNMatrix4MakeRotation(Float(-Double.pi / 2.0), 1, 0, 0)
//add plane node
self.addChildNode(planeNode)
}

这是 View Controller

enum BodyType: Int {
case box = 1
case pyramid = 2
case plane = 3
}
class ViewController: UIViewController, ARSCNViewDelegate, SCNPhysicsContactDelegate {
//outlets
@IBOutlet var sceneView: ARSCNView!
//globals
var planes = [Plane]()
var boxes = [SCNNode]()
//life cycle
override func viewDidLoad() {
super.viewDidLoad()
//set sceneView's frame
self.sceneView = ARSCNView(frame: self.view.frame)
//add debugging option for sceneView (show x, y , z coords)
self.sceneView.debugOptions = [ARSCNDebugOptions.showFeaturePoints, ARSCNDebugOptions.showWorldOrigin]
//give lighting to the scene
self.sceneView.autoenablesDefaultLighting = true
//add subview to scene
self.view.addSubview(self.sceneView)
// Set the view's delegate
sceneView.delegate = self
//subscribe to physics contact delegate
self.sceneView.scene.physicsWorld.contactDelegate = self
//show statistics such as fps and timing information
sceneView.showsStatistics = true
//create new scene
let scene = SCNScene()
//set scene to view
sceneView.scene = scene
//setup recognizer to add scooter to scene
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapped))
sceneView.addGestureRecognizer(tapGestureRecognizer)
}
//MARK: helper funcs
@objc func tapped(recognizer: UIGestureRecognizer) {
let scnView = recognizer.view as! ARSCNView
let touchLocation = recognizer.location(in: scnView)
let touch = scnView.hitTest(touchLocation, types: .existingPlaneUsingExtent)
//take action if user touches box
if !touch.isEmpty {
guard let hitResult = touch.first else { return }
addBox(hitResult: hitResult)
}
}

private func addBox(hitResult: ARHitTestResult) {
let boxGeometry = SCNBox(width: 0.1,
height: 0.1,
length: 0.1,
chamferRadius: 0)
let material = SCNMaterial()
material.diffuse.contents = UIColor(red: .random(),
green: .random(),
blue: .random(),
alpha: 1.0)
boxGeometry.materials = [material]
let boxNode = SCNNode(geometry: boxGeometry)
//adding physics body, a box already has a shape, so nil is fine
boxNode.physicsBody = SCNPhysicsBody(type: .dynamic, shape: nil)
//set bitMask on boxNode, enabling objects with diff categoryBitMasks to collide w/ each other
boxNode.physicsBody?.categoryBitMask = BodyType.plane.rawValue | BodyType.box.rawValue
boxNode.position = SCNVector3(hitResult.worldTransform.columns.3.x,
hitResult.worldTransform.columns.3.y + 0.3,
hitResult.worldTransform.columns.3.z)
self.sceneView.scene.rootNode.addChildNode(boxNode)
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let configuration = ARWorldTrackingConfiguration()
configuration.planeDetection = .horizontal
//track objects in ARWorld and start session
sceneView.session.run(configuration)
}
//MARK: - ARSCNViewDelegate
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
//if no anchor found, don't render anything!
if !(anchor is ARPlaneAnchor) {
return
}
DispatchQueue.main.async {
//add plane to scene
let plane = Plane(anchor: anchor as! ARPlaneAnchor)
self.planes.append(plane)
node.addChildNode(plane)
//add initial scene object
let pyramidGeometry = SCNPyramid(width: CGFloat(plane.planeGeometry.width / 8), height: plane.planeGeometry.height / 8, length: plane.planeGeometry.height / 8)
pyramidGeometry.firstMaterial?.diffuse.contents = UIColor.white
let pyramidNode = SCNNode(geometry: pyramidGeometry)
pyramidNode.name = "pyramid"
pyramidNode.physicsBody = SCNPhysicsBody(type: .dynamic, shape: nil)
pyramidNode.physicsBody?.categoryBitMask = BodyType.pyramid.rawValue | BodyType.plane.rawValue
pyramidNode.physicsBody?.contactTestBitMask = BodyType.box.rawValue
pyramidNode.position = SCNVector3(-(plane.planeGeometry.width) / 3, 0, plane.planeGeometry.height / 3)
node.addChildNode(pyramidNode)
}
}
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
let plane = self.planes.filter {
plane in return plane.anchor.identifier == anchor.identifier
}.first

if plane == nil {
return
}

plane?.update(anchor: anchor as! ARPlaneAnchor)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
//pause session
sceneView.session.pause()
}
}

最佳答案

我想我遵循了相同的教程。我也有同样的结果。原因是立方体从高处下落时加速,并没有恰好撞在平面上,而是穿过了。如果将立方体缩小到“1 毫米”,您可以看到盒子完全穿过平面并继续下降到平面以下。
您可以尝试将立方体从离平面较近的地方放下,盒子下降得更慢,并且不会发生这种“抖动”。或者您可以尝试使用高度较小的盒子而不是平面。

关于ios - 为什么 SCNNode "jiggling"掉落到 SCNPlane 上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48329115/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com