Relative 3D rotation change according to current rotation - java

I rotate an object in 3D space in XYZ by 90 degree steps, (rX rY rZ). The angle's are limited to 0-360 degree and I use the following commands for rotating the matrix:
Matrix.rotateM(mRotationMatrix, 0, rX, 1.0f, 0.0f, 0.0f);
Matrix.rotateM(mRotationMatrix, 0, rY, 0.0f, 1.0f, 0.0f);
Matrix.rotateM(mRotationMatrix, 0, rZ, 0.0f, 0.0f, 1.0f);
To figure out in what direction the up, right and away of the object ended up after the rotation I simply parse the 3x3 upper left of the rotation matrix. That works great by reading:
mRotationMatrix[0], mRotationMatrix[1], mRotationMatrix[2]
mRotationMatrix[4], mRotationMatrix[5], mRotationMatrix[6]
mRotationMatrix[8], mRotationMatrix[9], mRotationMatrix[10]
From here I need to figure out how I can update rX, rY, rZ using four different formulas|commands|functions where each rotates the object along the resulting X and Y axis back and forward. Imagine like if the four commands can push the object at four directions and the object will "roll" 90 degree in that direction.
I have no other information and can only manipulate the rX, rY and rZ rotation variables. I must not add a fourth rotation to the result. Somehow I must calculate what change to rX, rY and rZ respectively will have the same effect on the resulting rotation matrix independently of what the rX, rY and rZ already are set to.
I can't figure the maths out. Knowing what side of the object is currently pointing up isn't enough since it can be rotated in four different directions and still have the same side up, etc. Even if I know exactly in what directions the six sides of the object is pointing I still can't figure out what of the rX, rY or rZ I should manipulate to achieve the rotation.
I am starting to lean towards creating a hardcoded lookup-table for all possible combinations, but I really want to avoid that (I guess that would be 4*4*4*4, where the last four is the "roll" direction).
Another way of seeing it is instead of thinking of rolling the top side 90 degrees to any of the four sides facing left, right, away or near one can say that I need to figure out how I can manipulate rX, rY and rZ to rotate any of the sides of the object, except for up or down, to the top side. I hope that explains what my goal is.

Related

Misunderstanding of multiplyMV - OpenGL ES 2.0

I wrote a simple program using OpenGL ES 2.0 and Java for Android.
This program draw a point in a random position on the screen using an ortho projection matrix, view matrix and a model matrix. In the shader I put matrix * position.
All works well, but then I tried, for testing purpose, to calculate the position of the point by myself, so I used multiplyMV and as arguments I put my MVPmatrix (obtained by using multiplyMM before between projection and view and then between the result and the model matrix) and my point (for example 2f, 3.5f, 0f, 1f). The problem is that sometimes the result I get for x and/or y is greater than 1 or smaller than -1, despite the fact that the point is on the screen. But in normalized device coordinates the point must have a range between -1 and 1 in order to be "on screen".
I really don't understand where is my mistake.
The point has to be in normalized device space [-1, 1] (for x, y, z), after the projection matrix is applied.
But note the point may be a Homogeneous coordinate. This means you have to do a Perspective divide first.
The projection matrix describes the mapping from 3D points of a scene, to 2D points of the viewport. The projection matrix transforms from view space to the clip space. The coordinates in the clip space are transformed to the normalized device coordinates (NDC) in the range (-1, -1, -1) to (1, 1, 1) by dividing with the w component of the clip coordinates.
Clip space coordinates are Homogeneous coordinates. In clipspace the clipping of the scene is performed. A point is in clip space if the x, y and z components are in the range defined by the inverted w component and the w component of the homogeneous coordinates of the point:
-p.w <= p.x, p.y, p.z <= p.w.
The clip coordinates are transformed to the normalized evice coordiantes by doing the Perspective divide:
ndc.xyz = (p.x/p.w, p.y/p.w, p.z/p.w)

LWJGL First Person Camera Rotation

I have run into a problem making a first person camera on LWJGL 2. I am using the following code to rotate the camera (up down left and right) based on how the mouse moves. This is basically what every other tutorial has, however, its movement is flawed and ends up spiraling out of control.
float mouseDX = Mouse.getDX();
float mouseDY = Mouse.getDY();
rotation.x = mouseDX;
rotation.y = mouseDY;
glRotatef(rotation.y, 1, 0, 0);
glRotatef(rotation.x, 0, 1, 0);
Rotation is a Vector3f
I am aware that the rotation.y is rotating the x access and the x is rotating the y. I am not totally sure why but it doesn't work for me unless its this way. The problem may be related to this.
Here is a video I made showing what I mean:
https://www.youtube.com/watch?v=V6Iu5oQuWo4&feature=youtu.be
In the video I attempt to show that both the x and y rotation work fine separately, but when used together they don't work at all.
I know this is only a small section of my code, but it is the only part dealing with rotation so the problem must be there somewhere.
The flaw that stands out to me is the value by which you rotate.
Mouse.getDY returns the change in y pixels so if you move your mouse half way down the screen you will move typically 300 pixels (800x600).
Now you also have glRotatef which rotates by radians which compared are tiny compared to degrees.(360 degrees -> 6.28 radians)
Now take 300 hundred pixels, use it as the number of radians to rotate by and you get 17188.7 degrees of rotation.
And that's the cause of your spiralling (47 revs/few milliseconds)
What you will need to do if divide your dy and dx by a good couple of hundred.
And you can also still use degrees by using Math.toRadians in the glRotatef method

