我试图建立一个应用程序,你可以在桌子上放置设备,自动生成,如果应用程序检测水平面。我将在代码后面解释这个问题:
import UIKit
import SceneKit
import ARKit
class ViewController: UIViewController, ARSCNViewDelegate {
@IBOutlet var sceneView: ARSCNView!
var isTableAdded = false
var diceArray = [SCNNode]()
override func viewDidLoad() {
super.viewDidLoad()
// Set the view's delegate
sceneView.delegate = self
self.sceneView.debugOptions = [ARSCNDebugOptions.showFeaturePoints]
sceneView.autoenablesDefaultLighting = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Create a session configuration
let configuration = ARWorldTrackingConfiguration()
configuration.planeDetection = .horizontal
// Run the view's session
sceneView.session.run(configuration)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Pause the view's session
sceneView.session.pause()
}
// MARK: - ADDS DICE
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("Tapped")
if let touch = touches.first {
let touchLocation = touch.location(in: sceneView)
let results = sceneView.hitTest(touchLocation, types: .existingPlaneUsingExtent)
if let hitResults = results.first {
// Create a new scene
let diceScene = SCNScene(named: "art.scnassets/diceCollada.scn")!
if let diceNode = diceScene.rootNode.childNode(withName: "Dice", recursively: true) {
diceNode.position = SCNVector3(
x: hitResults.worldTransform.columns.3.x,
y: hitResults.worldTransform.columns.3.y,
z: hitResults.worldTransform.columns.3.z)
diceArray.append(diceNode)
sceneView.scene.rootNode.addChildNode(diceNode)
}
}
}
}
// MARK: - RENDERS TABLE AT THE HORIZONTAL PLANE
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
print("plane detected")
if isTableAdded == false {
let planeAnchor = anchor
// let planeNode = SCNNode()
let x = planeAnchor.transform.columns.3.x
let y = planeAnchor.transform.columns.3.y
let z = planeAnchor.transform.columns.3.z
//planeNode!.position = SCNVector3(x: x, y: y, z: z)
let idleScene = SCNScene(named: "art.scnassets/Table.scn")!
let node = SCNNode()
for child in idleScene.rootNode.childNodes{
node.addChildNode(child)
}
node.position = SCNVector3(x,y,z)
node.scale = SCNVector3(0.001,0.001,0.001)
sceneView.scene.rootNode.addChildNode(node)
isTableAdded = true
}
print("Model placed")
}
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
guard let planeAnchor = anchor as? ARPlaneAnchor else { return }
print("plane updated")
}
}
问题在这里。(视频来自Imgur)。正如你所看到的桌子被放置,但我不太明白如何将SCNScene直接放置在另一个。我所做的唯一一件事就是在水龙头处创建一个模型,并且它只放置在水平面上。
我如何在另一个模型上生成模型?
您可以使用这个小小的extension
来实现您想要的。它基本上是一个辅助函数,允许您从任何场景文件(.scn)中抓取所有几何对象,并且可以将它们放置在您想要的任何地方。我使用这个函数从大量其他场景文件中组合/构建一个场景(默认),这些场景文件包含单独的几何形状。它将返回一个SCNNode而不是一个新的SCNScene。如果你需要更多的信息,或者如果我误解了你的话,请告诉我。
extension SCNNode {
convenience init(named name: String) {
self.init()
guard let scene = SCNScene(named: name) else {return}
for childNode in scene.rootNode.childNodes {addChildNode(childNode)}
}
}
(将此代码片段放在ViewController
之外的某个地方)
那么你可以这样使用:
let objectNode = SCNNode(named:"art.scnassets/some_directory/some_scene.scn").flattenedClone()
如果您想将单个SCNNode
中的所有几何图形合并到一个对象中,flattenedClone
是有用的。如果你不使用flattenedClone
,你会发现你的几何图形是objectNode
的单独childNodes
。
请记住,添加静态物理体到表(可能地板)和动态物理体到你的设备,如果你想保持他们在桌子的顶部,防止他们掉下地面(地板)。