OpenGL сохранение объектов для последующего рисования - PullRequest
1 голос
/ 04 декабря 2011

Я делаю программу, использующую openGL с прозрачными объектами в ней, так что, очевидно, я должен нарисовать их последними. К сожалению, я не знал об этом требовании, когда начинал этот проект, и теперь было бы очень больно менять его порядок, наконец, рисуя их.

Я рисую объекты, вызывая свои функции рисования после перевода и поворота сцены. Перед фактическим рисунком может быть несколько переводов и поворотов (например, сначала я рисую землю, затем переводю, затем вызываю чертеж дома, который многократно переводит и вращает, затем вызывает рисунок стен и т. Д.).

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

Я делаю это для сохранения матрицы:

GLdouble * modelMatrix = (GLdouble *)malloc(16 * sizeof(GLdouble));
glGetDoublev(GL_MODELVIEW, modelMatrix);
addWindow(modelMatrix); // save it for later painting

И это часть "прозрачного управления вещами":

/***************************************************************************
 *** TRANSPARENT STUFF MANAGEMENT ******************************************
**************************************************************************/

typedef struct wndLst {
    GLdouble * modelMatrix;
    struct wndLst * next;
} windowList;

windowList * windows = NULL;
windowList * pWindow;

void addWindow(GLdouble * windowModelMatrix) {
    pWindow = (windowList *)malloc(sizeof(windowList));
    pWindow->modelMatrix = windowModelMatrix;
    pWindow->next = windows;
    windows = pWindow;
}

void clearWindows() {
    while(windows != NULL) {
        pWindow = windows->next;
        free(windows->modelMatrix);
        free(windows);
        windows = pWindow;
    }
}

void paintWindows() {

    glPushMatrix(); // I've tried putting this and the pop inside the loop, but it didn't help either
        pWindow = windows;

        while(pWindow != NULL) {
            glLoadMatrixd(pWindow->modelMatrix);

            Size s;

            s.height = 69;
            s.width = 49;
            s.length = 0.1;

            glEnable(GL_BLEND);
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            glDepthMask(GL_FALSE);

            glColor4f(COLOR_GLASS, windowAlpha);
            drawCuboid(s);

            glDepthMask(GL_TRUE);
            glDisable(GL_BLEND);

            pWindow = pWindow->next;
        }
    glPopMatrix();
}

/* INTERFACE
 * paint all the components, that are not yet painted,
 * then clean up.
 */
void flushComponents() {
    paintWindows();
    clearWindows();
}

/**************************************************************************/

Я вызываю flushComponents (); в самом конце моих рисунков.

Проблема в том, что окна не встают на свои места, вместо этого в моей сцене случайно появляются и исчезают синие объекты странной формы.

Я что-то не так делаю? Или такие матричные манипуляции не могут быть использованы даже так Тогда какой другой метод я мог бы использовать для этого?

Вот полный код, если он вам нужен: farm.zip Сохранение матрицы в компонентах.c строка 1548, управление в строке 142. Оно может не работать в Windows без незначительного взлома с помощью include, что, вероятно, должно быть сделано в global.h.

Редактировать: Я могу использовать только код C и библиотеку переизбытка для написания этой программы.

Редактировать 2: Проблема в том, что glGetDoublev по какой-то причине ничего не возвращает, оставляет массив modelMatrix нетронутым. Хотя я до сих пор не знаю, чем это вызвано, я мог бы обойти эту проблему, используя идею Берни.

Ответы [ 2 ]

3 голосов
/ 04 декабря 2011

OpenGL не математическая библиотека. Вы не должны использовать его для выполнения матричных вычислений. Фактически эта часть была полностью удалена из OpenGL-3. Вместо этого вы должны полагаться на специализированную матричную математическую библиотеку. Это позволяет вам с легкостью вычислять матрицы для каждого объекта, не перепрыгивая через циклы API OpenGL glGet… (который никогда не был источником для такого рода злоупотреблений). Для хорошей замены посмотрите на GLM: http://glm.g -truc.net /

1 голос
/ 04 декабря 2011

Попробуйте добавить glMatrixMode(GL_MODELVIEW) перед вашим paintWindows() методом.Возможно, вы не изменяете правильную матрицу.

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

Что касается вашего комментария о матрицах push и pop, вы можете безопасно поместить его вне цикла, как вы это делали.

edit

Строго говоря, ваш метод рендеринга прозрачных объектов пропускает один шаг: перед рендерингом списка окон вы должны отсортировать их обратно вперед.Это позволяет перекрывающимся окнам иметь правильный конечный цвет.Как правило, для 2 окон и функции наложения:

blend( blend(scene_color, window0_color, window0_alpha), window1_color, window1_alpha )
!=
blend( blend(scene_color, window1_color, window1_alpha), window0_color, window0_alpha )

Однако , если все окна состоят из одного и того же однородного цвета (например, простая текстура или без текстуры) и альфа-значения,вышеприведенное уравнение является верным (window0_color == window1_color и window1_alpha == window0_alpha), поэтому вам не нужно сортировать окна.Кроме того, если невозможно иметь перекрывающиеся окна, не беспокойтесь о сортировке.

edit # 2

Теперь вы обнаружили что-то интересное с ошибочной обратной матрицей.Вместо этого попробуйте следующее (вам определенно не нужна двойная точность):

GLfloat* modelMatrix = (GLfloat*)malloc(16 * sizeof(GLfloat)); // glass
glGetFloatv(GL_MODELVIEW, modelMatrix);
addWindow(modelMatrix); // save it for later painting

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

Однако правильный способ сделать это состоит в том, чтобы выполнить матричные вычисления напроцессор и просто загрузить полные матрицы в OpenGL.Это позволяет повторно использовать матрицы, контролировать точность операций, легко просматривать фактические матрицы и т. Д.

...