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.
Related
I am attempting to render the reflection of some water.
To create the illusion of reflection, I need the camera to be below the water:
(Pictures not drawn by me)
Therefore, I need to move the camera under the water before rendering the scene. I need to move the camera downward by the distance from the camera to the water multiplied by two, and then I need to invert the cameras' pitch.
The problem is that I am currently limited to the fixed-function pipeline to do this, meaning that I must use glTranslatef() and glRotatef() calls to do this.
Here's my current implementation:
public void createReflectionTexture(){
EulerCamera c = Main.TerrainDemo.camera; //This is the camera
float amtDown = -(2f * (c.y() - 300)); //Amount to move the camera down by. 300 is the height of the water.
float amtPit = (-(c.pitch() * 2));//Pitch to invert the camera by
glRotatef(-amtPit, 0, 0, 1); //I have tried both negative and positive values here, neither seem to work.
glTranslatef(0, amtDown, 0);
bindArrays();
fbos.bindReflectionFrameBuffer();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Main.TerrainDemo.renderVBOTerrain();
fbos.unbindCurrentFrameBuffer();
unBindArrays();
glTranslatef(0, -amtDown, 0); /This puts things back to their original translation so I can keep on rendering other objects.
glRotatef(amtPit, 0, 0, 1);
}
Unfortunately, in my game, the code creates a completely messy image which definitely is obviously not the correct reflection:
If I crash my plane into the water and then position the cameras' pitch to 0, it does appear to render the correct objects.
The refraction texture renders perfectly fine.
How can I correctly move the camera below the water to create a scene that looks like reflection when viewed from above?
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);
I'm sure this is something very simple. I am having a major brain freeze. I have been inverting it, subtracting from it, multiplying to it, adding to it. No matter what up is down and down is up.
if (Gdx.input.isButtonPressed(Buttons.LEFT)) s.drawCirc(c, Gdx.input.getX(), Gdx.input.getY(), 100, 100);
The x axis is fine the culprit is the Gdx.input.getY(). When I move my finger up it goes down and down it goes up.
My circle lines up in the middle but when I go up it goes down and when I go down it goes up. I would like to understand what exactly is going on here and why it is happening.(& of course how to fix it please)
In case you need to know c is my camera and here is the code in case this is the culprit
c = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
and in my drawCirc method I am using
shapeRenderer.setProjectionMatrix(c.combined);
This is because the coordinate system used for input and the coordinate system used by the camera are opposite of each other on the y axis. Ideally when getting inputs, you want to unproject the input to the camera so that all of the coordinates are nicely aligned. You can do this using c.unproject(input). Here's a code example:
if (Gdx.input.isButtonPressed(Buttons.LEFT))
{
Vector3 input = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
cam.unproject(input);
//Now you can use input.x and input.y, as opposed to Gdx.input.getX() and
//Gdx.input.getY(), to draw the circle
s.drawCirc(c, input.x, input.y, 100, 100);
}
LibGDX uses OpenGL which uses another coordinate system.
It uses left to right, bottom to top.
So in OpenGL 0,0 means bottom left corner.
Use
c = new OrthographicCamera();
c.setToOrtho(true, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
First parameter means Y-Down
More information here: http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/OrthographicCamera.html
Check this link for more information about using LibGDX with down-y.
https://github.com/libgdx/libgdx/blob/master/tests/gdx-tests/src/com/badlogic/gdx/tests/YDownTest.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.
I'm creating a 3D renderer in Java, which currently can render the wireframe of a cube using Points and lines and rotate the cube, the question is, what should Z be? And what should be set to Z? I'm guessing that the size of the cube should be set to Z?
Thanks for your time! Any answers would be much appreciated.
Z usually means the out-of-plane direction if the current viewport lies in the x-y plane.
Your 3D world has its own coordinate system. You'll transform from 3D world coordinates to viewport coordinates when you render.
I think you might be missing some basic school math/geometry here. However, it's actually not that hard to understand.
Imagine a flat plane, e.g. a sheet of paper.
The first coordinate axis will go straight from left to right and we'll call it X. So X = 0 means your point is on the left border. X = 10 might mean your point is on the right border (really depends on how big you define a unit of 1; this could be in centimeters, inches, etc.). This is already enough to describe some point in one dimension (from left to right).
Now, we need a second axis. Let's call it Y. It's running from the top border (Y = 0) to the bottom (Y = 10). Now you're able to describe any point on the plane as you've got two positions. For example, (0, 0) would be the top left corner. (10, 10) would be the bottom right corner. (5, 0) would be the center point of the top border, etc.
What happens if we add yet another dimension? Call it Z. This will essentially be the height of your point above the sheet. For example, Z = 0 could mean your point is sitting on the sheet of painter, while Z = 10 means your point is sitting 10 cm above the paper. Now you use three coordinates to describe a point: (5, 5, 0) is the center of the paper. (5,5,5) is the center of the cube sitting on your paper filling it and being 10 cm high.
When programming in 3D, you can use the same terminology. The only real difference is, that you're using a so called projection/view matrix to determine how to display this 3d positions on screen. The easiest transform could be the following matrix:
1 0 0
0 1 0
Multiplying this with your 3d coordinates you'll get the following two terms:
2d-x = 3d-x
2d-y = 3d-y
This results in you viewing the cube (or whatever you're trying to display) from straight above essentially ignoring the Z axis again (you can't render something sticking out of your display, unless using some kind of 3d glasses or similar technology).
Overall, it's up to you how you use the coordinates and interpret them. Usually x and y refer to the plane (position on the ground or position inside a 2D world) while z might be the height or the depth (front or back). It really depends on the specific case. But in generic, it's really just another dimension like x and y.
3D means 3 "Dimensions". One dimension is "X", the other "Y", the third "Z". None have a sepcific direction, though it's convenient to conventionally assign a direction, for example "Forward", "Left", and "Up".
Something whose X, Y, and Z values are all equal to 0 resides at the origin, or center of the space. You can write this as (0,0,0) where the order of the parameters are (x,y,z).
A point or vertex at the location (1,0,0) is one unit in the X direction from the origin. So if you moved from (0,0,0) to (1,0,0), you would be moving purely in the X direction.
(0,1,0) is one unit in the Y direction away from the origin.
(0,0,1) is one unit in the Z direction away from the origin.
(1,1,0) is one unit in the X direction and one unit in the Y direction. So if X means "Forward", and Y means "Left", then (1,1,0) is forward-and-left of the origin.
So a basic cube can be defined by the following vertices:
(1,1,-1)
(1,-1,-1)
(-1,1,-1)
(-1,-1,-1)
(1,1,1)
(1,-1,1)
(-1,1,1)
(-1,-1,1)