How to change X3DOM mouse model for rotating camera - x3dom

Currently X3DOM handles camera movement like all scene is in a sphere, dragging mouse left to right moves the sphere (thus the scene) around the center of that sphere, like this.
Can we change this behaviour like in Blender's, as the same left to right dragging rotates the scene around Z axis (in other words, changes the azimuth without changing the current elevation) and dragging from up to down changes the elevation, without changing azimuth, like this one?

There are some navigation modes available: https://doc.x3dom.org/tutorials/animationInteraction/navigation/index.html. However I think you will have to create your own navigation mode if you want to have exact behaviour as in Blender.
For example you could activate the "Turntable" mode adding the following to your scene node:
<NavigationInfo type= 'turntable' ></NavigationInfo>
You can also find some discussion regarding more control over the navigation on mailing list and within the issues of X3DOM:
https://github.com/x3dom/x3dom/issues/454 and
https://github.com/x3dom/x3dom/issues/486

Related

How to temporarily freeze a node in front of the camera using ARKit, SceneKit in Swift

I built a complete structure as a node (with its child nodes) and the user will walk through it using ARKit.
At some point, if the user cannot continue because of some real obstacle in the real world, I added a "pause" button which should freeze whatever the user currently sees in front of the camera, the user could then move freely to some other open space and when the user will release the pause button he/she will be able to resume where they left off (only someplace else in the real world).
A while ago I asked about it in the Apple Developer forum and an Apple Frameworks Engineer gave the following reply:
For "freezing" the scene, you could transform the anchor's position (in world coordinates) to camera coordinates, and then anchor your content to the camera. This will give you the effect that the scene is "frozen", i.e., does not move relative to the camera.
I'm currently not using an anchor because I don't necessarily need to find a flat surface. Rather, my node is placed at a certain position relative to where we start at (0,0,0).
My question is how do I exactly do what the Apple engineer told me to do?
I have the following code which I'm still stuck with. When I add the node to the camera (pointOfView, last line of the code below), it does freeze in place, but I can't get it to freeze in the same position and orientation as it was before it was frozen.
#IBAction func pauseButtonClicked(_ sender: UIButton) {
let currentPosition = sceneView.pointOfView?.position
let currentEulerAngles = sceneView.pointOfView?.eulerAngles
var internalNodeTraversal = lastNodeRootPosition - currentPosition! // for now, lastNodeRootPosition is (0,0,0)
internalNodeTraversal.y = lastNodeRootPosition.y + 20 // just so it’s positioned a little higher in front of the camera
myNode?.removeFromParentNode() // remove the node from the Real World view. Looks like this line has no effect and just adding the node as a child to the camera (pointOfView) is enough, but it feels more right to do this anyway.
myNode?.position = internalNodeTraversal // the whole node is moved respectively in the opposite direction from the root to where I’m standing to reposition the camera in my current position inside the node
// myNode?.eulerAngles = (currentEulerAngles! * -1) — this code put the whole node in weird positions so I removed it
myNode?.eulerAngles.y = currentEulerAngles!.y * -1 // opposite orientation of the node so the camera will be oriented in the same direction
myNode?.eulerAngles.x = 0.3 // just tilting it up a little bit to have a better view, more similar to the view as before it was locked to the camera
// I don’t think I need to change the eulerAngles.z
myNode!.convertPosition(internalNodeTraversal, to: sceneView.pointOfView) // I’m not sure I wrote this correctly. Also, this line doesn’t seem tp change anything
sceneView.pointOfView?.addChildNode(myNode!) // attaching the node to the camera so it will remain stuck while the user moves around until the button is released
}
So I first calculate where in the node I'm currently standing and then I change the position of the node in the opposite direction so that the camera will now be in that position. That seems to be correct.
Now I need to change the orientation of the node so that it will point in the right direction and here things get funky. I've been trying so many things for days now.
I use the eulerAngles for the orientation. If I set the whole vector multiplied by -1, it would show weird orientations. I ended up only using the eulerAngles.y which is the left/right orientation and I hardcoded the x orientation (up/down).
Ultimately what I have in the code above is the closest that I was able to get. If I'm pointing straight, the freeze will be correct. If I turn just a little bit, the freeze will be pretty close as well. Almost the same as what the user saw before the freeze. But the more I turn, the more the frozen image is off and more slanted. At some point (say I turn 50 or 60 degrees to the side) the whole node is off the camera and cannot be seen.
Somehow I have a feeling that there must be an easier and more correct way to achieve the above.
The Apple engineer wrote to "transform the anchor's position (in world coordinates) to camera coordinates". For that reason I added the "convertPosition" function in my code, but a) I'm not sure I used it correctly and b) it doesn't seem to change anything in my code if I have that line or not.
What am I doing wrong?
Any help would be very much appreciated.
Thanks!
I found the solution!
Actually, the problem I had was not even described as I didn't think it was relevant. I built the AR nodes 2 meters in front of the origin (-2 for the z-coordinate) while the center of my node was still at the origin. So when I changed the rotation or eulerAngles, it rotated around the origin so my nodes moved in a large curve and in fact also changed their position as a result.
The solution was to use a simdPivot. Instead of changing the position and rotation of the node itself, I created a translation matrix and a rotation matrix which was at the point of the camera (where the user is standing) and I then multiplied both matrices. Now when I added the node as a child of the camera (pointOfView) this would freeze the image and in effect show exactly what the user was seeing before it was frozen as the position is the same and the rotation is exactly around the user's standing position.

