Rotation in OpenGL ES - java

I am trying to rotate a sphere continuously on a given axis using this code:
gl.glRotatef(axisX, 0, 1, 0);
gl.glRotatef(axisY, 0, 0, 1);
axisX = (axisX+1)%360;
axisY = (axisY+1)%360;
The variables axisX and axisY are both being incremented by one right now which would make the rotation go in a diagonal direction up to the right. The object gets to about 45 degrees of rotation and then start to turn and start rotation the other way. How can I get it to continuously rotate on an axis other than just x and y by themselves?
Note: I am trying to hook up a virtual joystick to control the axisX and axisY values and have the sphere rotate on the axis represented by the joystick. If anyone has any advice on that, that would be great as well.
Edit:
I've change it so that if I use gl.glRotatef(angle, axisX, axisY, axisZ); that it works and keeps the rotation going, but the rotation isn't smooth, it looks like the rotation starts over when I switch the rotation axis.

glLoadIdentity(); // Reset rotation and give a new one
glRotatef(theta[0],1.0,0.0,0.0);
glRotatef(theta[1],0.0,1.0,0.0);
The first argument is the angle, then the axis you want to pivot around.
About your edit: Looks like you are mixing axis and angles here. The axis should a unit length vector and the angle go from 0 to 2*PI.
Another way would be to use quaternions, then transform the quaternion to matrix and load the matrix as your current modelview matrix.
Hope that helps.

Related

3D rotation ratios via mouse placement on screen - Java

I am making a 3D game in which the player can rotate their view point via the mouse to look around the environment. I firstly just did x and y rotation via vertical and horizontal movement of the mouse and z via another control. But after playing the game I realised it did not rotate correctly. NOTE: I have a global variable matrix which represents the player's angle (3x1), at 0,0,0 it seems to work correctly as up or down is a direct x axis rotation and right or left is a direct y axis rotation, but if I move my camera diagonally for example then left doesn't directly correlate to a y axis rotation anymore.
Visually on a unit circle the players viewpoint wouldn't travel the full circumference anymore and would travel in a circle that is smaller that the circumference. This is the current code (x and yRateOfRot is the ratio of how far away from the centre the cursor is in each direction between -1 and 1):
private static void changeRotation(){
angle.set(Matrix.add(angle.matrix,new double[][]{
{ROTATION_SPEED * camera.xRateOfRot()},
{ROTATION_SPEED * camera.yRateOfRot()},
{ROTATION_SPEED * camera.zRateOfRot()}}));
}
I have looked at this source http://paulbourke.net/geometry/rotate/ and understand how to rotate via an arbitrary axis which I could do but I am not sure how to correlate this into getting a ratio to find out what the x,y and z change would be for looking in a specific direction i.e. at 0,0,0 the ratio of looking up would be x:1, y:0, z:0 but then at another angle the ratios would be different as looking up no longer means only an x rotation. Any information would be appreciated, thanks!

How to map 3D coordinates to 2D plane