Calculate object XYZ orientation after XYZ-rotation

I rotate an object in 3D space in XYZ by 90 degree steps, (rX rY rZ). The angle's are limited to 0-360 degree and I use the following commands for rotating the matrix:
Matrix.rotateM(mModelMatrix, 0, rX, 1.0f, 0.0f, 0.0f);
Matrix.rotateM(mModelMatrix, 0, rY, 0.0f, 1.0f, 0.0f);
Matrix.rotateM(mModelMatrix, 0, rZ, 0.0f, 0.0f, 1.0f);
If the XYZ of the object - before rotation - is right (X+), away (Y+) and up (Z+); How can easily calculate what is right, away and up after an arbitrary rotation?
I have no other information but the rX, rY and rZ rotation variables.
When having a matrix it might make most sense to multiply the base vectors with the same matrix to get transformed vectors. For instance if you are looking for a vector facing from object toward (0,0,1) respecting its internal coordinate system you would first transform the origin (0,0,0) with this matrix to get the new center and then transform the target vector (0,0,1) with the same procedure. The result is then target-origin. This procedure will work for any system and any combination you need but you do need to watch out what matrix you are multiplying with as in most cases the projection should not be included.
Another interesting solution for your specific case might be simply looking at the matrix base vectors. The top-left 3x3 part of the matrix actually represents the 3 axis for x, y and z. So identity is x=(1,0,0), y=(0,1,0), z=(0,0,1). Once rotated or scaled these values will change and can be accessed directly from the matrix.

Rotation in OpenGl ES to place objects then rotate the world

