【问题标题】:OpenGL movement object and rotate in same axisOpenGL移动对象并在同一轴上旋转
【发布时间】:2018-02-28 01:05:25
【问题描述】:

我正在尝试在 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);
}

欢迎提出建议...

【问题讨论】:

  • 很难理解你的问题,但无论如何,glutSwapBuffers() 应该只被调用一次,在display() 函数体的末尾。葡萄牙语:Tá bem difícil de entender a sua pergunta, mas de qualquer forma, a chamada da funçãoglutSwapBuffers() deveria ser feita uma única vez, no final da função display()
  • 我现在试着解释得更好!
  • 您应该尝试将调用顺序从:glTranslatef(0.0f, posY, zoom_value); glRotatef(rotate_value, 0.0f, 0.0f, 1.0f); 交换为 glRotatef(rotate_value, 0.0f, 0.0f, 1.0f); glTranslatef(0.0f, posY, zoom_value);。无论如何,我建议您更改 posXposY 的计算方式

标签: c++ opengl coordinate-transformation


【解决方案1】:

glutSwapBuffers 在当前窗口使用的层上执行缓冲区交换。您应该在渲染结束时进行一次 glutSwapBuffers 调用。此外,在主循环中调用 glutPostRedisplay 就足够了。

这意味着从您的整个代码中删除所有glutPostRedisplayglutPostRedisplay,但以某种方式更改display 函数:

void display()
{
    glClear(GL_COLOR_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    drawGrid();
    drawCursor();

    glutSwapBuffers();
    glutPostRedisplay();
}



如果要围绕视口中心旋转,则必须交换 glTranslatefglRotatef 操作:

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 )

【讨论】:

  • 完美,有效!但是当我在示例中将 drawGrid() 旋转 45° 时,使用移动(向上或向下)它会根据角度移动,而不是在 drawCursor() 的方向上移动。总是在向上和向下时,我希望 drawGrid() 垂直移动(90°)。建议?
  • 感谢@Rabbid76 的帮助。我不知道我是否理解,我在 drawGrid() 中使用 glTranslatef() 中的另一个变量进行了更改,但继续以旋转的角度移动。例如,下面我按下 UP,底部向下,给人一种位移的感觉。 ibb.co/nymOXn 然后它旋转 45°,当按下 UP 时它会移动,但会以旋转的角度移动,总是想像第一张图像一样下降。 ibb.co/bHxK57
  • 是的!现在可以了。抱歉,我忘记了变量 posX。谢谢@Rabbid76
猜你喜欢
  • 1970-01-01
  • 2014-12-05
  • 2018-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-12
  • 1970-01-01
相关资源
最近更新 更多