Default camera position not changing? - scenekit

So I am trying to understand how allowsCameraControl really work.
I have a scene and I set the allowsCameraControl = true. When I pan around and the scene rotates, or translates (two fingers...), I don't understand what scene kit really changes for me.
I was expecting the camera node to change position, or rotation. Not the case.
I also logged the position and rotation of the rootNode of the scene...no change.
So just to be clear, in the render delegate called for every frame update, I log the position and rotation of the camera node I set for the scene, I logged the position and rotation of the root node, I also logged te position and rotation of a node I added to the scene. None of these show any change in position and or rotation.
Can anyone explain to me what scene kit changes when the scene rotates or translates using the standard camera controls?

A new camera is indeed created, leaving the original one unchanged. The scene graph is also unchanged. The new camera is not part of the scene graph and can be accessed with
scnView.pointOfView

A new camera is created, leaving the original one unchanged.
If you show the inspector using the showsStatistics property, you'll notice the Point of View changes from the camera you had (even if it is "Untitled") to kSCNFreeViewCameraName.
Sadly there is not much documentation about this behavior but you might be able to find it in the node hierarchy.
Let us know what you find!

Just came across an easy way of detecting the moment when a new camera is switched by SceneKit using KVO.
Swift 5
Declare an observer property in your class:
var povObserver: NSKeyValueObservation?
Then, setup the observer:
povObserver = defaultCameraController.observe(\.pointOfView, options: [.new]) { (cameraController, change) in
if let newPov = cameraController.pointOfView {
// Access new camera here
}
}
When finished you can set povObserver to nil

Related

Importing Archilogic scene into A-frame

I came across this scene (scene ID # 71c8eef9-b44e-447f-a0d2-fd299318da56) on one of the examples on stackoverflow. When I use that scene id as in the code below in a-frame.
io3d.scene.getAframeElements('71c8eef9-b44e-447f-a0d2-fd299318da56').then(elems => { document.querySelector('a-scene').appendChild(elems[0]) })
I can see the scene with perfect position and scale. However, when I use the scene I developed (scene id: 8f769bc6-4a0e-4bb4-bfaa-8580ac93f88f) using the same code in a-frame, the house displays as a very small object and position is also not correct. There is no difference in the code for both the scenes but the scale and position differs for both of them.
I tried to play around with position and scale attributes but it did not work. Could you kindly help understand what could be the difference? Thanks, Niraj
Your model is positioned very far from the origin of the worl, that means it is (110.86, 88.96) meters away from the center.
when you use io3d.scene.getAframeElements it will take the position and scale from the original scene.
you have the following options:
1) change your camera position to match the offset of the model
2) move the model to the center by changing positions of the elements
3) use the appcreator to create your aframe scene with the correct setup (here is an example of your scene
4) adjust the scene in spaces.archilogic.com
Hope that helps!

How do I get the real-time position of SCNNode? [duplicate]

I am working on a basic racing game using Apple's SceneKit and am running into issues simulating a car. Using the SCNPhysicsVehicle behavior, I am able to properly set up the car and drive it using the documented methods.
However, I am unable to get the car's position. It seems logical that the SCNPhysicsVehicle would move the SCNNodes that contain the chassis and the wheels as the car moves but the SCNNodes remain at their original position and orientation. Strangely enough, the chassis' SCNPhysicsBody's velocity remains accurate throughout the simulation so I can assume that the car's position is based off of the SCNPhysicsBody and not the SCNNode. Unfortunately, there is no documented method that I have found to get an SCNPhysicsBody's position.
Getting a car's position should be trivial and is essential to create a racing game but I can't seem to find any way of getting it. Any thoughts or suggestions would be appreciated.
Scene Kit automatically updates the position of the node that owns an SCNPhysicsBody based on the physics simulation, so SCNNode.position is the right property to look for.
The catch is that there are actually two versions of that node in play. The one you typically access is called the "model" node. It reflects the target values for properties you set, even if you set those properties through an animation. The presentationNode reflects the state of the node currently being rendered — if an animation is in progress, the node's properties have intermediate values, not the target values of the animation.
Actions, physics, constraints, and any scene graph changes you make inside update/render loop methods directly target the "presentation" version of your scene graph. So, to read node properties that have been set by the physics simulation, get the presentationNode for the node you're interested in (the node that owns the vehicle's chassisBody physics body), then read the presentation node's position (or other properties).
I have the same problem with my player node.
I move it with applyForce (to manage collision detection).
But when i check node position after some movement, the node position has not move (presentation node is the actual position as rickster write in his answer)
I manage to update the scnNode.position with renderer loop
You have to set position of your node with the presentationNode position.
node.position = node.presentationNode.position
Set this into renderer(_: updateAtTime) and your node position will sync with any animation you made to the physicsBody

