Reputation: 9
I have been trying to place an 3d object in horizontal plane but placed 3d object does not fixed into its position.
Currently i can able place 3d object in horizontal plane but placed 3d object in horizontal are moving. placed 3d object are not fixing into its position.
Here is the code i have trying to place 3d object into fixed position:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
// gives us the location of where we touched on the 2D screen.
let touchLocation = touch.location(in: sceneView)
// hitTest is performed to get the 3D coordinates corresponding to the 2D coordinates that we got from touching the screen.
// That 3d coordinate will only be considered when it is on the existing plane that we detected.
let results = sceneView.hitTest(touchLocation, types: .existingPlaneUsingExtent)
// if we have got some results using the hitTest then do this.
if let hitResult = results.first {
let boxScene = SCNScene(named: "art.scnassets/porsche.scn")!
// var boxScene = SCNScene(named: "art.scnassets/porsche.scn")!
if let boxNode = boxScene.rootNode.childNode(withName: "car", recursively: true) {
print("box:::\(boxNode.childNodes)")
boxNode.position = SCNVector3(x: hitResult.worldTransform.columns.3.x, y: hitResult.worldTransform.columns.3.y, z: hitResult.worldTransform.columns.3.z)
// finally the box is added to the scene.
sceneView.scene.rootNode.addChildNode(boxNode)
}
}
}
}
Here is the code to detect plane:
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
if anchor is ARPlaneAnchor {
anchors can be of many types, as we are just dealing with horizontal plane detection we need to downcast anchor to ARPlaneAnchor
let planeAnchor = anchor as! ARPlaneAnchor
creating a plane geometry with the help of dimentions we got using plane anchor.
let plane = SCNPlane(width: CGFloat(planeAnchor.extent.x), height: CGFloat(planeAnchor.extent.z))
// a node is basically a position.
let planeNode = SCNNode()
setting the position of the plane geometry to the position we got using plane anchor.
planeNode.position = SCNVector3(x: planeAnchor.center.x, y: 0, z: planeAnchor.center.z)
// when a plane is created its created in xy plane instead of xz plane, so we need to rotate it along x axis.
planeNode.transform = SCNMatrix4MakeRotation(-Float.pi/2, 1, 0, 0)
//create a material object
let gridMaterial = SCNMaterial()
//setting the material as an image. A material can also be set to a color.
gridMaterial.diffuse.contents = UIImage(named: "art.scnassets/grid.png")
// assigning the material to the plane
plane.materials = [gridMaterial]
// assigning the position to the plane
planeNode.geometry = plane
//adding the plane node in our scene
node.addChildNode(planeNode)
}
else {
return
}
}
Upvotes: 1
Views: 2065
Reputation: 418
The problem is that your model is probably too big, if you pay attention to the default model from Apple, then it is the size -
And my uploaded model was 1000 times bigger -
And this is why it not fixed, we need to make it less:
And now our model have fixed position and behaves like a default model from apple:
Done:)
Upvotes: 0
Reputation: 7385
I think what you need to do is create an ARAnchor
for your model:
Whenever you place a virtual object, always add an ARAnchor representing its position and orientation to the ARSession. After moving a virtual object, remove the anchor at the old position and create a new anchor at the new position. Adding an anchor tells ARKit that a position is important, improving world tracking quality in that area and helping virtual objects appear to stay in place relative to real-world surfaces.
As such this will probably point you in the right direction:
1st: Create a variable which will refer to your boxNode:
var boxNode: SCNNode?
2nd: Create an ARAnchor
at the touch location e.g:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//1. Get The Current Touch Location & Perform An ARSCNHitTest
guard let currentTouchLocation = touches.first?.location(in: sceneView),
let hitTest = sceneView.hitTest(currentTouchLocation, types: .existingPlaneUsingExtent).first else { return }
//2. Create An Anchor At The World Transform
let anchor = ARAnchor(transform: hitTest.worldTransform)
//3. Add It To The Scene
sceneView.add(anchor: anchor)
}
3rd: In the rendererDidAddNode delegate callback
intialize the model:
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
//1. If We Havent Created Our Box Node Then Create It
if boxNode == nil{
//a. Check That Our SCNScene Is Valid
guard let validScene = SCNScene(named: "art.scnassets/porsche.scn"),
let carRoot = validScene.rootNode.childNode(withName: "car", recursively: true) else { return }
//b. Set The BoxNodes Position And Add It To The Anchor
boxNode = carRoot
boxNode?.position = SCNVector3(anchor.transform.columns.3.x, anchor.transform.columns.3.y, anchor.transform.columns.3.z)
node.addChildNode(boxNode!)
}
}
Hope it helps...
Upvotes: 2