I are trying add an object(triangle) in OpenGL, it move using glTranslatef() and rotate with glRotatef(), it is ok!
I add one matrix of the grid in background and want hold position of the object(triangle) in center and rotate only grid background, ok works!
However, when "walking" the object(triangle) using keys(up and down) it not rotate in same axis of the grid background.
it seems that it is distancing the rotate when move!
Code example:
#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <cmath>
#include <vector>
#include <GL/glew.h>
#include <GL/glut.h>
#define DEG_TO_RADIANS 0.017453292519943295769236907684886f
#define GL_WIN_SIZE_X 800
#define GL_WIN_SIZE_Y 600
#define ANGLE_INITIAL 90.0f
using namespace std;
GLint idWin=0;
double rotate_value=ANGLE_INITIAL;
float posX = 0.0f, posY = 0.0f, angle = 0.0f;
float velocity = 0.1f;
float zoom_value=-5.0f;
float zoom_steps=0.5f;
float x_offset=0.0f;
float y_offset=0.0f;
/* Store points way traveled */
struct vertex {
float x, y, u, v, r, g, b;
};
std::vector<vertex> vertices;
bool start = false;
GLuint vboId;
void keyPress(int key, int xpos, int ypos)
{
if (key == GLUT_KEY_UP) {
posX += (cos( rotate_value * DEG_TO_RADIANS )) * velocity;
posY += -(sin( rotate_value * DEG_TO_RADIANS )) * velocity;
}
else if (key == GLUT_KEY_DOWN) {
posX -= (cos( rotate_value * DEG_TO_RADIANS )) * velocity;
posY -= -(sin( rotate_value * DEG_TO_RADIANS )) * velocity;
}
else if (key == GLUT_KEY_RIGHT) {
if (rotate_value == 360) { rotate_value=0.0f; }
else { rotate_value+=0.5f; }
}
else if (key == GLUT_KEY_LEFT) {
if (rotate_value == 0) { rotate_value=360; }
else {rotate_value-=0.5f; }
}
{
static float posXOld=0;
static float posYOld=0;
if (posX == posXOld && posY == posYOld) { cout << "Some position..." << endl; }
else {
vertex temp = {-posX, -posY, 1, 0, 1, 0, 0};
vertices.push_back(temp);
}
posXOld = posX;
posYOld = posY;
}
glutPostRedisplay();
}
void initRendering()
{
glClearColor(0.3f, 0.4f, 0.65f, zoom_value);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-GL_WIN_SIZE_X, GL_WIN_SIZE_X, -GL_WIN_SIZE_Y, GL_WIN_SIZE_Y);
}
void handleResize(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); //Reset the camera
gluPerspective(45.0, //The camera angle
(double)w / (double)h,
1.0,
200.0);
}
static void drawline(float x1, float y1, float x2, float y2)
{
glLineWidth(2.0);
glBegin (GL_LINES);
glVertex3f(x1, y1, zoom_value);
glVertex3f(x2, y2, zoom_value);
glEnd();
}
static void drawGrid()
{
float size_w = GL_WIN_SIZE_X;
float size_h = GL_WIN_SIZE_Y;
float size_offset = 1.0;
glColor3f(1.0, 0.5, 1.0);
glLoadIdentity();
glPushMatrix();
glTranslatef(0.0f, posY, zoom_value);
glRotatef(rotate_value, 0.0f, 0.0f, 1.0f); //Z
glLineWidth(1.5);
for (float x1=-size_w; x1<size_w; x1 += size_offset)
{
drawline(size_w, x1, -size_w, x1);
}
for (float y1=-size_h; y1<size_h; y1 += size_offset)
{
drawline(y1, size_h, y1, -size_h);
}
glPopMatrix();
glutSwapBuffers();
}
static void drawCursor()
{
glColor3d(0.5, 0.1, 0.0);
glLoadIdentity();
glTranslatef(-posX, -posY, 0.0f);
glBegin(GL_TRIANGLES);
glVertex3f( posX+0.0f, posY+0.5f, zoom_value);
glVertex3f( posX+0.5f, posY+(-0.5f), zoom_value);
glVertex3f( posX+(-0.5f), posY+(-0.5f), zoom_value);
glEnd();
glutSwapBuffers();
}
void initVertexBuffer() {
glGenBuffers(1, &vboId);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex) * vertices.size(), &vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
drawGrid();
drawCursor();
}
int main(int argc,char** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(GL_WIN_SIZE_X, GL_WIN_SIZE_Y);
idWin = glutCreateWindow("Tests OpenGL Objects in Scene");
initRendering();
glutDisplayFunc(display);
glutSpecialFunc(keyPress);
glutReshapeFunc(handleResize);
glutMainLoop();
return(EXIT_SUCCESS);
}
Suggestions are welcomed...
glutSwapBuffers
Performs a buffer swap on the layer in use for the current window. You should do a single glutSwapBuffers
call at the end of the rendering. Further it is sufficient to on glutPostRedisplay
call in the main loop.
This means remove all all glutPostRedisplay
and glutPostRedisplay
from your entire code, but change the display
function somehow like this:
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
drawGrid();
drawCursor();
glutSwapBuffers();
glutPostRedisplay();
}
If you want to rotat around the center of the vieport, the you have to swap the glTranslatef
and the glRotatef
operation:
void drawGrid()
{
.....
glRotatef(rotate_value, 0.0f, 0.0f, 1.0f);
glTranslatef(0.0f, posY, zoom_value);
.....
}
If you want to move the cursor on grid in the Y-direction of the viewport, then you have to proper respect the angle of rotation:
if (key == GLUT_KEY_UP) {
posX -= sin( rotate_value * DEG_TO_RADIANS ) * velocity;
posY -= cos( rotate_value * DEG_TO_RADIANS ) * velocity;
}
else if (key == GLUT_KEY_DOWN) {
posX += sin( rotate_value * DEG_TO_RADIANS ) * velocity;
posY += cos( rotate_value * DEG_TO_RADIANS ) * velocity;
}
And you have to respect the posX
in the translation of the grid:
glRotatef(rotate_value, 0.0f, 0.0f, 1.0f);
glTranslatef(posX, posY, zoom_value);
Explanation:
See the documentation of glTranslate
:
glTranslate
produces a translation byx y z
. The current matrix (seeglMatrixMode
) is multiplied by this translation matrix, with the product replacing the current matrix,
and see the documentation of glRotate
:
glRotate
produces a rotation of angle degrees around the vectorx y z
. The current matrix (seeglMatrixMode
) is multiplied by a rotation matrix with the product replacing the current matrix,
Note, the translation matrix looks like this:
Matrix4x4 translate;
translate[0] : ( 1, 0, 0, 0 )
translate[1] : ( 0, 1, 0, 0 )
translate[2] : ( 0, 0, 1, 0 )
translate[3] : ( tx, ty, tz, 1 )
And the rotation matrix around Y-Axis looks like this:
Matrix4x4 rotate;
float angle;
rotate[0] : ( cos(angle), sin(angle), 0, 0 )
rotate[1] : ( -sin(angle), cos(angle), 0, 0 )
rotate[2] : ( 0, 0, 1, 0 )
rotate[3] : ( 0, 0, 0, 1 )
A matrix multiplication works like this:
Matrix4x4 A, B, C;
// C = A * B
for ( int k = 0; k < 4; ++ k )
for ( int l = 0; l < 4; ++ l )
C[k][l] = A[0][l] * B[k][0] + A[1][l] * B[k][1] + A[2][l] * B[k][2] + A[3][l] * B[k][3];
The result of translate * rotate
is this:
model[0] : ( cos(angle), sin(angle), 0, 0 )
model[1] : ( -sin(angle) cos(angle), 0, 0 )
model[2] : ( 0, 0, 0, 0 )
model[3] : ( tx, ty, tz, 1 )
Note, the result of rotate * translate
would be:
model[0] : ( cos(angle), sin(angle), 0, 0 )
model[1] : ( -sin(angle), cos(angle), 0, 0 )
model[2] : ( 0, 0, 0 0 )
model[3] : ( cos(angle)*tx - sin(angle)*tx, sin(angle)*ty + cos(angle)*ty, tz, 1 )