I'm writing a OpenGL application in which there is a rectangle placed on a 3D object. The 3D object can move around and rotate and the rectangle follows these movements.
What I would like to do is to point with the mouse towards the rectangle so that a dot would appear in that point on the rectangle, and I want the point to follow it as the 3D object that "holds" the rectangle moves around.
I know how to find the intersection on a plane, and I know how to find the world coordinates of the contact point. What I need is a way to convert the world coordinates to the 2D local coordinate system of the rectangle.
For example, suppose I have the plane positioned like this in the 3D world, with a given orientation (sorry, I can't really draw properly):
The black point in the center is the origin of the plane, while the blue point is the one I would like to find. The numbers near the points are their world coordinates; in this example the Z axis "comes out" of the screen.
I would like to map the coordinates of the blue point in the local coordinate system of the plane, like this:
I know that somehow this shouldn't be hard, but I can't find a way at all. Any hints would be appreciated!
You probably already use a transformation matrix to render the rectangle. If you have the 3D position of the point, just transform it with the inverse transformation matrix and you get a 3D position in the rectangle's space. If the local system is aligned with the rectangle, one of the coordinates should always be zero and you can drop it.
I found what I needed in this post here.
Basically the solution for me is to project the point onto the x and y axis of the local coordinate system of the rectangle.
In pseudo code it's like this:
// I compute the direction that go from the origin of the rectangle to its x axis, in world coordinates, and take the norm; same thing for the y axis
var xDir = Norm(mRectangle.LocalToWorld([1, 0, 0]) - mRectangle.LocalToWorld([0, 0, 0]));
var yDir = Norm(mRectangle.LocalToWorld([0, 1, 0]) - mRectangle.LocalToWorld([0, 0, 0]));
// I compute the dot product
mLocalPosition.x = Dot(xDir, (contactPoint - mRectangle.LocalToWorld([0, 0, 0])));
mLocalPosition.y = Dot(yDir, (contactPoint - mRectangle.LocalToWorld([0, 0, 0])));
// I can now set the position of the point converting the local coordinates found to world coordinates
mPoint.SetPosition(mRectangle.LocalToWorld([mLocalPosition.x, mLocalPosition.y, 0]));

Libgdx sprite rotation causing position offset

Hi I am creating a game for android using the Libgdx framework. I am trying to place a sprite in the middle of the X axis near the top of my screen. I can do this just fine but since the sprite needs to be rotated 90 degrees(to save room on spritesheet) it causes some sort of offset and I don't understand why. I believe it is because of the origin rotation but I have tried setting the origin to the center of the sprite but it still doesn't work as planned. Please can you help me understand why the rotation is causing an offset and how it can be fixed thank you.
regions [1] = new TextureRegion(menu, 395, 0, 115, 320);
logo=new Sprite(regions[1]);// the sprite
logo.setPosition(W/2-logo.getWidth()/2,H*0.95f); //draw right in the middle of X and 95% up Y
logo.rotate(90); //rotate the sprite 90 degrees
logo.setOrigin(logo.getWidth()/2,logo.getHeight()/2); //rotate around the centre of the sprite
logo.draw(spriteBatch); //in render method draw the sprite
You set the origin of the sprite after you rotate it:
logo.rotate(90); //rotate the sprite 90 degrees
logo.setOrigin(logo.getWidth()/2,logo.getHeight()/2); //rotate around the centre of the sprite
you should do it the other way round. First set origin, then rotate:
logo.setOrigin(logo.getWidth()/2,logo.getHeight()/2);
logo.rotate(90);

Position Vector relative to origin

I have a little tech game I am messing around with and I can't figure out the formula to position 1 object given another objects origin.
So I have a Spaceship and a Cannon. I have the game setup to use units, so 1 unit = 16 pixels (pixel art).
Basically my cannon should be placed 0.5625 units on the X and 0 on the Y relative to the origin of the Spaceship, which is located at 0, 0 (bottom left corner).
The cannon should is independent on the angle of the spaceship, it can aim in different directions rather than being fixed to aim the way of the spaceship.
I have it constantly following the cursor, which works fine. Now when I rotate the Spaceship, obviously the origin of the Spaceship is changing in world coordinates, so my formula to place the cannon is all messed up, like so:
protected Vector2 weaponMount = new Vector2();
weaponMount.set(getBody().getPosition().x + 0.5625f, getBody()
.getPosition().y);
Obviously if I position the ship at a 90° angle, X is going to be different and the cannon would be waaaayyy off the ship. Here is a screenshot example of what I mean:
What would be the formula for this? I have tried using cos/sin but that does not work.
Any ideas?
weaponMount.set(0.5625f,0).setAngle(SpaceshipAngle).add(getBody().getPosition());
Where SpaceshipAngle is the angle of your Spaceship.
The origin of the spaceship is the point, arround which the spaceship will rotate and scale (the Texture of it). The position instead is always the lower left corner of the Texture and does not depend on the rotation.
Your problem is, that your offset does not depent on the rotation of your spaceship.
To take care about this rotation you should store a Vector2 offset, which describes your weapons offset (in your case it is a Vector2(0.5625f, 0)).
Next store a float angle describing your spaceships rotation.
Then you can rotate the offset by using: offset.setAngle(rotation).
The last thing is to set the weapons position. The code for this did not change so much:
weaponMount.set(getBody().getPosition().x + offset.x, getBody()
.getPosition().y + offset.y);

Android, calling glRotatef based on geomagnetic sensor

I have an app that renders a cube. I'm kind of new to using openGL for 3d stuff, but essentially what I want is for a corner of my cube to point north at all times, but also orient itself according to the geomagnetic sensor.
That way, when the user has the phone parallel to the ground and faces north, the corner will point "up" on the screen, whereas if the user has the phone upright, the corner will point "away" from the user, toward the back of the phone.
I had no problem writing this in 2d on only one rotational axis so that it would point the corner north if the phone was parallel to the ground.
However, when I made this 3D, two of the axes seem to be working fine, but the axis I worked with the first time doesn't seem to behave the same way.
I use the following code to get the rotation for each:
gl.glPushMatrix();
gl.glTranslatef(0,0,-4);
//get target angle
targetAngle1 = rotationHandler.getRotation1();
targetAngle2 = rotationHandler.getRotation2();
targetAngle3 = rotationHandler.
if (Math.abs(getShortestAngle(targetAngle1, currentAngle)) > 5) //this is to create a 5 degree "dead zone" so the compass isnt shaky
currentAngle1 = (getShortestAngle(currentAngle, targetAngle1) > 0) ?
currentAngle+1f : currentAngle-1f; //increase or decrease the current angle to move it towards the target angle
if (Math.abs(getShortestAngle(targetAngle2, currentAngle2))>5)
currentAngle2 = (getShortestAngle(currentAngle2, targetAngle2) > 0) ?
currentAngle2 + 1f : currentAngle2-1f;
if (Math.abs(getShortestAngle(targetAngle3, currentAngle3))>5)
currentAngle3 = (getShortestAngle(currentAngle3, targetAngle3) > 0) ?
currentAngle3 + 1f : currentAngle3 - 1f;
gl.glRotatef(currentAngle, 0, 0, -4);
gl.glRotatef(currentAngle2, 0, -4, 0);
gl.glRotatef(currentAngle3, -4, 0, 0);
cube.draw(gl);
gl.glPopMatrix();
The calls to glRotatef that use currentAngle2 and currentAngle3 seem to rotate the cube on an axis relative to the cube, while the first call seems to rotate it on an axis relative to the screen. When I comment out any two of the rotation calls, the third works as intended. But I can't seem to figure out how to get them to work together.
---EDIT---
I found that I could get the cube to rotate to almost any position possible even after taking away the first call. So it seems like I'm going to have to come up with an algorithm that will calculate the rotation as appropriate. I honestly don't know if I can do it but I'll post it here if I figure it out.
This might not be the best solution, but it seems to work as long as the phone isn't completely flat.
After changing the model to a rectangular prism, I could approach the problem a little more clearly. I used only the first two axes, and didn't even touch the last axis. I treated the prism like a fighter jet - in order to turn it left or right, I rotated it on its side, then altered the pitch up or down. Then I "un-rotated" it, and altered the pitch again for to point it up or down as appropriate.
public void findTargetRotation(float rotationAngle, float pitchAngle, GL10 gl){
//first, enable rotation around a vertical axis by rotating on frontBack axis by -90 degrees
gl.glRotatef(-90, 0, -4, 0);
//rotate around the leftRight axis by the angle1 amount
gl.glRotatef(rotationAngle, 0,-4,0);
//then rotate on frontBack axis by 90 degrees again, to straighten out
gl.glRotatef(90, 0, -4, 0);
//lastly, rotate around the leftRight axis to point it up or down
gl.glRotatef(pitchAngle, -4, 0, 0);
}
This seems to work as long as pitchAngle isn't extremely close to or equal to 0. So I just added a little more code to treat it like a 2D object if the pitchAngle is really small.
There's probably a better solution but at least this works.

Categories