OpenGL / GLFW выглядят прозрачными - PullRequest
1 голос
/ 06 октября 2011

При рисовании простого куба с использованием opengl и glfw грани куба выглядят прозрачными.Вот кодИспользуйте клавиши со стрелками для поворота.Я только что заключил в класс, в моей программе.Использование Visual C ++ Ultimate 2010.

#include "GAME.h"
using namespace std;
GAME::GAME() 
{
    glfwInit();
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_LIGHTING); 
    glEnable(GL_LIGHT0); 
    glEnable(GL_LIGHT1); 
    glEnable(GL_NORMALIZE); 
}
int GAME::execute() 
{
    glfwOpenWindow(640, 320, 16, 16, 16, 16, 16, 16, GLFW_WINDOW);
    glfwSetWindowTitle("Viraj");
    glClearColor(1.0, 1.0, 1.0, 1.0);
    glfwSetKeyCallback(events);
    running = true;
    while(glfwGetWindowParam(GLFW_OPENED))
    {
        glfwPollEvents();
        loop();
        render();
    }
    return 0;
}
void GAME::events(int key, int action)
{
    switch(key)
    {
    case GLFW_KEY_UP:
        glRotatef(10, 1, 0, 0);
        break;
    case GLFW_KEY_DOWN:
        glRotatef(-10, 1, 0, 0);
        break;
    case GLFW_KEY_RIGHT:
        glRotatef(10, 0, 1, 0);
        break;
    case GLFW_KEY_LEFT:
        glRotatef(-10, 0, 1, 0);
        break;
    }
}
int GAME::loop()
{
    return 0;
}
int GAME::render()
{
    int win_width;
    int win_height;
    glfwGetWindowSize(&win_width, &win_height);
    const float win_aspect = (float)win_width / (float)win_height;
    glViewport(0, 0, win_width, win_height);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    //glOrtho(-win_aspect, win_aspect, -1., 1., -1., 1.);
    gluPerspective(90, win_aspect, 1, 100.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0, 0, 3.0, 0, 0, 0, 0.0, 1.0, 0.0);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_LIGHTING); 
    glEnable(GL_LIGHT0); 
    glEnable(GL_LIGHT1); 
    glEnable(GL_NORMALIZE); 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glBegin(GL_QUADS);
    glRotatef(-1, 0, 1, 0);
    glColor3f(0.0f, 0.0f, 0.0f);
    //Front
    glVertex3f(0.0, 0.0, 0.0);
    glVertex3f(1.0, 0.0, 0.0);
    glVertex3f(1.0, 1.0, 0.0);
    glVertex3f(0.0, 1.0, 0.0);

    glColor3f(1.0f, 0.0f, 0.0f);
    //Left
    glVertex3f(1.0, 0.0, 0.0);
    glVertex3f(1.0, 0.0, -1.0);
    glVertex3f(1.0, 1.0, -1.0);
    glVertex3f(1.0, 1.0, 0.0);

    glColor3f(0.0f, 1.0f, 0.0f);
    //Back
    glVertex3f(1.0, 0.0, -1.0);
    glVertex3f(1.0, 1.0, -1.0);
    glVertex3f(0.0, 1.0, -1.0);
    glVertex3f(0.0, 0.0, -1.0);

    glColor3f(0.0f, 0.0f, 1.0f);
    //Right
    glVertex3f(0.0, 0.0, -1.0);
    glVertex3f(0.0, 1.0, -1.0);
    glVertex3f(0.0, 1.0, 0.0);
    glVertex3f(0.0, 0.0, 0.0);

    glColor3f(1.0f, 0.0f, 1.0f);
    //Top
    glVertex3f(0.0, 1.0, -0.0);
    glVertex3f(0.0, 1.0, -1.0);
    glVertex3f(1.0, 1.0, -1.0);
    glVertex3f(1.0, 1.0, 0.0);

    glColor3f(1.0f, 1.0f, 0.0f);
    //Bottom
    glVertex3f(0.0, 0.0, 0.0);
    glVertex3f(1.0, 0.0, 0.0);
    glVertex3f(1.0, 0.0, -1.0);
    glVertex3f(0.0, 0.0, -1.0);

    glEnd();
    glfwSwapBuffers();
    return 0;
}

Ответы [ 2 ]

12 голосов
/ 06 октября 2011

Прошу прощения, но ваш код разбит на несколько уровней.Позвольте мне объяснить это для вас:

