Edit
*Solved. Source code updated to working version!*
I'm trying to make a simple game engine for my next game using OpenGL and Box2D.
Problem is I can't get working these two well. If i turn OpenGL rotation off, everything looks as I'd except it in real worl. Problem is with rotation on.
http://cl.ly/image/0I0M3C3K1c3c - rotation off
http://cl.ly/image/421v321t201D - rotation on
I don't know if it's Box2D or OpenGL problem but I think right box shouldn't be rotated if it's on a flat ground in calm state or it's clearly violates law of physics. This is not only one problem but this one is clearly visible with picture only. I personally blame OpenGL for this :)
Here's my rendering code
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
GLuint texture_handle;
/* texture load logic */
...
...
glTranslatef(this->xPos + this->width / 2, this->yPos + this->height / 2, 0.0f);
glRotatef(this->angle, 0.0f, 0.0f, 1.0f);
glTranslatef(-this->width / 2, -this->height / 2 , 0);
/* Creates 3D cube */
glBegin(GL_QUADS);
glVertex2f(0, 0);
glTexCoord2f(1, 0);
glVertex2f(this->GetWidth(), 0);
glTexCoord2f(1, 1);
glVertex2f(this->GetWidth(), this->GetHeight());
glTexCoord2f(0, 1);
glVertex2f(0, this->GetHeight());
glTexCoord2f(0, 0);
glEnd();
glDeleteTextures(1, &texture_handle);
glPopMatrix();
glFlush();
For completion, here's Box2D part
/* define body for box */
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(this->xPos / RATIO, this->yPos / RATIO);
bodyDef.angle = this->angle * (M_PI / 180);
body = this->world->CreateBody(&bodyDef);
b2PolygonShape box;
box.SetAsBox((this->width / 2) / RATIO, (this->height / 2) / RATIO);
b2FixtureDef shapeDef;
shapeDef.shape = &box;
shapeDef.density = 1f;
shapeDef.friction = 0.8f;
body->CreateFixture(&shapeDef);
this->body = body;
/* apply physics */
b2Vec2 position = this->body->GetPosition();
this->angle = this->body->GetAngle() / (M_PI / 180);
this->xPos = (position.x * RATIO);
this->yPos = (position.y * RATIO);
Related
NOTE I know that my plane and the cylinder are badly built but their purpose is just to have something to see on the screen. Considering (px,py,pz), the camera position, and (dx, dy, dz), the view direction.
Important: My camera should follow a structure similar to the one I implemented here, so I can't use glRotate, glTranslate everything has to be done manually, the imposition of my teacher sadly, And also I am using Visual Studio.
FIX: My translations are all ok now I fixed a thing in the case GLUT_KEY_LEFT and GLUT_KEY_RIGTH.
Problem: Now the remaning problem is in the mouse_motion, when I click with left mouse button and drag the mouse around the screen my camera changes it direction really fast and sometimes when I go up it faces down its strange and hard to describe XD.
Warning: Warning C26451 Arithmetic overflow: Using operator '+' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator '+' to avoid overflow (io.2). class2 main.cpp 199 .
This is my the line that says gluLookAt(px, py, pz, px+dx, py+dy, pz+dz, 0.0f, 1.0f, 0.0f); How can I fix it?
Camera: I just want the motion of the mouse to allow me to define the direction I want to go and use the up, down, left, right keys to move.
#include <math.h>
#include <ctime>
#include <iostream>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#define PI 3.1415926535897932384626433832795
//For Camera
#define GlUT_KEY_UP 72
#define KEY_DOWN 80
#define KEY_LEFT 75
#define KEY_RIGHT 77
// angle of rotation for the camera direction
float angle = 0.0f; //alpha
float angle1 = 0.0f; //beta
// actual vector representing the camera's direction
float dx = 0.0f;
float dy = 0.0f;
float dz = 1.0f;
// XZ position of the camera
float px = 0.0f;
float py = 0.0f;
float pz = 10.0f;
float speed = 1.0f;
float rotateSpeed = 0.0008f;
//For FPS
int timebase;
float frame;
void changeSize(int w, int h) {
// Prevent a divide by zero, when window is too short
// (you cant make a window with zero width).
if(h == 0)
h = 1;
// compute window's aspect ratio
float ratio = w * 1.0 / h;
// Set the projection matrix as current
glMatrixMode(GL_PROJECTION);
// Load Identity Matrix
glLoadIdentity();
// Set the viewport to be the entire window
glViewport(0, 0, w, h);
// Set perspective
gluPerspective(45.0f ,ratio, 1.0f ,1000.0f);
// return to the model view matrix mode
glMatrixMode(GL_MODELVIEW);
}
// Draw Figures
void drawAxis() {
glBegin(GL_LINES);
// X axis in Red
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(100.0f, 0.0f, 0.0f);
glVertex3f(-100.0f, 0.0f, 0.0f);
// Y Axis in Green
glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(0.0f, 100.0f, 0.0f);
glVertex3f(0.0f, -100.0f, 0.0f);
// Z Axis in Blue
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.0f, 0.0f, 100.0f);
glVertex3f(0.0f, 0.0f, -100.0f);
glEnd();
}
void drawPlane(float width) {
width/=2;
glBegin(GL_TRIANGLE_FAN);
glColor3f(4.0f, 1.0f, 1.0f);
glVertex3d(width, 0,width);
glVertex3d(width, 0, -width);
glVertex3d(-width, 0,-width);
glColor3f(3.0f, 1.0f, 0.0f);
glVertex3d(width, 0, width);
glVertex3d(-width, 0, -width);
glVertex3d(-width, 0, width);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3d(width, 0, -width);
glVertex3d(width, 0, width);
glVertex3d(-width, 0, -width);
glColor3f(1.0f, 1.0f, 1.0f);
glVertex3d(-width, 0, -width);
glVertex3d(width, 0, width);
glVertex3d(-width, 0, width);
glEnd();
}
void drawCylinder(float radius, float height, int slices) {
float interval = 2 * PI / slices;
float next_a, next_h;
for (float a = 0; a < 2 * PI; a += interval) {
next_a = a + interval;
if (next_a > 2 * PI) {
next_a = 2 * PI;
}
glBegin(GL_TRIANGLES);
//Top
glColor3f(0.698f, 0.133f, 0.133f);
glVertex3f(0.0f, height / 2, 0.0f);
glVertex3f(radius * sin(a), height / 2, radius * cos(a));
glVertex3f(radius * sin(next_a), height / 2, radius * cos(next_a));
//Bottom
glColor3f(0.698f, 0.133f, 0.133f);
glVertex3f(0.0f, -height / 2, 0.0f);
glVertex3f(radius * sin(next_a), -height / 2, radius * cos(next_a));
glVertex3f(radius * sin(a), -height / 2, radius * cos(a));
for (float h = -height / 2; h < height / 2; h += height) {
next_h = h + height;
if (next_h > height / 2) {
next_h = height / 2;
}
//Walls
glColor3f(1.0f, 0.271f, 0.0f);
glVertex3f(radius * sin(next_a), next_h, radius * cos(next_a));
glVertex3f(radius * sin(a), next_h, radius * cos(a));
glVertex3f(radius * sin(next_a), h, radius * cos(next_a));
glColor3f((a + 0.05) / (2 * PI), (a + 0.3) / (2 * PI), (h + height / 2) / height);
glVertex3f(radius * sin(a), next_h, radius * cos(a));
glVertex3f(radius * sin(a), h, radius * cos(a));
glVertex3f(radius * sin(next_a), h, radius * cos(next_a));
}
glEnd();
}
}
void renderScene(void) {
// clear buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// set the camera
glLoadIdentity();
//FPS Camera
gluLookAt(px, py, pz, px+dx, py+dy, pz+dz, 0.0f, 1.0f, 0.0f);
// put the geometric transformations here
// put drawing instructions here
drawAxis();
drawPlane(4);
drawCylinder(1,3,30);
//FPS counter
frame++;
int final_time = glutGet(GLUT_ELAPSED_TIME);
if (final_time - timebase > 1000) {
int fps = frame * 1000.0f / (final_time - timebase);
char title[(((sizeof fps) * CHAR_BIT) + 2) / 3 + 2];
sprintf(title,"FPS: %d", fps);
glutSetWindowTitle(title);
timebase = final_time;
frame = 0;
}
// End of frame
glutSwapBuffers();
}
//FPS Camera
void move(int key, int x, int y) {
switch (key) {
case GLUT_KEY_RIGHT: {
px -= (dz * speed);
pz += (dx * speed);
break;
}
case GLUT_KEY_LEFT: {
px += (dz * speed);
pz -= (dx * speed);
break;
}
case GLUT_KEY_UP: {
px += (dx * speed);
pz += (dz * speed);
break;
}
case GLUT_KEY_DOWN: {
px -= (dx * speed);
pz -= (dz * speed);
break;
}
default: {
break;
}
}
glutPostRedisplay();
}
void mouse_motion(int x, int y) {
float lx = x - 800;
float ly = y - 800;
angle = angle + lx * rotateSpeed;
angle1 = angle1 + ly * rotateSpeed;
dx = cos(angle1) * sin(angle);
dy = sin(angle1);
dz = cos(angle1) * cos(angle);
}
int main(int argc, char **argv) {
// init GLUT and the window
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH|GLUT_DOUBLE|GLUT_RGBA);
glutInitWindowPosition(100,100);
glutInitWindowSize(800,800);
glutCreateWindow("CG");
// Required callback registry
glutIdleFunc(renderScene);
glutDisplayFunc(renderScene);
glutReshapeFunc(changeSize);
//FPS
timebase = glutGet(GLUT_ELAPSED_TIME);
// put here the registration of the keyboard callbacks
glutSpecialFunc(move);
glutMotionFunc(mouse_motion);
//glutPassiveMotionFunc(mouse_motion);
// OpenGL settings
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
// enter GLUT's main cycle
glutMainLoop();
return 1;
}
I am trying to draw an arrow using the style below but this arrow should be also rotated according to a condition (need to pass the degree for each condition). I can draw the rectangle and a triangle but I cannot draw the triangle as an arrowhead. Also, how can I include the rotation degree into the code? Is there any easier way to draw an arrow and rotate it?
int triangleRect=4, triangleTri=3, lineWidth=3;
double twicePi = 2.0f * M_PI, angle_offsetR =1.5* M_PI/2, radius = 0.05,
xR=m_start.x(), y=m_start.y(), xT=m_start.x()+ m_rect_width;
glColor3f(0,1,0);
glLineWidth(lineWidth);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_MULTISAMPLE);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_LINE_SMOOTH);
glBegin(GL_TRIANGLE_FAN);
//RECTANGLE
for(int i = 0; i <= triangleRect; i++) {
glVertex2f((xR + (radius * cos(i * twicePi / triangleRect + angle_offsetR)))* m_parent_width_function(),
(y + (radius * sin(i * twicePi / triangleRect + angle_offsetR)))* m_parent_height_function());
}
// TRIANGLE
for(int i = 0; i <= triangleTri; i++) {
glVertex2f((xT + (radius * cos(i * twicePi / triangleTri + angle_offsetR)))* m_parent_width_function(),
(y + (radius * sin(i * twicePi / triangleTri + angle_offsetR)))* m_parent_height_function());
}
glEnd();
You accidentally add angle_offsetR to the angle for the triangle vectors. Furthermore you've to restart a GL_TRIANGLE_FAN primitiv when you draw an new shape (see Triangle primitives).
If you want to rotate the model, then set the add a rotation around the z axis to the model view matrix by glRotatef.
Do not translate and scale the vertex coordinates. Use glScale and glTranslate. The matrix transformations are not commutative, the order matters:
float angle_of_roation = 30.0; // 30°
glPushMatrix();
// scale
glScalef( m_parent_width_function(), m_parent_height_function(), 1.0f);
// move triangle and rectangle to the position in the world
glTranslatef(xR, y, 0.0f);
// roatate triangle and rectangle
glRotatef(angle_of_roation, 0, 0, 1);
//RECTANGLE
glBegin(GL_TRIANGLE_FAN);
for(int i = 0; i <= triangleRect; i++) {
float angle = i * twicePi / triangleRect + angle_offsetR;
glVertex2f(radius * cos(angle), radius * sin(angle));
}
glEnd();
glPushMatrix();
// translate triangle relative to rectangle
glTranslatef(xT-xR, 0.0f, 0.0f);
// TRIANGLE
glBegin(GL_TRIANGLE_FAN);
for(int i = 0; i <= triangleTri; i++) {
float angle = i * twicePi / triangleTri;
glVertex2f(radius * cos(angle), radius * sin(angle));
}
glEnd();
glPopMatrix();
glPopMatrix();
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
I am having trouble rotating an ellipse in OpenGL. So, I have some code to draw an ellipse as follows:
glPushAttrib(GL_CURRENT_BIT);
glColor3f(1.0f, 0.0f, 0.0f);
glLineWidth(2.0);
glPushMatrix();
glTranslatef(0, 0, 0); // ellipse centre
glBegin(GL_LINE_LOOP);
float inc = (float) M_PI / 500.0;
for (GLfloat i = 0; i < M_PI * 2; i+=inc)
{
float x = cos(i) * 0.4;
float y = sin(i) * 0.4;
glVertex2f(x, y);
}
glEnd();
glPopMatrix();
glPopAttrib();
This produces a picture as so:
Now what I want to do is rotate this ellipse clockwise. So I added a glrotate in between but the result was not what I had expected.
So, I did something like:
glPushAttrib(GL_CURRENT_BIT);
glColor3f(1.0f, 0.0f, 0.0f);
glLineWidth(2.0);
glPushMatrix();
glTranslatef(0, 0, 0);
glRotatef(-90, 1, 1, 0);
glBegin(GL_LINE_LOOP);
float inc = (float) M_PI / 500.0;
for (GLfloat i = 0; i < M_PI * 2; i+=inc)
{
float x = cos(i) * 0.4;
float y = sin(i) * 0.4;
glVertex2f(x, y);
}
glEnd();
glPopMatrix();
glPopAttrib();
This produced an image which was simply collapsed. What I wanted to do was rotate the ellipse along its center by the specified degrees. Also, I tried playing around with the various parameters of glRotatef but could not get it do as I expected. The resulting image looks like:
You're working in the XY plane, so you can't really rotate around a vector in XY. Instead, you want to rotate along the unit Z axis (glRotate (angle, 0, 0, 1);). Imagine your screen being the XY coordinate system and the Z axis pointing inwards. What you want is to rotate around the Z axis, so your XY plane remains in the XY plane.
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.