I developed a game using OpenGL and c++, it all works fine but this glitch that I need to fix: when I move my camera around (using mouse) my map does not remain in a fixed spot.
It is basically a square (gl_quad) that I draw in front of me.
This is an example of the glitch:
Video
This is the drawing code of a square if it is needed
texture = scene->getTexture("map_papyrus.png");
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glUseProgram(this->shader->getRes());
glActiveTexture(GL_TEXTURE0);
GLint texture_location = glGetUniformLocation(this->shader- >getFragment(), "color_texture");
glUniform1i(texture_location, texture_location);
glBindTexture(GL_TEXTURE_2D, this->texture->getRes());
glBegin(GL_QUADS);
float size = .5f;
float offsetx = 0.0f;
float offsety = 0.0f;
if (set->easymode) { size = .2f; offsetx = 0.8f; offsety = 0.35f; }
glTexCoord2f(0,0); glVertex2f(-size + offsetx, -size + offsety);
glTexCoord2f(1, 0); glVertex2f(size + offsetx, -size +offsety);
glTexCoord2f(1,1); glVertex2f(size + offsetx, size + offsety);
glTexCoord2f(0, 1); glVertex2f(-size + offsetx, size + offsety);
glEnd();
glTranslated(0, 0, 0.00001);
Instead of rendering GUI elements as part of the 3D world, i'd rather finish drawing the world and then overlay on top of that a gui (without clearing the buffer).
That way the HUD doesn't need to move based on the camera's position and rotation.
Also, HUD elements wont clip with the world.
glClear(...)
// Scene:
glPushMatrix()
glPerspective(...)
glTranslatef(...)
glRotatef(...)
glBegin(...)
// ...
glEnd(...)
glPopMatrix()
// UI:
glPushMatrix()
glOrtho(...)
glBegin(...)
// ...
glEnd(...)
glPopMatrix()
// Swap buffers
Related
I am trying to render a rectangle onto the screen. When the program is run, only the clear color shows up, and no rectangle.
Here's the code:
glClearColor(0.0, 0.0, 0.0, 0.0);
glViewport(0, 0, 1280, 720);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1280, 720, 0, -10, 10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT || GL_DEPTH_BUFFER_BIT); //Clear the screen and depth buffer
int x = 100;
int y = 100;
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
glBegin(GL_QUADS);
glVertex2f(x, y);
glVertex2f(x + 10, y);
glVertex2f(x + 10, y + 10);
glVertex2f(x, y + 10);
glEnd();
gsm->update();
gsm->render();
glfwSwapBuffers(window);
}
It got culled. You had inverted Y axis with your projection, by supplying bottom =720 larger than top 0. Your quad is counterclockwise in your local coordinates, but in normalized coordinates it is clockwise. Remember, projection matrix is a part of global transform matrix! Now, if that's default state, then out of those two winding directions
the GL_CCW is the actual one, it is considered "Front". By default OpenGL culls triangles with mode glCullFace(GL_BACK), and quad internally is considered as pair of triangles).
Either change order of vertices
glBegin(GL_QUADS);
glVertex2f(x, y);
glVertex2f(x, y + 10);
glVertex2f(x + 10, y + 10);
glVertex2f(x + 10, y);
glEnd();
or change culling mode to match left-handedness of your coordinate system or disable culling.
See also:
1. https://www.khronos.org/opengl/wiki/Viewing_and_Transformations
2. The answer to Is OpenGL coordinate system left-handed or right-handed?
I'm having a problem with moving my camera with glOrtho. I have a small quad in the center and i want to try to move the camera using glOrtho, but it just doesn't seem to be working. The quad doesn't move at all, so the camera isn't moving too i guess. maybe i miss understand how glOrtho works?
here is my code so far.
void Camera::updateCamera(float x, float y, float zoom)
{
camX = x;
camY = y;
this->zoom = zoom;
viewWidth = 320;
viewHeight = 240;
//viewWidth = tan(60) * this->zoom;
//viewHeight = tan(45) * this->zoom;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(camX - viewWidth,
camX + viewWidth,
camY - viewHeight,
camY + viewHeight,
-1,
1);
glMatrixMode(GL_MODELVIEW);
}
and here is where i apply it. i tried to move it along the x axis for 25 points.
void Engine::renderAll()
{
x += 25;
glClear(GL_COLOR_BUFFER_BIT);
shader->use();
camera.updateCamera(x, y, 1.0);
//shader->setUniform4fv("view", camera.getView());
batchManager->renderBatches();
SDL_GL_SwapWindow(window);
}
Yes, I guess you misundertood how glOrtho works. The role of glOrtho is transform a 3D view in a 2D view, using an orthographic projection.
If you want to work with positioning camera in a 3D space, the correct function is normally called LookAt. Once, it seems me that you are using old OpenGL, you can try the glu function gluLookAt
PS. In moderm openGL, this functions is now deprecated. I suggest you to try to learn the modern way.
I am trying to setup my OpenGL views for some texture rendering. Following some advice on the forum, I set up my viewport and ortho matrix as follows:
First I try to compute the screen width and height that I can use while maintaining the aspect ratio of my image:
void resize(int w, int h)
{
float target_aspect_ratio = image_width / image_height;
width = w;
height = (int)(width / target_aspect_ratio + 0.5f);
if (height > h) {
height = h;
width = (int)(height * target_aspect_ratio + 0.5f);
}
off_x = (w - width)/2.f;
off_y = (h - height)/2;
// I want to center my image. So I have these offsets
glViewport(off_x, off_y, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, 0, height, 0.0f, 1.0f);
Now when I want to render my texture I do:
void paint()
{
// texture binding etc.
glTexCoord2f(0, 0); glVertex2f(0, 0);
glTexCoord2f(1, 0); glVertex2f(width, 0);
glTexCoord2f(1, 1); glVertex2f(width, height);
glTexCoord2f(0, 1); glVertex2f(0, height);
}
However, this does not show the image as expected. It does not maintain the aspect ratio as I size the screen. It is almost like the glViewport has no effect and I can verify this function gets called every time my window is resized.
Update:
It is strange. Almost as if these calls have no effect. I even did something as:
_off_x = _off_y = 0;
_width = 500;
_height = 500;
So I expected the viewport to be lower left box of my screen but the image is being drawn as before basically using the whole screen as the viewport.
Update 2:
Ok, so if I call
glViewport(_off_x, _off_y, _width, _height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, _width, 0, _height, 0, 1);
in my paint events, it works as expected! However, I thought it was enough to put this in the resize event handler.
Before start drawing, you need to switch your Matrix mode to GL_MODELVIEW. You don't need to set your projection matrix inside your render function at each frame.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
Here is a detailed analysis that I wrote about glMatrixMode() function modes :
OpenGL glMatrixMode(GL_PROJECTION) vs glMatrixMode(GL_MODELVIEW)
I am trying to make a tank game. I have successfully loaded an OBJ model, and calculated its bounding box for the model at the origin.
I am now trying to apply the transformations done to my model in the game logic to the original coordinates for the bounding box. For this, I grab the modelview matrix right before drawing my model, then multiply this matrix for the two vectors that define the BBox.
Here is the code that draws my tank:
void drawTank()
{
bBox = calcBBox(modelo, 1);
glPushMatrix();
glBindTexture(GL_TEXTURE_2D, texTank);
glScalef(0.2, 0.2, 0.2);
glTranslatef(posTank.x,posTank.y,posTank.z);
glRotatef(anguloTanque, 0, 1, 0); // rotate around Y (horizontal)
glRotatef(90, 0, 1, 0);
glRotatef(-90, 1, 0, 0);
glGetFloatv(GL_MODELVIEW_MATRIX, matrix);
glmDraw(modelo, GLM_TEXTURE | GLM_MATERIAL);
glColor3f(1,0,0);
drawBBox(bBox);
glPopMatrix();
}
With this snippet, my bbox is properly drawn over the tank model (transformations are applied in rendering by the glTranslate & glRotate functions). As you can see I also grab here my ModelView matrix.
Then I apply this matrix as follows (this is my entire display function):
void Display(void) {
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
camera();
glEnable(GL_TEXTURE_2D);
//glTranslatef(0,-40,150);
//PLANE
glBindTexture(GL_TEXTURE_2D, texArena);
glBegin(GL_POLYGON);
glTexCoord2f( 0.0f, 0.0f );
glVertex3f(-500, 0, -500);
glTexCoord2f( 5.0f, 5.0f );
glVertex3f(500, 0, -500);
glTexCoord2f(5.0f, 0.0f );
glVertex3f(500, 0, 500);
glTexCoord2f( 0.0f, 5.0f );
glVertex3f(-500, 0, 500);
glEnd();
drawTank();
glPopMatrix();
point3D max = bBox.max;
point3D min = bBox.min;
point3D resultMax;
point3D resultMin;
//Transformacion
multVectorByMatrix(matrix, max, resultMax);
multVectorByMatrix(matrix, min, resultMin);
bBox.max.x = resultMax.x; bBox.max.y = resultMax.y; bBox.max.z = resultMax.z;
bBox.min.x = resultMin.x; bBox.min.y = resultMin.y; bBox.min.z = resultMin.z;
glPushMatrix();
glColor3f(1,1,1);
drawBBox(bBox);
glPopMatrix();
glFlush();
glutSwapBuffers();
}
The function that multiplies a vector by a matrix:
void multVectorByMatrix(float* matrix, point3D vector, point3D &result)
{
result.x = (matrix[0] * vector.x) +
(matrix[4] * vector.y) +
(matrix[8] * vector.z) +
matrix[12];
result.y = (matrix[1] * vector.x) +
(matrix[5] * vector.y) +
(matrix[9] * vector.z) +
matrix[13];
result.z = (matrix[2] * vector.x) +
(matrix[6] * vector.y) +
(matrix[10] * vector.z) +
matrix[14];
}
If I draw the bounding box with this render loop, then my bounding box gets drawn but transformations are not applied properly. I can see the bounding box moving correctly with translations, but rotations are not done right.
What might be the problem here?
edit: some screenshots
Your problem is in this code.
point3D max = bBox.max;
point3D min = bBox.min;
point3D resultMax;
point3D resultMin;
//Transformacion
multVectorByMatrix(matrix, max, resultMax);
multVectorByMatrix(matrix, min, resultMin);
bBox.max.x = resultMax.x; bBox.max.y = resultMax.y; bBox.max.z = resultMax.z;
bBox.min.x = resultMin.x; bBox.min.y = resultMin.y; bBox.min.z = resultMin.z;
glPushMatrix();
glColor3f(1,1,1);
drawBBox(bBox);
glPopMatrix();
You take two vertices from your box and then apply transformations to them, then you use this transformed vertices to display a box, which of course will be axis aligned, because that's the only box you can get from just two opposite vertices. And you can see on your screenshot, that you bbox and the correct bbox have common vertices - these are exactly the vertices you applied your transformations to. So, in order to get a correct bbox, you need to get all vertices of the bbox and apply these transformations to all of them. Then you'll get exactly what you want.
UPDATE
See bottom for update.
I've been looking alot around the internet and I have found a few tutorials that explain what I'm trying to achieve but I can't get it to work, either the tutorial is incomplete or not applicable on my code.
I'm trying something as simple as rotating a 2D image around its origin (center).
I use xStart, xEnd, yStart and yEnd to flip the texture which are either 0 or 1.
This is what the code looks like
GameRectangle dest = destination;
Vector2 position = dest.getPosition();
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, this->image);
//If the rotation isn't 0 we'll rotate it
if (rotation != 0)
{
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef(0.5, 0.5, 0);
glRotatef(rotation, 0, 0, 1);
glMatrixMode(GL_PROJECTION);
}
glBegin(GL_QUADS);
glTexCoord2d(xStart,yStart);
glVertex2f(position.x, position.y);
glTexCoord2d(xEnd,yStart);
glVertex2f(position.x + this->bounds.getWidth(), position.y);
glTexCoord2d(xEnd,yEnd);
glVertex2f(position.x + this->bounds.getWidth(), position.y + this->bounds.getHeight());
glTexCoord2d(xStart,yEnd);
glVertex2f(position.x, position.y + this->bounds.getHeight());
glEnd();
glDisable(GL_TEXTURE_2D);
//Reset the rotation so next object won't be rotated
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glRotatef(0, 0, 0, 1);
glMatrixMode(GL_PROJECTION);
This code will draw the image in it's original size and it will rotate it, but it will rotate it from the top left corner which crops the image a lot. By calling GameRectangle.getOrigin() I can easily get the center of the rectangle, but I don't know where to use it.
Bit if put:
glTranslatef(-0.5, -0.5, 0);
After I call the:
glRotatef(0.5, 0.5, 0);
It will rotate from the center, but it will strech the image if it's not a perfect 90 degrees rotation.
UPDATE
After trying pretty much everything possible, I got the result I was looking for.
But I'm not sure if this is the best approach. Please tell me if there's something wrong with my code.
As I mentioned in a comment above, I use the same image multiple times and draw it with different values, so I can't save anything to the actual image. So I must reset the values everytime after I have rendered it.
I changed my code to this:
//Store the position temporary
GameRectangle dest = destination;
Vector2 position = dest.getPosition();
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, this->image);
glTranslatef(dest.getOrigin().x, dest.getOrigin().y, 0);
glRotatef(rotation, 0, 0, 1);
glBegin(GL_QUADS);
glTexCoord2d(xStart,yStart);
glVertex2f(-dest.getWidth()/2, -dest.getHeight()/2);
glTexCoord2d(xEnd,yStart);
glVertex2f(dest.getWidth()/2, -dest.getHeight()/2);
glTexCoord2d(xEnd,yEnd);
glVertex2f(dest.getWidth()/2, dest.getHeight()/2);
glTexCoord2d(xStart,yEnd);
glVertex2f(-dest.getWidth()/2, dest.getHeight()/2);
glEnd();
//Reset the rotation and translation
glRotatef(-rotation,0,0,1);
glTranslatef(-dest.getOrigin().x, -dest.getOrigin().y, 0);
glDisable(GL_TEXTURE_2D);
This rotates the texture together with the quad it's drawn in, it doesn't strech or crop. However the edges are a bit jagged if the image is filled square but I guess I can't avoid that with out antialiasing.
What you want is this:
glPushMatrix(); //Save the current matrix.
//Change the current matrix.
glTranslatef(dest.getOrigin().x, dest.getOrigin().y, 0);
glRotatef(rotation, 0, 0, 1);
glBegin(GL_QUADS);
glTexCoord2d(xStart,yStart);
glVertex2f(-dest.getWidth()/2, -dest.getHeight()/2);
glTexCoord2d(xEnd,yStart);
glVertex2f(dest.getWidth()/2, -dest.getHeight()/2);
glTexCoord2d(xEnd,yEnd);
glVertex2f(dest.getWidth()/2, dest.getHeight()/2);
glTexCoord2d(xStart,yEnd);
glVertex2f(-dest.getWidth()/2, dest.getHeight()/2);
glEnd();
//Reset the current matrix to the one that was saved.
glPopMatrix();