OpenGL 保存对象以供以后绘制

发布于 2024-12-19 13:02:51 字数 2784 浏览 3 评论 0原文

我正在使用 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。矩阵保存位于 Components.c 第 1548 行,管理位于第 142 行。如果不对包含内容进行一些小的修改,它可能无法在 Windows 上运行,这可能应该在 global.h 中完成。

编辑:我只能使用C代码和glut库来编写这个程序。

编辑2:问题是 glGetDoublev 由于某种原因没有返回任何内容,它使 modelMatrix 数组完好无损。虽然我仍然不知道是什么原因造成的,但我可以使用伯尼的想法来解决问题。

I'm making a program using openGL with transparent objects in it, so obviously I have to paint those last. Unfortunately I was unaware of this requirement when beginning this project and now it would be a real pain to reorder it painting those at last.

I'm drawing objects by calling my drawing functions after translating and rotating the scene. There can be multiple translations and rotations before an actual drawing (e.g. first I draw the ground, then translate, then call the drawing of the house, which repeatedly translates and rotates, then calls the drawing of the walls and so on).

So my idea was saving the current modelview matrices in a list instead of painting the transparent objects when I normally would, then when I'm done with the opaque stuff, I iterate through my list and load each matrix and paint each object (a window, to be precise).

I do this for saving a matrix:

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

And this is the "transparent stuff management" part:

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

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

I call flushComponents(); at the very end of my drawings.

The problem is, that the windows don't get in their place, instead I get weird-shaped blue objects randomly appearing and disappearing in my scene.

Am I doing something wrong? Or such matrix manipulations cannot even be used like this? Then what other method could I use for doing this?

Here is the full code if you need it: farm.zip Matrix-saving is at components.c line 1548, management is at line 142. It might not work on Windows without some minor hacking with the includes, which should probably be done in global.h.

Edit: I can only use C code and the glut library to write this program.

Edit 2: The problem is glGetDoublev not returning anything for some reason, it leaves the modelMatrix array intact. Though I still have no idea what causes this, I could make a workaround using bernie's idea.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

吃→可爱长大的 2024-12-26 13:02:51

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

OpenGL is not a math library. You should not use it for doing matrix calculations. In fact that part has been completely removed from OpenGL-3. Instead you should rely on a specialized matrix math library. That allows you to calculate the matrices for each object with ease, without jumping through the hoops of OpenGL's glGet… API (which was never meat for this kind of abuse). For a good replacement look at GLM: http://glm.g-truc.net/

故人的歌 2024-12-26 13:02:51

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

您的方法的基本思想很好,并且与我用于透明对象的方法非常相似。然而,出于性能原因,我建议不要从 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 值组成,则上述等式为 true (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 中加载完整的矩阵。这允许您重用矩阵、控制运算精度、轻松查看实际矩阵等。

Try adding glMatrixMode(GL_MODELVIEW) before your paintWindows() method. Perhaps you are not modifying the correct matrix.

The basic idea of your method is fine and is very similar to what I used for transparent objects. I would however advise for performance reasons against reading back the matrices from OpenGL. Instead, you can keep a CPU version of the current modelview matrix and just copy that to your window array.

As for your comment about push and pop matrix, you can safely put it outside the loop like you did.

edit

Strictly speaking, your method of rendering transparent objects misses one step: before rendering the list of windows, you should sort them back to front. This allows for overlapping windows to have the correct final color. In general, for 2 windows and a blending function:

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

However, if all windows consist of the exact same uniform color (e.g. plain texture or no texture) and alpha value, the above equation is true (window0_color==window1_color and window1_alpha==window0_alpha) so you don't need to sort your windows. Also, if it's not possible to have overlapping windows, don't worry about sorting.

edit #2

Now you found something interesting with the erroneous matrix readback. Try it out with the following instead (you certainly don't need double precision):

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

If that still doesn't work, you could directly store references to your houses in your transparent object list. During the transparent rendering pass, re-render each house, but only issue actual OpenGL draw calls for the transparent parts. In your code, putWallStdWith would take another boolean argument specifying whether to render the transparent or the opaque geometry. This way, your succession of OpenGL matrix manipulation calls would be redone for the transparent parts instead of read using glGetxxx(GL_MODEL_VIEW).

The correct way to do it however is to do matrix computation on the CPU and simply load complete matrices in OpenGL. That allows you to reuse matrices, control the operation precision, see the actual matrices easily, etc.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文