I'm building a 2D physics engine in Java using OpenGL (from LWJGL) to display the objects. The problem I am having is that the transformation matrices I apply to the frame seem to be getting applied in a different order to what it says that are.
/**
* Render the current frame
*/
private void render() {
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, Display.getDisplayMode().getWidth(), 0, Display
.getDisplayMode().getHeight(), -1, 1);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT);
GL11.glPushMatrix();
GL11.glTranslatef(Display.getDisplayMode().getWidth() / 2, Display
.getDisplayMode().getHeight() / 2, 0.0f);
renderFrameObjects();
GL11.glPopMatrix();
}
public void renderFrameObjects() {
Vector<ReactiveObject> objects = frame.getObjects();
for (int i = 0; i < objects.size(); i++) {
ReactiveObject currentObject = objects.get(i);
Mesh2D mesh = currentObject.getMesh();
GL11.glRotatef((float)(currentObject.getR() / Math.PI * 180), 0, 0, 1.0f);
GL11.glTranslated(currentObject.getX(), currentObject.getY(), 0);
GL11.glBegin(GL11.GL_POLYGON);
for (int j = 0; j < mesh.size(); j++) {
GL11.glVertex2d(mesh.get(j).x, mesh.get(j).y);
}
GL11.glEnd();
GL11.glTranslated(-currentObject.getX(), -currentObject.getY(), 0);
GL11.glRotatef((float)(-currentObject.getR() / Math.PI * 180), 0, 0, 1.0f);
}
}
In renderFrameObjects() I apply a rotation, a translation, draw the object (mesh coordinates are relative to the object's x, y), reverse the translation, and reverse the rotation. Yet the effect it gives when an object rotates (on collision) is similar to when one would apply a translation then a rotation (ie. rotates around a point at a radius). I can't seem to be able to figure this one out having tried various combinations of transformations.
Any help would be appreciated.
That is beacause they are applied to the local coordinate system of the object, not the object itself.
So the rotate rotates the coordinate system and the translation is applied within that rotated coordinate system.
BTW: Don't undo your matrix changes by applying negative transformations. Roundoff error's will accumulate and it probably is also less efficient then using glPushMatrix and glPopMatrix
Related
I am programming a GUI framework in lwjgl (opengl for java). I've recently implemented rounded rectangles by rendering a couple of normal rectangles surrounded by circles. To render the circles I used GL11.GL_POINTS. I now reached the point, where I am trying to implement animations and for a window open animation, I decided to GL11.glScaled() it from small to normal. That works fine, but unfortunately my circles don't get resized.
I tried changing my GL_POINTS circle render method against a method that uses TRIANGLE_FANs and that worked fine. My problem there was, that the circles didn't look smooth and round at all and if I increase the rendered triangles it starts to lag very quick. Even though my computer isn't bad at all.
This is the code I've used to render circles with GL_POINTS.
GL11.glEnable(GL11.GL_POINT_SMOOTH);
GL11.glHint(GL11.GL_POINT_SMOOTH_HINT, GL11.GL_NICEST);
GL11.glPointSize(radius);
GL11.glBegin(GL11.GL_POINTS);
GL11.glVertex2d(x, y);
GL11.glEnd();
GL11.glDisable(GL11.GL_POINT_SMOOTH);
This is the code I've used to scale the circles
GL11.glPushMatrix();
GL11.glTranslated(x, y, 0);
GL11.glScaled(2.0f, 2.0f, 1);
GL11.glTranslated(-x, -y, 0);
render circles
GL11.glPopMatrix();
I expect the circles to scale accordingly to the number I've put into glScaled()
Currently they aren't rescaling at all, just rendered at their normal size.
Here's a demonstration of how to properly render a circle using triangle fans:
public void render() {
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
// Coordinate system starts out as screen space coordinates
glOrtho(0, 400, 300, 0, 1, -1);
glColor3d(1, 0.5, 0.5);
renderCircle(120, 120, 100);
glColor3d(0.5, 1, 0.5);
renderCircle(300, 200, 50);
glColor3d(0.5, 0.5, 1);
renderCircle(200, 250, 30);
}
private void renderCircle(double centerX, double centerY, double radius) {
glPushMatrix();
glTranslated(centerX, centerY, 0);
glScaled(radius, radius, 1);
// Another translation here would be wrong
renderUnitCircle();
glPopMatrix();
}
private void renderUnitCircle() {
glBegin(GL_TRIANGLE_FAN);
int numVertices = 100;
double angle = 2 * Math.PI / numVertices;
for (int i = 0; i < numVertices; ++i) {
glVertex2d(Math.cos(i*angle), Math.sin(i*angle));
}
glEnd();
}
Output image:
The GL_POINT_SIZE value is actually the size of the point in pixels onscreen, not current coordinate units. For that reason your circles were unaffected by GL_SCALE. That's one reason not to use GL_POINTS to render circles. The other (arguably more important) reason being that GL_POINT_SIZE is severely deprecated and unsupported in newer OpenGL profiles.
currently I am scaling a matrix like so:
public void scale(float aw, float ah){
Matrix.scaleM(modelMatrix, 0, aw, ah, 1f);
updateMVP();
}
private void updateMVP(){
Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, modelMatrix, 0);
}
And using: gl_Position = u_Matrix * a_Position; in my vertex shader, u_Matrix being the mvpMatrix. The camera I am using is the default and the projectionMatrix is created by:
ASPECT_RATIO = (float) height / (float) width;
orthoM(projectionMatrix, 0, -1f, 1f, -ASPECT_RATIO, ASPECT_RATIO, -1f, 1f);
Now I can scale my object properly, but the only problem is that every time I scale the matrix, the object moves a little bit. I was wondering how I could scale the matrix while keeping the center point and not having the object translate. Anyone know how I can do this in OpenGL ES 2.0 on Android? Thanks
Do you have any other matrices (rotation/translation)?
If so: you might not be multiplying your matrices in the correct order, which can cause issues.
(proper order multiply right to left)
Translate * Rotation * Scale
Your error sounds like the one explained here:
You translate the ship by (10,0,0). Its center is now at 10 units of the origin.
You scale your ship by 2. Every coordinate is multiplied by 2 relative to the origin, which is far away… So you end up with a big
ship, but centered at 2*10 = 20. Which you don’t want.
http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/
this is a big problem I have been running into.
I am trying to render multiple tiles using glTranslate but when I call my draw function with the x, y coordinates the tiles are spaced weirdly(I don't want spaces).
Here is what happens.
here is my code:
Draw:
public void draw(float Xa, float Ya) {
GL11.glTranslatef(Xa, Ya, 0);
if(hasTexture) {
Texture.bind();
GL11.glBegin(GL11.GL_QUADS);
GL11.glColor3f(0.5f, 0.5f, 1);
GL11.glTexCoord2f(0, 0);
GL11.glVertex2f(0, 0);
GL11.glTexCoord2f(0, 1);
GL11.glVertex2f(0, S);
GL11.glTexCoord2f(1, 1);
GL11.glVertex2f(S, S);
GL11.glTexCoord2f(1, 0);
GL11.glVertex2f(S, 0);
GL11.glEnd();
}
and my render code:
public void a() throws IOException {
GL11.glTranslatef(0, 0, -10);
int x = 0;
while (x < World.BLOCKS_WIDTH - 1) {
int y = 0;
while (y < World.BLOCKS_HEIGHT - 1) {
blocks.b[data.blocks[x][y]].draw(x, y);
y++;
}
x++;
}
there are no errors (except the visible ones)
You do not appear to be initialising or pushing / popping the current transform. So the translations will accumulate, producing the effect you see, getting further and further apart as you translate by ever larger values.
Lets say your blocks are 10 units apart. The first is drawn with a translation of (0, 0), then next (0, 10), then (0, 20), (0, 30), etc.
However as the translations accumulate in the view matrix, what you actually get are translations of (0,0), (0,10), (0,30), (0,60), etc.
This is important, as it allows you to build a complex transform from a series of simple discrete steps. However when you want to render multiple objects, each with their own transform, you need to have some form of reset in between each object.
You could reinitialise the whole matrix, but that's a bit untidy and involves knowing what other transforms (such as the camera, etc.) have been done previously.
Instead, you can "push" the current matrix onto a stack, perform whatever local transformations you want to do, render stuff, and then "pop" the matrix back off so that you're back where you started, ready to render the next object.
I should point out that all this functionality is deprecated in the later versions of GL. With the more modern API you use shaders, and can supply whatever transforms you care to calculate.
I have a model matrix that I am keeping track of for position of the mesh in my world. With each call to glRotate() and glTranslate() I have a corresponding call to modelMatrix.rotate() and modelMatrix.translate() which appears to be working correctly.
Now I need to update the bounding box associated with each of my models. I'm working in the libGDX framework and in the BoundingBox class found here, there is a method mul() that should allow me to apply a matrix to the bounding box but the values are not being updated correctly and I think it may be the way I am trying to apply it. Any ideas?
Here is my relevant code:
gl.glPushMatrix();
// Set the model matrix to the identity matrix
modelMatrix.idt();
// Update the orbit value of this model
orbit = (orbit + ORBIT_SPEED * delta) % 360;
gl.glRotatef(orbit, 1.0f, 1.0f, 0);
// Update the model matrix rotation
modelMatrix.rotate(1.0f, 1.0f, 0, orbit);
// Move the model to it's specified radius
gl.glTranslatef(0, 0, -ORBIT_DISTANCE);
// Update the model matrix translation
modelMatrix.translate(0, 0, -ORBIT_DISTANCE);
// Update the bounding box
boundingBox.mul(modelMatrix);
if (GameState.DEBUG)
{
renderBoundingBox(gl, delta);
}
// Bind the texture and draw
texture.bind();
mesh.render(GL10.GL_TRIANGLES);
gl.glPopMatrix();
The order that matrix multiplication is computed is important. Can you do ModelMatrix * Box instead. I think that's the issue.
I want to create a camera moving above a tiled plane. The camera is supposed to move in the XY-plane only and to look straight down all the time. With an orthogonal projection I expect a pseudo-2D renderer.
My problem is, that I don't know how to translate the camera. After some research it seems to me, that there is nothing like a "camera" in OpenGL and I have to translate the whole world. Changing the eye-position and view center coordinates in the Matrix.setLookAtM-function just leads to distorted results.
Translating the whole MVP-Matrix does not work either.
I'm running out of ideas now; do I have to translate every single vertex every frame directly in the vertex buffer? That does not seem plausible to me.
I derived GLSurfaceView and implemented the following functions to setup and update the scene:
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
// Setup the projection Matrix for an orthogonal view
Matrix.orthoM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
public void onDrawFrame(GL10 unused) {
// Draw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
//Setup the camera
float[] camPos = { 0.0f, 0.0f, -3.0f }; //no matter what else I put in here the camera seems to point
float[] lookAt = { 0.0f, 0.0f, 0.0f }; // to the coordinate center and distorts the square
// Set the camera position (View matrix)
Matrix.setLookAtM( vMatrix, 0, camPos[0], camPos[1], camPos[2], lookAt[0], lookAt[1], lookAt[2], 0f, 1f, 0f);
// Calculate the projection and view transformation
Matrix.multiplyMM( mMVPMatrix, 0, projMatrix, 0, vMatrix, 0);
//rotate the viewport
Matrix.setRotateM(mRotationMatrix, 0, getRotationAngle(), 0, 0, -1.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mRotationMatrix, 0, mMVPMatrix, 0);
//I also tried to translate the viewport here
// (and several other places), but I could not find any solution
//draw the plane (actually a simple square right now)
mPlane.draw(mMVPMatrix);
}
Changing the eye-position and view center coordinates in the "LookAt"-function just leads to distorted results.
If you got this from the android tutorial, I think they have a bug in their code. (made a comment about it here)
Try the following fixes:
Use setLookatM to point to where you want the camera to be.
In the shader, change the gl_Position line
from: " gl_Position = vPosition * uMVPMatrix;"
to: " gl_Position = uMVPMatrix * vPosition;"
I'd think the //rotate the viewport section should be removed as well, as this is not rotating the camera properly. You can change the camera's orientation in the setlookat function.