OpenGL: Как я могу переместить 2d объект, не смещая всю сцену? - PullRequest
4 голосов
/ 13 апреля 2011

Хорошо, я пытаюсь воссоздать старую классическую ракетную команду, используя OpenGL в C ++.Это мой первый набег в 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();
}

color3f и vertex2f - простые классы:

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

Вместо использования glFlush() внутри моей функции рисования,Я должен был использовать glutSwapBuffers().Сделав это, код, который я впервые придумал:

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

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

Прекрасно работает для моих целей.У меня не было необходимости переводить матрицу, мне просто нужно было нарисовать элемент в другой позиции от одной сцены к другой.

Ответы [ 3 ]

3 голосов
/ 13 апреля 2011

GL_MODELVIEW - это то, что вам нужно.

Из FAQ по 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.
}
1 голос
/ 13 апреля 2011

Вы отвечаете на свой вопрос, вот решение:

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

Это изменит матрицу вида модели во время рисования прямоугольника, а затем вернет матрицу вида модели обратно к тому, что было раньше. Вы действительно пробовали это? Что не так?

1 голос
/ 13 апреля 2011

Если я правильно читаю ваш код, вы хотите повернуть только один элемент, верно?Если это так, сделайте следующее:

  • Позвоните glPushMatrix();
  • , затем выполните вращение
  • Сохраните, сколько вы повернули
  • , затем нарисуйтеваш повернутый элемент
  • , затем вызовите glPopMatrix();

Это будет вращать только один объект.

РЕДАКТИРОВАТЬ:

Я вижу, что делает это«разрушает» предыдущее вращение.Не могли бы вы уточнить?Это правильный способ перевести / повернуть один объект.

Я также заметил, что вы не инициализируете матрицу просмотра модели.Вы должны инициализировать матрицу просмотра модели после того, как настроите матрицу ПРОЕКЦИИ.Вы также должны убедиться, что вы инициализируете обе матрицы для идентичности.И наконец, убедитесь, что вы инициализируете обе матрицы КАЖДЫЙ раз при обновлении экрана.Чтобы проверить это, установите точку останова на инициализации вашей матрицы и посмотрите, будет ли она поражена только один раз или каждый кадр.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...