我正在使用带有透明对象的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的想法来解决这个问题。
答案 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)所以你不需要对窗户进行排序。此外,如果窗口不可能重叠,请不要担心排序。
现在你发现错误的矩阵回读有趣了。请尝试使用以下代码(您当然不需要双精度):
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中加载完整的矩阵。这允许您重用矩阵,控制操作精度,轻松查看实际矩阵等。