0

我正在尝试在 OpenGL 中创建镜像。我发现的大多数参考资料都建议使用模板缓冲区来定义镜子本身的边界,并结合使用平移和缩放矩阵来进行实际反射。当观察场景时,我设法让它工作,这样镜子前面就没有物体了。然而,当一个物体在镜子前面时,重叠部分不会显示出来,使它看起来好像它在镜子后面。我很有可能误解了模板缓冲区的工作原理,因为这是我第一次尝试使用它,但我也可能在深度或其他方面犯了一些错误。我会很感激任何建议。这是代码。

#include <gl/glut.h>

// perspective
void view(void) {
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-2.0, 2.0, -2.0, 2.0, -2.0, 2.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glRotatef(-85.0, 1.0, 0.0, 0.0);
    glScalef(0.25, 0.25, 0.25);
}

void init(void) {
    glEnable(GL_DEPTH_TEST);
    glClearStencil(0);
    glEnable(GL_STENCIL_TEST);
}

void mirror(GLboolean inside, GLfloat vertSet[4][3]) {
    GLint i;
    if(inside)
        glBegin(GL_QUADS); // draw inside of mirror
    else
        glBegin(GL_LINE_LOOP); // draw frame of mirror
            for(i = 0; i < 4; i++)
                glVertex3fv(vertSet[i]);
    glEnd();
}

void scene(void) {
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glRotatef(90.0, 1.0, 0.0, 0.0);
    glutSolidTeapot(1.0);
    glPopMatrix();
}

void display(void) {
    GLfloat vertSet1[4][3] = {{-3.0, 3.0, 0.0}, {2.0, 3.0, 0.0}, 
        {2.0, 3.0, 2.0}, {-3.0, 3.0, 2.0}};

    view();

    // store mirror shape in the stencil buffer.
    glClear(GL_STENCIL_BUFFER_BIT);
    glStencilFunc(GL_ALWAYS, 1, 1);
    glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
    mirror(true, vertSet1);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // draw mirror frame.
    glColor3f(0.0, 0.0, 0.0);
    mirror(false, vertSet1);

    // draw scene outside mirror
    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
    glStencilFunc(GL_NOTEQUAL, 1, 1);
    scene();

    // draw reflection of scene in mirror
    glStencilFunc(GL_EQUAL, 1, 1);
    glTranslatef(0.0, 3.0, 0.0);
    glScalef(1.0, -1.0, 1.0);
    glTranslatef(0.0, -3.0, 0.0);
    scene();

    glFlush();
    glutSwapBuffers();
    glutPostRedisplay();
}

int main (int argc, char **argv) {
    glutInit(&argc, argv);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(0, 0);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_STENCIL | GLUT_DEPTH);
    glutCreateWindow("");

    glClearColor(1.0, 1.0, 1.0, 0.0);

    init();

    glutDisplayFunc(display);

    glutMainLoop();
}
4

2 回答 2

4

模板的想法是,当您通常在场景中渲染镜子的玻璃时绘制它。您希望对模板的绘图进行深度测试。完成场景渲染后,在镜像平面中添加一个剪辑平面,然后清除深度缓冲区并重新绘制场景。由于您清除了深度缓冲区,因此您需要先对模板进行深度测试,以使镜子不会过度绘制世界上已经绘制的对象。

请注意,绘制镜子本质上与绘制门户相同。

于 2013-01-20T12:02:05.757 回答
0

这是我在旧 opengl 中进行反射的代码,希望对您有所帮助请注意,大部分代码来自 NeHe 教程: http: //nehe.gamedev.net/tutorial/clipping__reflections_using_the_stencil_buffer/17004/

double eqr[] = { 0.0f, -1.0f, 0.0f, 0.0f };
glColorMask(0, 0, 0, 0);

glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, 1); 
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);  

glDisable(GL_DEPTH_TEST);   
DrawFloor();    // draw flor to the stencil buffer

glColorMask(1, 1, 1, 1);            
glStencilFunc(GL_EQUAL, 1, 1);      

glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

glEnable(GL_CLIP_PLANE0);       

glClipPlane(GL_CLIP_PLANE0, eqr);
glPushMatrix();
    glScalef(1.0f, -1.0f, 1.0f);
    //glLightfv(GL_LIGHT0, GL_POSITION, light_pos);     
    glFrontFace(GL_CW);
    glTranslatef(0.0f, 0.3f, 0.0);
    RenderScene();
    glFrontFace(GL_CCW);
glPopMatrix();
glDisable(GL_CLIP_PLANE0);                  
glDisable(GL_STENCIL_TEST); 

glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glColor4f(0.6f, 0.7f, 1.0f, 0.5f);
    DrawFloor();    // draw floor second time
glDisable(GL_BLEND);

// draw normal scene
glPushMatrix();
    glColor3f(1.0f, 1.0f, 1.0f);
    glTranslatef(0.0f, 0.3f, 0.0);
    RenderScene();
glPopMatrix();

为了获得更好的结果,您可以使用 RenderToTexture 或使用立方体贴图

于 2013-01-20T09:09:40.267 回答