Swift: Obtain and save the updated SCNNode over time using projectPoint in scenekit
If I understand your question correctly you want to save the vertex positions each time they are updated, keeping track of all previous updates as well as the most recent one. In order to do this you simply need to append the new vertex position array to the global array with saved data.
var savedPositions = [CGPoint]()
var beginSaving = false
func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
guard anchor == currentFaceAnchor,
let contentNode = selectedContentController.contentNode,
contentNode.parent == node
else { return }
for vertex in vertices {
let projectedPoint = sceneView.projectPoint(node.convertPosition(SCNVector3(vertex), to: nil))
if beginSaving {
savedPositions.append(CGPoint(x: projectedPoint.x, y: projectedPoint.y))
}
}
selectedContentController.session = sceneView?.session
selectedContentController.sceneView = sceneView
selectedContentController.renderer(renderer, didUpdate: contentNode, for: anchor)
}
@IBAction private func startPressed() {
beginSaving = true
}
@IBAction private func stopPressed() {
beginSaving = false
....//do whatever with your array of saved positions
}
Why does SCNNode move all over the place using ARKit?
The camera is likely losing its real world position reference when you shake the device.
iOS SceneKit to UIView projection issue
The problem here is that CGRect
you use to calculate the mid points is based on the projected coordinates of the bounding box. The two corner points of the bounding box are transformed using the model view projection matrix, to get the correct view space coordinates for the mid points you need to perform the same transformation.
Hopefully the code is a bit clearer.
//world coordinates
let v1w = sm.node.convertPosition(sm.node.boundingBox.min, to: self.sceneView.scene?.rootNode)
let v2w = sm.node.convertPosition(sm.node.boundingBox.max, to: self.sceneView.scene?.rootNode)
//calc center of BB in world coordinates
let center = SCNVector3Make(
(v1w.x + v2w.x)/2,
(v1w.y + v2w.y)/2,
(v1w.z + v2w.z)/2)
//calc each mid point
let mp1w = SCNVector3Make(v1w.x, center.y, center.z)
let mp2w = SCNVector3Make(center.x, v2w.y, center.z)
let mp3w = SCNVector3Make(v2w.x, center.y, center.z)
let mp4w = SCNVector3Make(center.x, v1w.y, center.z)
//projected coordinates
let mp1p = self.sceneView.projectPoint(mp1w)
let mp2p = self.sceneView.projectPoint(mp2w)
let mp3p = self.sceneView.projectPoint(mp3w)
let mp4p = self.sceneView.projectPoint(mp4w)
var frameOld = sm.marker.frame
switch sm.position
{
case .Top:
frameOld.origin.y = CGFloat(mp1p.y) - frameOld.size.height/2
frameOld.origin.x = CGFloat(mp1p.x) - frameOld.size.width/2
sm.marker.isHidden = (mp1p.z < 0 || mp1p.z > 1)
case .Bottom:
frameOld.origin.y = CGFloat(mp2p.y) - frameOld.size.height/2
frameOld.origin.x = CGFloat(mp2p.x) - frameOld.size.width/2
sm.marker.isHidden = (mp2p.z < 0 || mp2p.z > 1)
case .Left:
frameOld.origin.y = CGFloat(mp3p.y) - frameOld.size.height/2
frameOld.origin.x = CGFloat(mp3p.x) - frameOld.size.width/2
sm.marker.isHidden = (mp3p.z < 0 || mp3p.z > 1)
case .Right:
frameOld.origin.y = CGFloat(mp4p.y) - frameOld.size.height/2
frameOld.origin.x = CGFloat(mp4p.x) - frameOld.size.width/2
sm.marker.isHidden = (mp4p.z < 0 || mp4p.z > 1)
}
It's a cool little sample project!
Update on z-clipping issue
The projectPoint
method returns a 3D SCNVector
, the x any y coords as we know are the screen coordinates. The z coordinate tells us the location of the point relative to the far and near clipping planes (z = 0 near clipping plane, z = 1 far clipping plane). If you set a negative value for your near clipping plane, objects behind the camera would be rendered. We don't have a negative near clipping plane, but we also don't have any logic to say what happens if those projected point locations fall outside the z far and z near range.
I've updated the code above to include this zNear and zFar check and toggle the UIView visibility accordingly.
tl;dr
The markers visible when the camera was rotated 180deg are behind the camera, but they were still projected onto the view plane. And as we weren't checking if they we behind the camera, they were still displayed.
Scene Kit: projectPoint calculated is displaced
have to set z to zero on both world coordinates:
v1w.z = 0
v2w.z = 0
explaining things help
Mapping 3D SceneKit Node-Position to 2D Coordinate - projectPoint doesn't work
It could be that it's projecting from the untranslated, unmodified node position, or that the node is a child of another node, thus changing its frame of reference. Try using myNode.presentation.worldPosition
as the input for projectPoint
.
[EDIT]
Reading a bit closer, would you not be better off creating a flat texture of your sprite, attach it to the node in question, give it a 'billboard' constraint and set its Z order so that it always appears in front?
Related Topics
How to Handle Usernotifications Actions in iOS 10
Modifing One Variable from Another View Controller Swift
Records, Zone Doesn't Displayed in Dashboard and Delete Zone Issue Cloudkit
Swift:Background Color Fading Animation (Spritekit)
How to Get Account Name from Contact Framework
Create Hash in Swift Using Key and Message
How to Change Uitextfield Color in Searchcontroller
iOS Do Scheduled Operation in Background or When App Active
How to Open Amazon App from Within My App
Pure Swiftui Login, Signup, Register Flow, Is It Possible
Animating Strings Fading In/Out in Swift
How to Change How a Remote Notification Is Presented Before Presentation
Subview Gesture Recognizer Not Being Called
Swift Difference Between Var Arr:[String] = [] and Var Arr = [String]()
Wkwebview: How to Preload Multiple Urls
Creating a Rtsp Client for Live Audio and Video Broadcasting in Objective C
Swift Calling Setnavigationbarhidden But View Wont Move to Top