Swift SceneKit - I am trying to figure out if a Node object goes off the screen

Using SceneKit
I want to make the gray transparent box to disappear and only show the colored boxes when the user zooms in.
So I want to detect when that box's edges are starting to fall off the screen as I zoom, so I can hide the gray box accordingly.
First thoughts, but there may be better solutions:
You could do an unprojectPoint on the node and check against screen coordinates, do the +/- math on object size and skip Z. I "think" that would work
You can do some physics based collision detection against an invisible box or plane geometries that acts as your screen edges, has some complexity if your view is changing, but testing would be easy - just leave visible until you get what you want, then isVisible=false
isNode(insideFrustomof: ) - returns boolean on whether it "might" be visible. I'm assuming "might" means obscured by other geometry which in your case, shouldn't matter (edit) on second thought, that doesn't solve your problem but I'll leave it in here for reference.

Controlling movement of flying a vehicle with SceneKit

I currently have a scene which contains a central node at the root of the scene with earth-like geometry and a node representing a flying vehicle.
However I cannot find the right approach to control the movement of the vehicle. I need the ability to turn left and right while orbiting at a static altitude and speed.
I have tried many combinations of animations and physics body forces all leading to undesirable results.
The closest I've come is:
Setting the pivot property of the vehicle to the centre of the scene
Then setting an Action like below to control moving forward
[_vehicleNode runAction:[SCNAction repeatActionForever:[SCNAction rotateByX:-1 y:0 z:0 duration:10.0]]];
Then finally applying forces for turning left and right with
[_vehicleNode.physicsBody applyTorque:SCNVector4Make(0, 1, 0, 1) impulse:YES];
However I cannot seem to set the pivot and/or position to the right value to get the desired result.
Edit: It appears as the above method would be the solution I'm looking for, however for some reason when I add geometry to the vehicle node, it's position in the scene graph gets changed dramatically. When I add hardcoded buttons to change it's position to where it belongs it appears correct for only that single frame then straight back to being in the middle of nowhere.
Edit 2: After replacing all geometry with a primitive sphere for testing the node is now rotating as intended but is now unaffected by physics forces appearing to ignore it's declaration as a dynamicBody.
If I understand what you are trying to achieve correctly, you can try this:
add a first node to your scene, positioned at (0,0,0) and make it rotate forever along the Y axis using an SCNAction
add your ship node as a child of the first node. Position it at (X,0,0) so that it orbits around the earth
rotate your ship node along the X axis with an action or an animation

Moving around the planet in sprite kit

I'm currently making a game where driving a moon lander across the terrain of alien planets. The lander is free moving so you can turn any direction you like.
I've got a camera centred on the player's vehicle and navigation is working well, however...
As the player approaches the horisontal sides (x) of the map I'd like the map to display continuously.
I've used a couple of different approaches so far; I've added an identical sprite as the map to the left of the map and created a method that moves the extended map to the right side if you approach that side instead, and I've also tested with two different extended maps, one for left and one for right. I've then setup physics for the extended maps and changed the landers position from one side of the map to the other as it collides with the extended maps.
My issue is that I'd like to have my enemies spawning and walking around the main map and as you approach the side you will of course not see the enemies on the other side of the map - you'd only see the extended map with no contents.
My preference would be for the world to "bend" so that as you approach the left edge you'd automatically see the right edge and vice versa. I have no idea whether this is even feasible so any suggestions are much appreciated.
Thanks in advance.
I'm not sure I understand your question. Maybe this will further discussion, anyhow.
If you are looking for a scrolling behavior then I would have two backgrounds (or more if you want a wider scrolling field) and your method for swapping the tiles around to make the background feel continuous, use the "camera" tracking technique and shown in Apple's sprite kit demo to follow your player (which it sounds like you are doing). Then when aliens move offscreen in either direction relocate them in the same way that you would swap out your background tile(s) with something like position.x += widthOfBackgroundTile.

how to Move world view instead of camera view

I have a viewport3d with a camera and some blocks inside of it. Currently using the keyboard to move the camera up/down/left/right/rotate ect.
but instead of the camera i want to move the world view. So when a user presses the W key to move up, its not just moving the camera in a +x position. As the user maybe at a 20 degree view.
Create a virtual Camera Boom.
Create an invisible object like a TDummy, in the same location as the object of interest or the center of the scene.
Create the TCamera as a child of the object. Set its position the desired distance away on one of the axes.
you can now rotate the camera around the object simply by changing the rotationAngle of the dummy object. The camera will maintain the exact distance and automatically points directly toward the center.
Also by adding light as a child of the camera it too will follow as the camera moves. Hope this helps someone.

Resources