OpenGL:如何移动2D对象而不移动整个场景?

问题描述:

好吧,我正在尝试使用C++中的OpenGL重新创建旧的经典导弹命令。这是我第一次进入OpenGL,尽管我现在对C++感觉相当舒服。OpenGL:如何移动2D对象而不移动整个场景?

我想我的第一个任务是弄清楚如何在屏幕上移动2D对象,看起来好像很简单。我创建了两个快捷的方法调用,使其中的三角形或四边形:

void makeTriangle(color3f theColor, vertex2f &p1, vertex2f &p2, vertex2f &p3, 
        int &xOffset, int &yOffset) 
{ 
    //a triangle 
    glBegin(GL_POLYGON); 
     glColor3f(theColor.red, theColor.green, theColor.blue); 
     glVertex2f(p1.x, p1.y); 
     glVertex2f(p2.x, p2.y); 
     glVertex2f(p3.x, p3.y); 
    glEnd(); 
} 

void makeQuad(color3f theColor, vertex2f &p1, vertex2f &p2, vertex2f &p3, 
       vertex2f &p4, int &xOffset, int &yOffset) 
{ 
    //a rectangle 
    glBegin(GL_POLYGON); 
     glColor3f(theColor.red, theColor.green, theColor.blue); 
     glVertex2f(p1.x, p1.y); 
     glVertex2f(p2.x, p2.y); 
     glVertex2f(p3.x, p3.y); 
     glVertex2f(p4.x, p4.y); 
    glEnd(); 
} 

color3fvertex2f是简单的类:

class vertex2f 
{ 
public: 
    float x, y; 

    vertex2f(float a, float b){x=a; y=b;} 
}; 

class color3f 
{ 
public: 
    float red, green, blue; 

    color3f(float a, float b, float c){red=a; green=b; blue=c;} 
}; 

这里是我的主要文件:

#include <iostream> 
#include "Shapes.hpp" 

using namespace std; 

int xOffset = 0, yOffset = 0; 
bool done = false; 

void keyboard(unsigned char key, int x, int y) 
{ 
    if(key == 'q' || key == 'Q') 
     { 
      exit(0); 
      done = true; 
     } 

     if(key == 'a') 
      xOffset = -10; 

     if(key == 'd') 
      xOffset = 10; 

     if(key == 's') 
      yOffset = -10; 

     if(key == 'w') 
      yOffset = 10; 

} 


void init(void) 
{ 
    //Set color of display window to white 
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 

    //Set parameters for world-coordiante clipping window 
    glMatrixMode(GL_PROJECTION); 
    gluOrtho2D(-400.0,400.0,-300.0,300.0); 

} 


void display(void) 
{ 
    glClear(GL_COLOR_BUFFER_BIT); 

    color3f aGreen(0.0, 1.0, 0.0); 
    vertex2f pa(-400,-200); 
    vertex2f pb(-400,-300); 
    vertex2f pc(400,-300); 
    vertex2f pd(400,-200); 

    makeQuad(aGreen,pa,pb,pc,pd,xOffset,yOffset); 

    color3f aRed(1.0, 0.0, 0.0); 
    vertex2f p1(-50.0,-25.0); 
    vertex2f p2(50.0,-25.0); 
    vertex2f p3(0.0,50.0); 

    makeTriangle(aRed,p1,p2,p3,xOffset,yOffset); 

    glFlush(); 
} 


int main(int argc, char** argv) 
{ 
    // Create Window. 
    glutInit(&argc, argv); 
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); 
    glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT); 
    glutCreateWindow("test"); 

    // Some initialization. 
    init(); 

    while(!done) 
    { 
    //display functions 
    glutDisplayFunc(display); 
    glutKeyboardFunc(keyboard); 

    // Start event loop. 
    glutMainLoop(); 
    } 

    return 0; 
} 

四分之一被定义为暂时的“背景”,只由一个绿色的矩形框组成在屏幕的底部。红色三角形是我想移动的“对象”。在按键上,按照指示的方向保存偏移量。

我试过使用glTranslatef(xOffset,yOffset,0);,但问题在于它移动了屏幕上的两个元素,而不仅仅是红色的三角形。我试图把整个呼叫绘制push和pop矩阵运算之间的三角:

PushMatrix(); 
glTranslatef(xOffset,yOffset,0); 
glBegin(GL_POLYGON); 
    glColor3f(theColor.red, theColor.green, theColor.blue); 
    glVertex2f(p1.x, p1.y); 
    glVertex2f(p2.x, p2.y); 
    glVertex2f(p3.x, p3.y); 
glEnd(); 
PopMatrix(); 

据我所知,这破坏了任何更改,翻译是事先做。 我也试着只是改变了X和Y坐标的值调用draw之前,但只是导致一个简短的闪烁留下三角形在其原始位置之前:

p1.x += xOffset; 
p2.x += xOffset; 
p3.x += xOffset; 

p1.y += yOffset; 
p2.y += yOffset; 
p3.y += yOffset; 

必须有一个很好的这样做的简单方法,我只是忽略它。有人可以提供一个建议吗?

编辑:

我实际的问题是,我从来没有刷新屏幕初始平局之后。我需要的是指定我的主回路内的闲置功能:

glutIdleFunc(IdleFunc); 

凡实际IdleFunc样子:

GLvoid IdleFunc(GLvoid) 
{ 
    glutPostRedisplay(); 
} 

而不是使用glFlush()我绘制函数里面的,我一直在使用glutSwapBuffers() 。通过这样做,我首先想到的代码:

p1.x += xOffset; 
p2.x += xOffset; 
p3.x += xOffset; 

p1.y += yOffset; 
p2.y += yOffset; 
p3.y += yOffset; 

适合我的目的。我没有必要翻译这个矩阵,我只需要从一个场景到另一个场景的不同位置绘制元素。

GL_MODELVIEW是你需要的。

从OpenGL的常见问题解答,2.1:http://www.opengl.org/resources/faq/technical/gettingstarted.htm

program_entrypoint 
{ 
    // Determine which depth or pixel format should be used. 
    // Create a window with the desired format. 
    // Create a rendering context and make it current with the window. 
    // Set up initial OpenGL state. 
    // Set up callback routines for window resize and window refresh. 
} 

handle_resize 
{ 
    glViewport(...); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    // Set projection transform with glOrtho, glFrustum, gluOrtho2D, gluPerspective, etc. 
} 

handle_refresh 
{ 
    glClear(...); 

    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
    // Set view transform with gluLookAt or equivalent 

    // For each object (i) in the scene that needs to be rendered: 
     // Push relevant stacks, e.g., glPushMatrix, glPushAttrib. 
     // Set OpenGL state specific to object (i). 
     // Set model transform for object (i) using glTranslatef, glScalef, glRotatef, and/or equivalent. 
     // Issue rendering commands for object (i). 
     // Pop relevant stacks, (e.g., glPopMatrix, glPopAttrib.) 
    // End for loop. 

    // Swap buffers. 
} 
+0

+1准确。这可能是问题所在。我没有在代码中看到任何Modelview矩阵初始化。另外,我看到holtavolt已经将矩阵初始化放在openGL循环中,所以它在每一帧都被初始化。 – 2011-04-13 03:19:21

+0

我没有找到有关opengl网站的文档非常有帮助。我不明白这些评论大部分意味着什么,而且大多数评论的谷歌搜索并不是很有启发性。我知道我的问题的答案在于Modelview矩阵和Push和Pop矩阵操作,但我似乎无法解决我原来的解决方案中的问题,或者我需要抛弃所有东西并从头开始。 – datguywhowanders 2011-04-13 04:25:07

+0

好的 - 你可能想从这个NeHe OpenGL教程开始,它独立旋转两个对象以获取表单:http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=04 – holtavolt 2011-04-13 11:04:56

如果我正在阅读你的代码,你只想旋转一个元素吗?如果是这样,这样做:

  • 呼叫glPushMatrix();
  • 然后做你的旋转
  • 商店你旋转多少
  • 然后绘制你的旋转项目
  • 然后调用glPopMatrix();

这只会旋转一个对象。

编辑:

我看到这样做“破坏”了以前的旋转。你能详细说明一下吗?这是翻译/旋转一个对象的正确方法。

我还注意到你没有初始化Modelview矩阵。在设置PROJECTION矩阵后,您应该初始化Modelview矩阵。您还需要确保您将两个矩阵初始化为身份。最后,确保每次刷新屏幕时都要初始化两个矩阵。为了测试这个,在你的矩阵初始化中设置一个断点,看它是否只被命中一次或每帧。

你回答你自己的问题,这是解决方案:

glPushMatrix(); 
glTranslatef(xOffset,yOffset,0); 
glBegin(GL_POLYGON); 
    glColor3f(theColor.red, theColor.green, theColor.blue); 
    glVertex2f(p1.x, p1.y); 
    glVertex2f(p2.x, p2.y); 
    glVertex2f(p3.x, p3.y); 
glEnd(); 
glPopMatrix(); 

而绘制矩形将改变模型视图矩阵,那么它会在模型​​视图矩阵回恢复到什么是前。你真的试过了吗?什么时候错了?

+0

+1,我的想法完全吻合。你能否更详细地说明什么与上面的代码无关? – 2011-04-13 03:20:46

+0

这样做的结果是没有发生转变。在回顾下面的joe_coolish和holtavolt的答案之后,我相信我的错误在于不初始化Modelview Matrix。但是,我仍然在努力以正确的方式来做到这一点,并将其插入到我的代码中。 – datguywhowanders 2011-04-13 04:23:35