In SceneKit, how do you make camera look at a specific face of a node's geometry?

In SceneKit, you can add a lookAtConstraint constraint to your SceneView's Point Of View, to make Camera look at a certain node.
Is there a standard way of doing the same but for a specific face of a geometry?
So that, if I touch a specific face of a cube, camera would move so that the Z axis of the camera node gets in line with the normal of the touched face? So that the cube would look like a plane form the new perspective.
No.
That would require movement of the camera, in addition to re-aiming it.
Imagine I'm in front of my house. I have a great view of the front and can just barely see the side to my left. In my Scene I tap the side of the house. A LookAt constraint would merely change the angle of the camera. It would not be aligned with the normal of that barely visible side.
To align with the normal, I'd have to walk around the house until I can stare at the house and be perpendicular to the side I tapped. At what radius? What path? You have to figure that out yourself.
Depending on what effect you're trying for, you might want to rotate the model instead of moving the camera. Rotate the tapped node locally (or as a child of an invisible parent) so that its minus-Z axis points out the tapped face, and keep a lookAtConstraint on the node, not the camera. This approach will change the look of the object, though: you will see it rotating, and the shading changing appropriately.
So that, if I touch a specific face of a cube, camera would move so that the Z axis of the camera node gets in line with the normal of the touched face?
Supposing you are using hit-testing to determine what object got touched, a SCNHitTestResult will give you both localCoordinates and localNormal from which it should be fairly easy to derive a camera transform.
One easy way would be to have the camera as a child node of the box, compute a position that would look like localCoordinates + distance * localNormal and finally a transform using GLKMatrix4MakeLookAt and SCNMatrix4FromGLKMatrix4.
Note that you can also use worldCoordinates, worldNormal, as well as conversion utilities such as SCNNode.convertTransform(_:from:).
mutating on mnuages answer, use a hit test or ray trace to find where the user tapped on the mesh, then add a node at that location, and constrain the camera to lookAt that node.

SceneKit, fixing a light's position

I would like to allow the user to rotate the scene by touch but have the lighting remain fixed. This works quite well using the default camera and default lighting. However, the default light is "straight on", i.e. along the screen's -z axis. I would rather it be directed at an angle more like a stage light, say from the front upper right.
But when I create my own light it appears that it needs to be attached to an existing node, the rootNode for example. When this is done, the light then rotates around with the model as the user manipulates the scene.
Is there a simple way to keep the lighting fixed while rotating with the default camera or do I need to get seriously involved creating a custom camera?
The lighting is already "fixed": that is, each light source keeps its position and direction within the scene unless you do something to change it. But it sounds like instead, you want to have a light that is fixed relative to a camera.
To achieve this, don't attach the light to the scene's root node. Instead, attach it to the same node that the camera is attached to. Or if you want to adjust the light's position relative to the camera, you could construct a small node tree, with one leaf containing the camera and the other leaf containing a directional light.
You'll almost always want to create your own camera or cameras in SceneKit. The default user-manipulable camera is useful for quickly getting up and running, and debugging, but not something that you want to expose to end users.

How to keep an MKAnnotation View Image fixed on the center of the map as the user pans and moves the map around (iOS 6)?

using iOS 6 MapKit, I would like to define an MKAnnotation (such as a pin, or a custom one) that remains fixed on the center of the map view as the user moves the map around. Once the user stops moving the map, I would like to be able to read the new coordinates of the annotation. How can I do this?
Thanks
The easiest way is to simply add your custom UIView to your MKMapView as a subview. This means when your user moves the map it will stay fixed. You will most likely have to pass through the touch events so that users can move over your custom view but worry about that later.
When your map view stops moving take its center coordinate. The MKMapView can calculate its coordinate based on its center etc [mapView centerCoordinate];
I know this is a bit old but I recommend you DSCenterPinMapView
It is a custom MapView with an animated and customizable center pin useful for selecting locations in map.
You should install the Pod and then, as a solution to your question you should implement the delegate so that you can get the location where pin drops.
pinMapView.delegate = self
extension MyViewController: DSCenterPinMapViewDelegate {
func didStartDragging() {
// My custom actions
}
func didEndDragging() {
// My custom actions
selectedLocation = pinMapView.mapview.centerCoordinate
}
}

Resources