繁体   English   中英

OpenGL:如何在不移动整个场景的情况下移动2d对象?

[英]OpenGL: How can I move a 2d object without displacing the whole scene?

好吧,我正在尝试使用C ++中的OpenGL重新创建旧的经典导弹命令。 这是我第一次涉足OpenGL,尽管此时我对C ++感到相当满意。

我认为我的第一个任务是弄清楚如何在屏幕上移动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坐标的值,但这只会导致短暂的闪烁,然后将三角形保留在原始位置:

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();
}

我不应该在我的draw函数中使用glFlush() ,而应该使用glutSwapBuffers() 通过这样做,我首先提出的代码:

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

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

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

GL_MODELVIEW就是您所需要的。

从OpenGL FAQ,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.
}

如果我正确地阅读你的代码,你想只旋转一个元素吗? 如果是,请执行以下操作:

  • 调用glPushMatrix();
  • 然后做你的轮换
  • 存储您旋转的数量
  • 然后绘制你的旋转项目
  • 然后调用glPopMatrix();

这只会旋转一个对象。

编辑:

我看到这样做“摧毁”了之前的轮换。 你能详细说说吗? 这是翻译/旋转一个对象的正确方法。

我还注意到你没有初始化Modelview矩阵。 设置PROJECTION矩阵后,应初始化Modelview Matrix。 您还需要确保将两个矩阵初始化为标识。 最后,确保在屏幕刷新时初始化两个矩阵。 要对此进行测试,请在矩阵初始化时设置断点,并查看它是仅被击中一次还是每帧。

你回答了自己的问题,那就是解决方案:

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();

这将在绘制矩形时更改模型视图矩阵,然后将模型视图矩阵恢复为之前的状态。 你真的试过吗? 什么错了?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM