Controlling movement of flying a vehicle with SceneKit - ios

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

Related

PhysicsBody stays after translation and rotation

I have a node with a cube attached which represents for example a door. The physicsbody type is .static. If i animate the node up, rotate it and animate it down to the orignial position of the physicsbody stays in the upper position.
In the debug mode the color of the phyisicsbody is first grey (i asume grey = .static), after the translation up, the physicsbody stays at the bottom. As soon as I rotate the node in the upper position, the physicsbody becomes green and moves up to the nodes position. After I translate the node down to the original position, the physicsbody stays in the upper position. Why is this behaviour? Is this because the type is .static?
I know if I set the physicsbody type to .kinematic (shown red in debug) mode it works as expected. The physicsbody adapts the translations and rotations. But with .static type I can place more objects before the fps drops than with .dynamic.
From the documentation for SCNPhysicsBodyTypeStatic we learn that it is
A physics body that is unaffected by forces or collisions and cannot move
However you can use resetTransform to explicitly tell the engine that the node has moved and that the physics body needs to be updated:
If you change the position or orientation of a node with an attached
static or dynamic physics body, call this method afterward to ensure
that the physics simulation incorporates the change. You need not call
this method for kinematic bodies.
Note that dynamic and physics bodies
are designed to be moved only by the physics simulation or not at all.
You may use this method to move them regardless of this restriction,
but at a cost to performance.

How to change X3DOM mouse model for rotating camera

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

IOS - using SCNLookAtConstraint does not seem to work the way I expected

I am learning SceneKit and trying to get the tip of a cone to point at the another node (a capsule) that is bouncing. Regardless of using the .orient on the cone, as soon as the SCNLookAtConstraint call gets made it re-orients the cone to the standard upright position so that the cone tip point straight up along the Y axis again and rock left and right as opposed to pointing its tip to the moving capsule which is to the rightof the cone. I tried changing the .pivot of the cone as well but that just seems to change the anchor point of the pivot but does not change the orientation of the cone.I need something like a SCNLookAtConstraint that indicates what point of the cone looks at the capsule?
Thanks
the pivot property is the way to go. It allows you to change the anchor point, but also its orientation since its a transform.

Make a SCNNode drop using gravity?

I have a SceneKit setup and have one Sphere in it that is setup as a Dynamic body.
I am able to run the app and see the sphere drop on the static body floor.
What I am trying to do is setup the scene so the sfere initially does not drop.
Then when a function is run I want the sfere to drop.
what is the correct logic / steps to make the scene suddenly (maybe when a button is pressed or something) drop the sphere?
I have tried also to set the sphere to mass 0 and then set the mass to 100 but it does not cause the drop...
Mass doesn't control how fast something falls. This is true in the real world, but more so in simulations that take shortcuts instead of simulating every detail of real-world physics. (Sadly, iOS devices still don't have the CPU power to account for the rotating reference frame of the Earth, the Van der Waals attraction between your sphere and any body especially close to it, the strong force that keeps its triangles atoms together, etc etc.) In SceneKit, gravity is just a constant acceleration in a specific direction.
Setting mass to zero and switching it to something else interferes with the distinction between static/kinematic and dynamic bodies... so don't do that.
As #mnuages notes, you can add/remove the physics body from your sphere when you want it to be affected or unaffected by physics entirely.
But what if you want to keep the sphere's physics body for other reasons—such as allowing other bodies to collide with it even before you make it start falling? There are a few approaches you could use for that:
Set the sphere body's damping to 1.0.
Set the sphere body's velocityFactor to zero (at least in the direction of gravity).
Both of those will keep the sphere from moving when something else hits it. If you want the ball to get knocked around, but not be affected by gravity, the best thing to do might be to switch out scene gravity for physics fields:
Set scene.physicsWorld.gravity to SCNVector3Zero.
Add a SCNPhysicsField created with the linearGravityField constructor to your scene, and set its direction and strength to get the kind of gravity behavior you want.
Set the categoryBitMasks on both your sphere body and the gravity field such that the field affects other bodies but not the sphere.
Whichever of these methods you use, you can change them when you want to "turn gravity on" for the sphere: reduce the damping, reset the velocityFactor, or change the sphere's or the gravity field's categoryBitMask.
As of iOS 9, you can set the isAffectedByGravity property to false then flip the value to true to make the sphere drop: https://developer.apple.com/reference/scenekit/scnphysicsbody/1514738-isaffectedbygravity
setting a physics body to sphere only when you want to it to be affected by gravity should work.

CC3Node rotation - Cocos3d

I am developing an iPhone application that uses Cocos3d. I have drawn a scene in the XZ plane ( y = 0 ). Now, I want to rotate the scene around a specified point in the XZ plane, whenever the user touches the screen with two fingers; the rotation point will be the center of the two touch points.
I started by projecting the two touch points to the 3D scene, by finding the intersecting between the CC3Ray (issued from the camera and passing by the touch point) and the XZ plane.
Now that I have the two points in the XZ plane, I can calculate the rotation point (that will be the middle point between these two points).
In order to rotate the scene around this point, I have added it to a parent node. Now all I have to do is to translate it by the negation of the coordinates of the middle point, rotate its parent by the angle, and translate it back by the coordinates of middle point.
Here is the code that I am using (in the ccTouchesMoved method):
// Assuming that the root is a CC3Node and it is the scene that I need to rotate
// and middle refers to the center of rotation
[root translateBy:cc3v(-middle.x, 0, -middle.z)];
[root.parent rotateByAngle:30 aroundAxis:cc3v(0, 1, 0)];
[root translateBy:cc3v(middle.x, 0, middle.z)];
However, I am not able to rotate the scene around the middle point.
Can anyone help me to resolve this problem?
Thank you!
Edit:
I also tried to add these lines of codes in the ccTouchesBegan method:
[root translateBy:CC3VectorNegate(middle)];
[self.cc3Scene.activeCamera translateBy:CC3VectorNegate(middle)];
And in the ccTouchesMoved:
[root rotateByAngle:angle aroundAxis:cc3v(0, 1, 0)];
It works only for the first time the user touches the screen, and then, whenever he/she touches it again, a unwanted translation is happening!
I think the problem is with the ccTouchesBegan method.
On any one node, rotation, translation, and scale transforms are independent of each other. They are each applied to the rest pose of the node, and are not accummulative with each other. This is so that interaction appears natural and expected by the developer controlling the node. In other words, during gameplay, rotating a character after it has been moved, rotates the character in place, not around a translated location. Similarly, translating a node translates it regardless of how the node has previously been rotated.
This is different control than taking a single matrix and accumulating transforms into it, which is how the matrix-based rotate-around-a-distant-point technique works.
However, you can effectively rotate a node around a location that is not its origin by:
Transforming the local rotation location to the global coordinate space.
Rotating the node as normal.
Transforming the (now rotated) local rotation location to the global coordinate space.
Align the rotation locations found in steps 1 & 3 by translating the node by the difference between the two locations.
You can perform steps 1 & 3 using the node's globalTransformMatrix. Code for the steps above is as follows:
CC3Vector gblRotLocBefore = [aNode.globalTransformMatrix transformLocation: rotationLoc];
[aNode rotateByAngle: angle aroundAxis: kCC3VectorUnitYPositive];
CC3Vector gblRotLocAfter = [aNode.globalTransformMatrix transformLocation: rotationLoc];
[aNode translateBy: CC3VectorDifference(gblRotLocBefore, gblRotLocAfter)];
Using this technique, you do not need to involve the node's parent.

Resources