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 に答える