#include "GAME.h"
using namespace std;
GAME::GAME() 
{
    glfwInit();
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_LIGHTING); 
    glEnable(GL_LIGHT0); 
    glEnable(GL_LIGHT1); 
    glEnable(GL_NORMALIZE); 
}

Здесь кроется первая ошибка: GLFW - это библиотека C, и ее нужно инициализировать точно один раз .Вызов glfwInit() принадлежит основной функции, а не конструктору класса.Другие вызовы функций - это вызовы OpenGL, однако они требуют активного контекста OpenGL.Однако в этой точке программы нет контекста OpenGL, поэтому все вызовы, которые вы выполняете, вообще не действуют.

int GAME::execute() 
{
    glfwOpenWindow(640, 320, 16, 16, 16, 16, 16, 16, GLFW_WINDOW);
    glfwSetWindowTitle("Viraj");
    glClearColor(1.0, 1.0, 1.0, 1.0);

Опять же, природа GLFW не согласуется с использованием в качестве части класса.Вы можете иметь только одно окно в GLFW и только один цикл обработки событий.Это не очень хорошо отображается на классы и объекты.Конечно, у вас может быть класс EventLoop или аналогичный, но вы не будете использовать его таким образом.

А затем есть следующая строка, я удивляюсь, что она фактически скомпилирована:

    glfwSetKeyCallback(events);

events если функция-член класса GAME, и если это не статическая функция-член, вы не можете использовать функцию-член класса в качестве обратного вызова, особенно если это не библиотека C, которая не знает классов,Откуда ему знать, к какому экземпляру относится эта функция события?В C ++ отсутствует концепция замыканий или делегатов , которая требовалась для этого (другие языки делают именно по этой причине).

    running = true;
    while(glfwGetWindowParam(GLFW_OPENED))
    {
        glfwPollEvents();
        loop();
        render();
    }
    return 0;
}

ЧтоТеперь пришло классическое заблуждение новичка:

void GAME::events(int key, int action)
{
    switch(key)
    {
    case GLFW_KEY_UP:
        glRotatef(10, 1, 0, 0);
        break;
    case GLFW_KEY_DOWN:
        glRotatef(-10, 1, 0, 0);
        break;
    case GLFW_KEY_RIGHT:
        glRotatef(10, 0, 1, 0);
        break;
    case GLFW_KEY_LEFT:
        glRotatef(-10, 0, 1, 0);
        break;
    }
}

Вызовы манипуляций с матрицей имеют смысл только в коде чертежа.Вызов glRotate здесь будет просто мешать со стеком матриц, но каждая нормальная функция рендеринга OpenGL будет инициализировать все состояния, поэтому некоторые нормальные значения в начале.

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

int GAME::loop()
{
    return 0;
}

Если это предназначено для цикла, почему нет цикла?

