首页 > 解决方案 > 在 OpenGL 中执行多次反射

问题描述

我的任务是对 2D 对象执行转换(反射)。

假设我的原始对象是一个圆圈:o

例如,我想将它反映在 y = 5 线上。○ | ○

然后,例如,我想在 x = 5 线上反映这两个对象。

__

最后,例如,我想在 y = 10 线上反映四个对象。

哦 | 哦

哦 | 哦

所以最终我希望最终结果包括 8 个圆圈。

我的问题是,我将如何在我的代码中实现它?

这是我的项目的代码:

#include <glut.h>

GLfloat square[4][3] = {{5, 0,0}, {5,20,0},{-5,20,0}, {-5,0,0}};
GLfloat square2[4][3] = { { 10, -5,0 },{ 10,25,0 },{ 0,25,0 },{ 0,-5,0 } };
GLfloat square3[4][3] = { { 0, -5,0 },{ 0,25,0 },{ -10,25,0 },{ -10,-5,0 } };
GLfloat colors[3][3] = {{0,0,1},{1,1,1},{0,0,0}};

void draw_square(void){
     glBegin(GL_POLYGON);
         for(int i = 0; i < 4; i++){
                 glVertex3fv(square[i]);
         }
     glEnd();
}

void draw_square2(void) {
    glBegin(GL_POLYGON);
    for (int i = 0; i < 4; i++) {
        glVertex3fv(square2[i]);
    }
    glEnd();
}

void draw_square3(void) {
    glBegin(GL_POLYGON);
    for (int i = 0; i < 4; i++) {
        glVertex3fv(square3[i]);
    }
    glEnd();
}

void draw_ring(void){
     for(int r =0; r < 360;r+=45){
             glPushMatrix();
             glRotated(r, 0,0,1);
             glTranslated(0,50,0);
             draw_square();
             glPopMatrix();
     }
}

void draw_ring2(void) {
    for (int r = 0; r < 360; r += 45) {
        glPushMatrix();
        glRotated(r, 0, 0, 1);
        glTranslated(0, 50, 0);
        draw_square2();
        glPopMatrix();
    }
}

void draw_ring3(void) {
    for (int r = 0; r < 360; r += 45) {
        glPushMatrix();
        glRotated(r, 0, 0, 1);
        glTranslated(0, 50, 0);
        draw_square3();
        glPopMatrix();
    }
}

下面的显示函数创建了一组我想要反映的重叠环。现在的样子,我只在左下角得到一组重叠的环。我希望输出是 8 组重叠环。我一直在尝试找到一种方法来创建我需要的反射,但我似乎无法弄清楚。

void display(void){
     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


         glPushMatrix();
         glColor3fv(colors[0]);
         draw_ring();
         glColor3fv(colors[1]);
         draw_ring2();
         glColor3fv(colors[2]);
         draw_ring3();

         glPopMatrix();


     glFlush();
}

void main(int argc, char** argv){
     glutInit(&argc, argv);
     glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH);
     glutInitWindowSize(1000,600);
     glutInitWindowPosition(200,100);
     glutCreateWindow("Project 2");
     glClearColor(1.0,1.0,0.0,1.0);
     glEnable(GL_DEPTH_TEST);
     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();
     gluOrtho2D(-100.0, 1000.0, -100.0,600.0);
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     glutDisplayFunc(display);
     glutMainLoop();
}

任何帮助将不胜感激。

标签: c++openglreflectiontransformation

解决方案


请注意,由glBegin/glEnd序列绘制和固定函数管道矩阵堆栈自几十年以来已被弃用。阅读Fixed Function Pipeline并查看Vertex Specification and Shader了解最先进的渲染方式。


无论如何,如果你想平铺对象,那么你可以通过嵌套循环来做到这一点:

void draw_object( void )
{
    glPushMatrix();

    glColor3fv(colors[0]);
    draw_ring();
    glColor3fv(colors[1]);
    draw_ring2();
    glColor3fv(colors[2]);
    draw_ring3();

    glPopMatrix();
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    int   tile_x = 4;
    int   tile_y = 2;
    float tile_dist = 200.0f;

    for ( int x = 0; x < tile_x; ++ x )
    {
          for (int y = 0; y < tile_y; ++ y )
          {
              glPushMatrix();
              glTranslatef( (float)x * tile_dist, (float)y * tile_dist, 0.0f );
              draw_object();
              glPopMatrix();
          }
    }

    glFlush();
}

通过递归函数可以实现相同的平铺效果:

void display_tiles_recursive( int level, float dist )
{
    if ( level == 0 )
    {
        draw_object();
        return;
    }

    int   tile     = level / 2;
    bool  tile_x   = level % 2 != 0;
    float offset_x = tile_x ? pow(2.0f, (float)tile) * dist : 0.0f;
    float offset_y = tile_x ? 0.0f : pow(2.0f, (float)(tile-1)) * dist;

    glPushMatrix();

    display_tiles_recursive( level - 1, dist );
    glTranslatef( offset_x, offset_y, 0.0f );
    display_tiles_recursive( level - 1, dist );

    glPopMatrix();
}

void display_mirror(void)
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    display_tiles_recursive( 3, 200.0f );
    glFlush();
}

如果要实现重复的镜像效果,则必须沿 x 和 y 轴镜像偶数块。镜像可以通过 来实现glScaleglScalef( -1.0f, 1.0f, 1.0f );沿 x 轴glScalef( 1.0f, -1.0f, 1.0f );镜像并沿 y 轴镜像。您可以扩展递归平铺功能以获得此效果:

void display_mirror_recursive( int level, float dist, bool even_x, bool even_y )
{
    if ( level == 0 )
    {
        glPushMatrix();
        if ( even_x )
            glScalef( -1.0f, 1.0f, 1.0f );
        if ( even_y )
            glScalef(  1.0f, -1.0f, 1.0f );
        draw_object();
        glPopMatrix();
        return;
    }

    int   tile     = level / 2;
    bool  tile_x   = level % 2 != 0;
    float offset_x = tile_x ? pow(2.0f, (float)tile) * dist : 0.0f;
    float offset_y = tile_x ? 0.0f : pow(2.0f, (float)(tile-1)) * dist;

    glPushMatrix();
    display_mirror_recursive( level - 1, dist, even_x, even_y );
    glTranslatef( offset_x, offset_y, 0.0f );
    if ( level == 1 )
      even_y = !even_y;
    if ( level == 2)
      even_x = !even_x;
    display_mirror_recursive( level - 1, dist, even_x, even_y );
    glPopMatrix();
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    display_mirror_recursive( 3, 200.0f, false, false );
    glFlush();
}


推荐阅读