I have a planeNode in a SceneKit Scene which I want to control. For this I want to constantly update the Orientation. Due to the Singularities of Euler Angles I am using Quaternions. So far I am directly updating planeNode.orientation and it works fine. The only issue is that due to the update rate it slightly jumps between orientations, which does not look very nice. I tried using SCNActions but the problem is I can only rotateTo and rotate by Euler Angles. Is there any way to rotateTo Quaternions?
Any help is very welcome! Thanks!
I solved it by up using sims_slerp and therefore not updating the orientation directly to the new set point orientation but rather to a part of it:
let qSlerp = simd_slerp(simd_quatf(quat: self.planeNode.orientation), self.orientationSP!, 0.1)
// UPDATE ORIENTATION TO CLOSEST INTERPOLATION
self.planeNode.orientation = SCNQuaternion(simd_quat: qSlerp)}
Related
I'm trying to have a model rotate 90 degrees when a button is pressed - should be simple, right?
Well, the entire system is a buggy mess for some odd reason. I would appreciate some help fixing it
transform.parent.rotation = Quaternion.Euler(transform.parent.rotation.x, transform.parent.rotation.y , transform.parent.rotation.z);
Instead, the model just rotates in random directions that seem like they shouldn't at all be related to my code.
I started up the game to rotate the model while it's in play-mode, but the way it rotates seems like it just suddenly changes out of the blue.
I'm really confused by this & would appreciate some help in fixing it
You code doesnt work like your think.
Quaterinion.Euler expects input in the form of Euler angles, but you are inputing the (x,y,z) of a Quaterinon which consists of (x,y,z,w) which is why you get really funky rotation.
https://docs.unity3d.com/ScriptReference/Quaternion.html
To get the current Euler Angles of your transform, simply use transform.eulerAngles (or in your case, transform.parent.eulerAngles)
var euler = transform.parent.eulerAngles;
transform.parent.rotation = Quaternion.Euler(euler.x, euler.y, euler.z);
However this doesnt change the rotation in anyway.
If you want to rotate 90 degrees around the Y-axis, you could add 90 like this
var euler = transform.parent.eulerAngles;
transform.parent.rotation = Quaternion.Euler(euler.x, euler.y+90, euler.z);
An even simpler way to rotate 90 degrees around Y is ofcourse
transform.Rotate(0, 90, 0);
Question Is there a way to use constraints to smooth the motion of the camera?
Detail I recently read a post about smoothing camera motion using linear interpolation (lerp) and it made me wonder if I could achieve a similar effect using constraints.
One promising option I saw in the documentation was distance(_: SKRange, toNode: SKNode) but after some experimentation, the results aren't at all what I was hoping for. I've tried using a constant value and the upper limit/lower limit range without success.
Here is the code that keeps the camera centered on a sprite:
let cameraRange = SKRange(constantValue: 0.0)
let heroLocationConstraint = SKConstraint.distance(cameraRange, toNode: hero)
I can imagine a set of constraints that would have to be enabled/disabled based on the player's y position, but that hardly seems like the best way to go. What would be really great is a node tracking variable that implements lerp automatically!
I have a UIImageView that is set to move up and down the screen with the value of the accelerometer, using the following code:
ship.center = CGPointMake(ship.center.x, ship.center.y+shipPosition.y);
Where shipPosition is a CGPoint set in the accelerometerDidAccelerate method using:
shipPosition.y = acceleration.x*60;
Obviously this works fine, it is very simple. I run into trouble when I try to something equally simple, vary the rotation of the image depending on its acceleration. I do this using:
ship.transform = CGAffineTransformMakeRotation(shipPosition.y);
For some reason this causes a very strange thing to happen, in that the image snaps back to its origin every time the main method is called. I can see frames where the image moves to where it should be, but then instantly snaps back.
This problem only happens when I have the rotation line in, commented out it works fine. I have no idea what is going on here, I have done this many times for different apps and i never had such a problem. In fact I copied my code from a different app I created where it works fine.
EDIT:
What really confuses me is when I change the angle of the rotation from the acceleration to the position of the ship using:
ship.transform = CGAffineTransformMakeRotation(ship.center.y/10);
When I do this, the ship actually rotates based on the accelerometer but does not move, which is crazy because a changing ship.center.y means the position of the ship is changing, but it's not!!
You should set the transform of you view back to CGAffineTransformIdentity before you set his center coordinates or frame and after that apply the new transformation.
The frame property returns the transformed coordinates of a view if it is transformed and not the true (well actually the transformed are true) coordinates.
Quote from the docs:
Warning: If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored.
Update/Actual Answer:
Well the actual problem is
shipPosition.y = acceleration.x*60;
Since you set the y pos in accelerometerDidAccelerate.
The acceleration won't remember it's old value. So if you move your device it will get a peak and as you slow down it will decelerate again.
Your ship will be +/-60 at the highest acceleration speed but will be 0 when you stop moving your device and shipPosition.y will be 0.
CGAffineTransformMakeRotation expects angle in radians, not in degrees.
1 radian = M_PI / 180.0 degrees
Is there a way to obtain a relative rotation from core motion?
What I need is: how much it rotated in one axis and which direction (+ sign = anti-clockwise, - = clockwise, according to the right-hand rule).
I have found the property rotationRate, but I am now sure how I would extract the angle out of it, as this is giving me radians per second.
I have done all kind of stuff on the last days but nothing is giving me stable values. I have tried to do a timed sample of core motion data, using a NSTimer and calculate the difference between two samples, so I would have how much it rotated since the last sample, but from times to times it gives me crazy numbers like 13600 degrees even when the iPhone is resting on the table.
Any thoughts on how this can be accomplished?
thanks
There is indeed. You can get what you're looking for by drilling down into the properties of CMMotionManager, through CMDeviceMotion and finally to CMAttitude. The attitude of the device is defined as:
the orientation of a body relative to
a given frame of reference.
In the case of DeviceMotion's CMAttitude, that frame of reference is established by the framework when starting device motion updates. From that point in time on, the attitude of the device is reported relative to that reference frame (not relative to the previous frame).
The CMAttitude class provides some handy built in functionality to convert a CMAttitude to a form that is actually useful for something, like Euler Angles, a rotation matrix, or a quaternion. You sound like you're looking for the Euler Angle representation (Pitch, Yaw, Roll).
The answer provided above isn't quite accurate, though it's probably sufficient to answer this question. Core Motion tries to determine the device's absolute attitude at all times, meaning that the definition of the axes can vary depending on the device's orientation. For example, if the device is face-up, then pitch up/down is a rotation about the y-axis, but if the device is in landscape orientation, then pitch is a rotation about the z-axis (perpendicular to the plane of the screen). This is somewhat helpful if your application will only be used in one orientation, or you want a delta like the question asked for, but makes it excessively complicated if you want to know absolute orientation.
I'm trying to use an iPhone/iPod acceleration to manipulate directly a 3D object.
For that I've been searching lot's of stuff (Euler angles, Quaternions, etc).
I'm using OpenSG, where I have a 3D environment and want to manipulate a certain object (just rotating in all possible iPhone/iPod degrees of freedom using only accelerometer).
So, I tried to figure it out a solution for this problem but it still doesn't have the expected result and get some weird rotations in some angles.
Can someone tell me what I'm doing wrong? Or, is there a better way of doing this without using quaternions?
The acceleration variable is a Vec3f containing the accelerometer values from iPhone/iPod filtered with a low-pass filter.
acceleration.normalize();
Vec3f reference = OSG::Vec3f(0, 0, 1);
OSG::Vec3f axis = acceleration.cross( reference );
angle = acos( acceleration.dot( reference ) );
OSG::Quaternion quat;
quat.setValueAsAxisRad(axis, angle);
After this code, I update my scene node using quaternion quat.
I wanted to do the exact same thing and just tried it, I hadn't played around with an accelerometer before and it seemed like it should be possible.
The problem is that if you set your iPhone on a table and then slowly spin it around and observe the output of the accelerometer it basically doesn't change (one gravity down). If you tilt it up/down on any of the four edges you will see the output change.
In other words you know that your table top is tilting top/bottom or left/right, but you can't tell that you are spinning it. So you can map this tilt to two rotations of a 3D object.
You could probably use the compass for the horizontal rotation, I couldn't try because I was prototyping in the Unity Game Engine and it doesn't seem to support compass yet.
The ever wonderful Brad Larson posted an excellent description of his initial experiences of a 3d viewer while writing his Moleculs app.
His method for rotations was achieved as follows:
GLfloat currentModelViewMatrix[16];
glGetFloatv(GL_MODELVIEW_MATRIX, currentModelViewMatrix);
glRotatef(xRotation, currentModelViewMatrix[1], currentModelViewMatrix[5], currentModelViewMatrix[9]);
glGetFloatv(GL_MODELVIEW_MATRIX, currentModelViewMatrix);
glRotatef(yRotation, currentModelViewMatrix[0], currentModelViewMatrix[4], currentModelViewMatrix[8]);
but whether or not this is helpful I can't recommend this blog entry enough Brad learns a lesson or two
Editing to add that I may have misread the question, but will keep the post here as it will likely help people searching with similar keywords.