int GAME::render()
{
    int win_width;
    int win_height;
    glfwGetWindowSize(&win_width, &win_height);
    const float win_aspect = (float)win_width / (float)win_height;

Отсутствует только одна деталь: Вы должны установить область просмотра здесь.Ничего страшного: glViewport(0, 0, win_width, win_height);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    //glOrtho(-win_aspect, win_aspect, -1., 1., -1., 1.);
    gluPerspective(90, win_aspect, 1, 100.0);

Теперь это действительно хорошо! Вы настраиваете матрицу проекции в функции рендеринга.Вперед, придерживайтесь этого шаблона!

ОБНОВЛЕНИЕ Однако следующая строка неверна:

    gluLookAt(0, 0, 3.0, 0, 0, 0, 0.0, 1.0, 0.0);

gluLookAt - это функция, предназначенная для выполнения на модель просмотра матрица.Матрица вида модели отвечает как за размещение моделей в мировом пространстве, так и за выравнивание мира с видом, поэтому преобразование составляет model→world, world→view, из которого вы можете уменьшить промежуточный шаг world, чтобы он составлял только model→view.

    glMatrixMode(GL_MODELVIEW);

Здесь вы бы назвали glLoadIdentity(); gluLookAt(...);.Теперь должно стать очевидным, почему делать манипуляции с матрицами в обработчиках событий не имеет смысла.

На самом деле вы должны установить матрицу просмотра модели со всеми преобразованиями, выполняемыми здесь с нуля.

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

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

Однако, прежде чем начать рендеринг, вы должны должны установить все необходимые состояния OpenGL.Помните те «инициализирующие» вызовы OpenGL в конструкторе.Они принадлежат здесь .

    glBegin(GL_QUADS);

    glColor3f(0.0f, 0.0f, 0.0f);
    //Front
    glVertex3f(0.0, 0.0, 0.0);
    glVertex3f(1.0, 0.0, 0.0);
    glVertex3f(1.0, 1.0, 0.0);
    glVertex3f(0.0, 1.0, 0.0);

    glColor3f(1.0f, 0.0f, 0.0f);
    //Left
    glVertex3f(1.0, 0.0, 0.0);
    glVertex3f(1.0, 0.0, -1.0);
    glVertex3f(1.0, 1.0, -1.0);
    glVertex3f(1.0, 1.0, 0.0);

    glColor3f(0.0f, 1.0f, 0.0f);
    //Back
    glVertex3f(1.0, 0.0, -1.0);
    glVertex3f(1.0, 1.0, -1.0);
    glVertex3f(0.0, 1.0, -1.0);
    glVertex3f(0.0, 0.0, -1.0);

    glColor3f(0.0f, 0.0f, 1.0f);
    //Right
    glVertex3f(0.0, 0.0, -1.0);
    glVertex3f(0.0, 1.0, -1.0);
    glVertex3f(0.0, 1.0, 0.0);
    glVertex3f(0.0, 0.0, 0.0);

    glColor3f(1.0f, 0.0f, 1.0f);
    //Top
    glVertex3f(0.0, 0.0, -0.0);
    glVertex3f(0.0, 0.0, -1.0);
    glVertex3f(1.0, 0.0, -1.0);
    glVertex3f(1.0, 0.0, 0.0);

    glColor3f(1.0f, 1.0f, 0.0f);
    //Bottom
    glVertex3f(0.0, 0.0, 0.0);
    glVertex3f(1.0, 0.0, 0.0);
    glVertex3f(1.0, 0.0, -1.0);
    glVertex3f(0.0, 0.0, -1.0);

    glEnd();

Если вы хотите освещение, вам нужно обеспечить нормальные значения.Но я не стал бы добавлять туда большую группу вызовов glNormal: Немедленный режим (glBegin, glEnd) устарел, я настоятельно рекомендую вам ознакомиться с массивами вершин и объектами буферов вершин.

    glfwSwapBuffers();
    return 0;
}

Подведение итогов: уберите звонки GLFW из класса.GLFW не является объектно-ориентированным.Просто используйте его глобально из функции main.Передача событий в классы в порядке, но вы не можете использовать функции-члены класса в качестве обратных вызовов для GLFW.Вам нужно написать некоторую вспомогательную функцию

extern GAME *pGame;
void eventhandler(int key, int action)
{
    pGame->event(key, action);
}

. Также вы можете иметь класс GAME для управления статическим списком всех экземпляров и обеспечения статической функции-члена, которая передает событие всем экземплярам в списке.Или используйте синглтон (однако я думаю, что синглтоны - это анти-паттерн, и его следует избегать).

2 голосов
/ 06 октября 2011

Хотя я не уверен, в чем заключается вопрос (действительно ли они выглядят прозрачными?), Первое очевидное место в вашем коде состоит в том, что вы включаете освещение, но не указываете нормальные векторы для своих вершин.Они необходимы, чтобы сообщить OpenGL, в каком направлении направлен вектор (как ориентирована фактическая поверхность объекта, но в каждой отдельной вершине).

Но в вашем случае куба каждая грань (квад) должна иметьнормальный вектор (то есть каждая вершина четырехугольника должна иметь одинаковую нормаль).Так что просто укажите соответствующий вектор нормали, прежде чем рисовать четыре вершины грани (аналогично тому, как вы задаете цвета).В вашем случае они должны быть (0,0,1) для передней части, (1,0,0) для левой стороны, (0,0, -1) для задней части, (-1,0,0) для правой стороны, (0,1,0) для верхней части и (0, -1,0) для нижней.

Во-вторых, вы не рисуете верхнюю грань, у вас есть две нижние грани (вы забыли установить y = 1для верха).

В-третьих, рекомендуется последовательно упорядочивать вершины граней объекта, чтобы все грани были ориентированы все против часовой стрелки или по часовой стрелке, если смотреть снаружи (на самом деле выопределите, что снаружи, с помощью этой ориентации), но не одних так, а других таким.Несмотря на то, что в вашей текущей конфигурации это не принесет никакого вреда, у вас будут проблемы, если вы включите выборку с обратной стороны (очень распространенный и простой в использовании метод оптимизации) или попытаетесь автоматически вычислить нормали лица.

Еслиэто все сумасшедшие разговоры для вас, а затем углубиться в OpenGL и компьютерную графику в целом.

...