How can I make an ARNode
pointing to an ARAnchor
?
I want to use art.scnassets/ship.scn
showing in the center of the screen and pointing to the object I just placed somewhere in the scene.
/// ViewController Class
func placeObject() {
let screenCentre : CGPoint = CGPoint(x: self.sceneView.bounds.midX, y: self.sceneView.bounds.midY)
guard let hitTestResult = sceneView.hitTest(screenCentre, types: [.featurePoint]).first else { return }
// Place an anchor for a virtual character.
let anchor = ARAnchor(name: identifierString, transform: hitTestResult.worldTransform)
sceneView.session.add(anchor: anchor)
// add to item model
ItemModel.shared.anchors.append((identifierString, anchor)
}
func showDirection(of object: ARAnchor) { // object: saved anchor
if !Guide.shared.isExist {
let startPoint = SCNVector3(0, 0 , -1)
let targetPoint = SCNVector3(object.transform.columns.3.x, object.transform.columns.3.y, object.transform.columns.3.z)
let guideNode = Guide.shared.setPosition(from: startPoint, to: targetPoint)
// add the ship in the center of the view
sceneView.pointOfView?.addChildNode(guideNode)
}
}
/// Guide Class
func setPosition(from start: SCNVector3, to target: SCNVector3) -> SCNNode {
isExist = true
guideNode.position = start
targetPosition = target
// create target node from saved anchor
let desNode = SCNNode()
desNode.position = targetPosition
let lookAtConstraints = SCNLookAtConstraint(target: desNode)
guideNode.constraints = [lookAtConstraints]
return guideNode
}
// MARK: - ARSCNViewDelegate
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
if let name = anchor.name, name.hasPrefix(identifierString) {
// Create 3D Text
let textNode: SCNNode = createNewBubbleParentNode(identifierString)
node.addChildNode(textNode)
}
}
I tried SCNLookAtConstraint
but it does not work as expected, any suggestions?
I don't know this will help you in your case or not. (If not i will delete my answer)
So I have faced same issue. Where I am drawing wall between two SCNVector object. Issue is wall is double sided so in some case part visible to camera is flipped.
like If you draw wall from two vectors and then add another Node (Plane Node) with same Euler Angle added Node (Plane) is Vertically Flipped.
I have searched many solution and tried many things but this working for me.
class func node(from:SCNVector3,
to:SCNVector3,height:Float,needToAlignToCamera:Bool) -> SCNNode {
let distance = MathHelper().getMeasurementBetween(vector1: from, and: to)
let wall = SCNPlane(width: CGFloat(distance),
height: CGFloat(height))
wall.firstMaterial = wallMaterial()
let node = SCNNode(geometry: wall)
// always render before the beachballs
node.renderingOrder = -10
// HERE IS MAGIC LINES
//============================================
let normalizedTO = to.normalized()
let normalizedFrom = from.normalized()
let angleBetweenTwoVectors = normalizedTO.cross(normalizedFrom)
var from = from
var to = to
if angleBetweenTwoVectors.y > 0 && needToAlignToCamera {
let temp = from
from = to
to = temp
}
//============================================
node.position = SCNVector3(from.x + (to.x - from.x) * 0.5,
from.y + height * 0.5,
from.z + (to.z - from.z) * 0.5)
// orientation of the wall is fairly simple. we only need to orient it around the y axis,
// and the angle is calculated with 2d math.. now this calculation does not factor in the position of the
// camera, and so if you move the cursor right relative to the starting position the
// wall will be oriented away from the camera (in this app the wall material is set as double sided so you will not notice)
// - obviously if you want to render something on the walls, this issue will need to be resolved.
node.eulerAngles = SCNVector3(0, -atan2(to.x - node.position.x, from.z - node.position.z) - Float.pi * 0.5, 0)
return node
}
Extension
func cross(_ vec: SCNVector3) -> SCNVector3 {
return SCNVector3(self.y * vec.z - self.z * vec.y, self.z * vec.x - self.x * vec.z, self.x * vec.y - self.y * vec.x)
}
func normalized() -> SCNVector3 {
if self.length() == 0 {
return self
}
return self / self.length()
}
ARKit
updates positions of anchors and corresponding nodes provided via delegate method renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode?
So your constraints idea is correct, but you need to provide nodes via the delegate method instead of adding them directly to the scene.
Something like that -
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
switch anchor {
case MyAnchor:
let constraint = // ...
let node = // ...
node.constraints = [constraint]
return node
default:
return nil
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With