OpenGL перемещает объект и вращается по одной оси
Я пытаюсь добавить объект (треугольник) в OpenGL, он перемещается с помощью glTranslatef() и вращается с помощью glRotatef(), это нормально!
Я добавляю одну матрицу сетки в фоновом режиме и хочу удерживать положение объекта (треугольник) в центре и вращать только фон сетки, хорошо работает!
Однако при "ходьбе" объекта (треугольника) с помощью клавиш (вверх и вниз) он не поворачивается по одной оси фона сетки.
кажется, что это дистанцирует вращение при движении!
Пример кода:
#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);
}
Предложения приветствуются...
1 ответ
glutSwapBuffers
Выполняет замену буфера на слое, используемом для текущего окна. Вы должны сделать один glutSwapBuffers
вызов в конце рендеринга. Далее достаточно на glutPostRedisplay
вызов в основном цикле.
Это значит удалить все все glutPostRedisplay
а также glutPostRedisplay
из всего вашего кода, но измените display
Функция как-то так:
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
drawGrid();
drawCursor();
glutSwapBuffers();
glutPostRedisplay();
}
Если вы хотите вращаться вокруг центра випорта, вы должны поменять местами glTranslatef
и glRotatef
операция:
void drawGrid()
{
.....
glRotatef(rotate_value, 0.0f, 0.0f, 1.0f);
glTranslatef(0.0f, posY, zoom_value);
.....
}
Если вы хотите переместить курсор на сетку в направлении Y окна просмотра, то вы должны правильно соблюдать угол поворота:
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;
}
И вы должны уважать posX
в переводе сетки:
glRotatef(rotate_value, 0.0f, 0.0f, 1.0f);
glTranslatef(posX, posY, zoom_value);
Пояснение:
Смотрите документацию glTranslate
:
glTranslate
производит переводx y z
, Текущая матрица (см.glMatrixMode
) умножается на эту матрицу перевода, с произведением, заменяющим текущую матрицу,
и посмотреть документацию glRotate
:
glRotate
производит вращение угловых градусов вокруг вектораx y z
, Текущая матрица (см.glMatrixMode
) умножается на матрицу вращения с произведением, заменяющим текущую матрицу,
Обратите внимание, матрица перевода выглядит следующим образом:
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 )
И матрица вращения вокруг оси Y выглядит так:
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 )
Умножение матриц работает так:
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];
Результат translate * rotate
это:
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 )
Обратите внимание, результат rotate * translate
было бы:
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 )