OpenGL保存对象以供以后绘制

时间:2011-12-04 01:15:59

标签: c opengl transparency glut

我正在使用带有透明对象的openGL制作一个程序,所以显然我必须画最后一个。不幸的是,在开始这个项目时我并没有意识到这个要求,现在重新排序它最终将是一个真正的痛苦。

我在翻译和旋转场景后通过调用绘图函数来绘制对象。在实际绘图之前可以有多个平移和旋转(例如,首先我绘制地面,然后平移,然后调用房屋的绘图,重复翻译和旋转,然后调用墙壁的绘图等等。)

所以我的想法是将当前的modelview矩阵保存在列表中,而不是像往常那样绘制透明对象,然后当我完成不透明的东西时,我遍历我的列表并加载每个矩阵并绘制每个对象(准确地说是一个窗口)。

我这样做是为了保存矩阵:

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 Matrix保存位于components.c第1548行,管理位于第142行。如果没有对包含的一些小的黑客行为,它可能无法在Windows上运行应该在global.h中完成。

编辑:我只能使用C代码和过剩库来编写此程序。

编辑2:问题是glGetDoublev由于某种原因没有返回任何内容,它使modelMatrix数组保持原样。虽然我仍然不知道是什么导致这种情况,但我可以使用bernie的想法来解决这个问题。

2 个答案:

答案 0 :(得分:3)

OpenGL不是数学库。您不应该使用它来进行矩阵计算。事实上,该部分已从OpenGL-3中完全删除。相反,你应该依赖一个专门的矩阵数学库。这使您可以轻松地计算每个对象的矩阵,而无需跳过OpenGL的glGet ... API(这种滥用从来没有用过)。如需更好地替换GLM:http://glm.g-truc.net/

答案 1 :(得分:1)

尝试在glMatrixMode(GL_MODELVIEW)方法之前添加paintWindows()。也许你没有修改正确的矩阵。

您的方法的基本思想很好,与我用于透明对象的方法非常相似。然而,我会建议性能原因不要回读OpenGL中的矩阵。相反,您可以保留当前模型视图矩阵的CPU版本,并将其复制到窗口数组中。

至于你关于推送和弹出矩阵的评论,你可以安全地把它放在循环之外。

修改

严格来说,渲染透明对象的方法错过了一步:在渲染窗口列表之前,您应该将它们排序到前面。这允许重叠窗口具有正确的最终颜色。通常,对于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 )

然而,如果所有窗口都包含完全相同的均匀颜色(例如纯纹理或无纹理)和alpha值,则上述等式为真(window0_color == window1_color和window1_alpha == window0_alpha)所以你不需要对窗户进行排序。此外,如果窗口不可能重叠,请不要担心排序。

编辑#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)进行读取。

正确这样做的方法是在CPU上进行矩阵计算,只需在OpenGL中加载完整的矩阵。这允许您重用矩阵,控制操作精度,轻松查看实际矩阵等。