I am developing an augmented reality application for android and trying to use openGl to place cubes at locations in the world. My current method can be seen in the code below:
for(Marker ma: ARData.getMarkerlist().values()) {
Log.d("populating", "");
gl.glPushMatrix();
Location maLoc = new Location("loc");
maLoc.setLatitude(ma.lat);
maLoc.setLongitude(ma.lng);
maLoc.setAltitude(ma.alt);
float distance = currentLoc.distanceTo(maLoc);
float bearing = currentLoc.bearingTo(maLoc);
Log.d("distance", String.valueOf(distance));
Log.d("bearing", String.valueOf(bearing));
gl.glRotatef(bearing,0,0,1);
gl.glTranslatef(0,0,-distance);
ma.cube.draw(gl);
gl.glPopMatrix();
}
gl.glRotatef(y, 0, 1, 0);
gl.glRotatef(x, 1, 0, 0);`
Where y is yaw and x is the pitch. currently I am getting a single cube on the screen at a 45 degree angle someway in the distance. It looks like I am getting sensible bearing and distance values. Could it have something to do with the phones orientation? If you need more code let me know.
EDIT: I updated bearing rotation to gl.glRotatef(bearing,0,1,0); I am now getting my cubes mapped horizontally along the screen at different depths. Still no movement using heading and pitch but #Mirkules has identified some reasons why that might be.
EDIT 2: I am now attempting to place the cubes by rotating the matrix by the difference in angle between heading and bearing to a marker. However, all I get is a sort of jittering where the cubes appear to be rendered in a new position and then jump back to there old position. Code as above except for the following:
float angleDiff = bearing - y;
gl.glRotatef((angleDiff),0,1,0);
gl.glTranslatef(0,0,-distance);
bearing and y are both normalised to a 0 - 360 scale. Also, I moveed my "camera rotation" to above the code where I set the markers.
EDIT 3: I have heading working now using, float angleDiff = (bearing + y)/2;. However, I cant seem to get pitch working. I have attempted to use gl.glRotatef(-x,1,0,0); but that doesn't seem to work.
It's tricky to tell exactly what you're trying to do here, but there are a few things that stick out as potential problems.
Firstly, your final two rotations don't seem to actually apply to anything. If these are supposed to represent a movement of the world or camera (which mostly amounts to much the same thing) then they need to happen before drawing anything.
Then your rotations themselves perhaps won't entirely do what you intend.
Your cube is rotated around the Z axis. The usual convention in GL is for the camera to look down the Z axis, with the Y axis being considered 'up'. You can naturally interpret axes however you like, but a rotation around 'Z' would not typically be 'bearing', but 'roll'. 'Bearing' to me would be analogous to 'yaw'.
As you translate along the Z axis, I assume you are trying to position the object by rotating and translating, but obviously if the rotation is around the same axis as you translate along, it won't actually alter the position of the cube - it will always just be directly in front of the camera, spinning on its axis.
I'm not really clear on why you're trying to position the cube like that when it seems like you start off with a more specific location. You could probably directly construct a more appropriate matrix.
Finally, your camera/world rotation is two concatenated rotations around Y and X. You call these pitch and roll, but typically using euler angles for a camera rotation does not result in an intuitive result where terms like pitch and roll make complete sense. It is common to maintain an orientation and apply individual rotations to that in order to update it, rather than attempting to update several dependent rotations.
So yes, I would expect that this code, in the absence of other matrix operations, would likely result in drawing one or more cubes straight ahead which are simply rotated by some angle around the view direction.

Rotating quaternions based on mouse movement (OpenGL and Java)

I'm writing a game in Java using OpenGL (the LWJGL binding, to be specific). Each entity, including the camera, has a quaternion that represents it's rotation. I've figured out how to apply the quaternion to the current OpenGL matrix and everything rotates just fine. The issue I'm having is getting the camera to rotate with the mouse.
Right now, every frame, the game grabs the amount that the mouse has moved on one axis, then it applies that amount onto the quaternion for the camera's rotation. Here is the code that rotates the quaternion, I'll post it since I think it's where the problem lies (although I'm always wrong about this sort of stuff):
public void rotateX(float amount){
Quaternion rot = new Quaternion(1.0f, 0.0f, 0.0f, (float)Math.toRadians(amount));
Quaternion.mul(rot, rotation, rotation);
rotation.normalise();
}
This method is supposed to rotate the quaternion around the X axis. 'rotation' is the quaternion representing the entity's rotation. 'amount' is the amount that I want to rotate the quaternion (aka the amount that the mouse was moved). 'rot' is a normalized vector along the X axis with a w value of the amount converted to radians (I guess the goal here is to give it an angle- say, 10 degrees- and have it rotate the quaternion along the given axis by that angle). Using Quaternion.mul takes the new quaternion, multiplies it by the rotation quaternion, and then stores the result as the rotation quaternion. I don't know if the normalization is necessary, since 'rot' is normal and 'rotation' should already by normalized.
The rotateY and rotateZ methods do the same thing, except for changing the vector for 'rot' (0.0, 1.0, 0.0 for y and 0.0, 0.0, 1.0 for z).
The code appears to work fine when the game starts and the camera is looking down the negative Z axis. You can spin all the way around on the Y axis OR all the way around the X axis. But as soon as you try to rotate the camera while not looking down the Z axis, everything gets really screwy (I can't even describe it, it rotates very oddly).
My end goal here is to have something to use for controlling a ship in a space with no up vector. So when you move the mouse on the Y axis, no matter what angle the ship is at, it changes the pitch of the ship (rotation along the X axis). Similarly, when you move the mouse on the X axis, it changes the yaw (rotation along the Y axis). I might be going about this the wrong way and I probably just need a push (or shove) in the right direction.
If you need more details on anything (how my rendering is done, any other maths that I'm trying to do) just ask and I'll put it up. I understood everything when I was using euler angles (which apparently are a big no-no for 3D application development... wish somebody would have told me that before I sunk a lot of time into getting them to work) but as soon as I switched over to quaternions, I got in over my head really fast. I've spent the past few months just playing with this code and reading about quaternions trying to get it to work, but I haven't really gotten anywhere at all :'(
Very, very frustrating... starting to regret trying to make something in 3D >_<
Quaternion rot = new Quaternion(1.0f, 0.0f, 0.0f, (float)Math.toRadians(amount));
OK, this is flat-out wrong.
The constructor that takes four floats assumes that they represent an actual quaternion. What you give that constructor is not a quaternion; it's a vec3 axis and an angle that you expect to rotate around.
You can't shove those into a quaternion class and expect to get a legitimate quaternion out of it.
Your quaternion class should have a constructor or some other means of creating a quaternion from an angle and an axis of rotation. But according to the documentation you linked to, it does not. So you have to do it yourself.
A quaternion is not a vec3 axis with a fourth value that is an angle. A unit quaternion representation a change in orientation is a vec3 that is the axis of rotation * the sine of half of the angle of rotation, and a scalar component that is the cosine of half the angle of rotation. This assumes that the angle of rotation is clamped on the range [-pi/2, pi/2].
Therefore, what you want is this:
float radHalfAngle = ... / 2.0; //See below
float sinVal = Math.Sin(radHalfAngle);
float cosVal = Math.Cos(radHalfAngle);
float xVal = 1.0f * sinVal;
float yVal = 0.0f * sinVal; //Here for completeness.
float zVal = 0.0f * sinVal; //Here for completeness.
Quaternion rot = new Quaternion(xVal, yVal, zVal, cosVal);
Also, converting amount to radians directly doesn't make sense, particularly so if amount is just a pixel-coordinate delta that the mouse moved. You need some kind of conversion scale between the distance the mouse moves and how much you want to rotate. And toRadians is not the kind of scale you want.
One more thing. Left-multiplying rot, as you do here, will perform a rotation about the camera space X axis. If you want a rotation about the world-space X axis, you need to right-multiply it.

Categories

Resources