zoukankan      html  css  js  c++  java
  • OpenGL_Qt学习笔记之_04(3D图形的绘制和旋转)

         绘制四棱锥

         四棱锥由5个面构成一个封闭的立体图,其中4个共顶点的侧面是三角形,底面是个四边形。如果我们要绘制一个3D的四棱锥只需要绘制这5个面即可,绘制的方法和前一篇文章OpenGL_Qt学习笔记之_03(平面图形的着色和旋转)的相同。只不过这里的顶点坐标是3维的,所以图像深度那一维不一定为0。因此我们可以事先计算好四棱锥各个顶点的坐标,这对学过立体几何的人来说应该是小case了。然后绘制每个面就可以。

         注意,在opengl中绘制每个面时,所有面给出的顶点的顺序都要按照逆时针或者顺时针(我这里采用的是逆时针),这样才能保证所绘制出来的图像时正确的。

         现在我们在paintGL中开始绘制四棱锥,如果按照NeHe的教程,它只是绘制了个金字塔,并没有底面,只有4个侧面,这里,我采用它的方法,代码如下: 

    /*下面开始画四棱锥*/
        glLoadIdentity();//重置当前的模型观察矩阵
    
        glTranslatef(-0.5, 0.0, -0.5);//将绘制平面移动到屏幕的左半平面和里面
    
        glRotatef(x_rotate, 0.2, 0.2, 0.0);
    
        glBegin(GL_TRIANGLES);
    
        /*前正面的绘制*/
    
        glColor3f(1.0, 0.0, 0.0);//上顶点红色
    
        glVertex3f(0.0, 0.3, 0.0);
    
        glColor3f(0.0, 0.0, 1.0);//左下点蓝色
    
        glVertex3f(-0.3, -0.3, 0.3);
    
        glColor3f(0.0, 1.0, 0.0);//右下角绿色
    
        glVertex3f(0.3, -0.3, 0.3);
    
        /*右侧面的绘制*/
    
        glColor3f(1.0, 0.0, 0.0);//上顶点红色
    
        glVertex3f(0.0, 0.3, 0.0);
    
        glColor3f(0.0, 0.0, 1.0);//左下点蓝色
    
        glVertex3f(0.3, -0.3, 0.3);
    
        glColor3f(0.0, 1.0, 0.0);//右下角绿色
    
        glVertex3f(0.3, -0.3, -0.3);
    
        /*后侧面的绘制*/
    
        glColor3f(1.0, 0.0, 0.0);//上顶点红色
    
        glVertex3f(0.0, 0.3, 0.0);
    
        glColor3f(0.0, 0.0, 1.0);//左下点蓝色
    
        glVertex3f(0.3, -0.3, -0.3);
    
        glColor3f(0.0, 1.0, 0.0);//右下角绿色
    
        glVertex3f(-0.3, -0.3, -0.3);
    
        /*左侧面的绘制*/
    
        glColor3f(1.0, 0.0, 0.0);//上顶点红色
    
        glVertex3f(0.0, 0.3, 0.0);
    
        glColor3f(0.0, 0.0, 1.0);//左下点蓝色
    
        glVertex3f(-0.3, -0.3, -0.3);
    
        glColor3f(0.0, 1.0, 0.0);//右下角绿色
    
        glVertex3f(-0.3, -0.3, 0.3);
    
        x_rotate_angle1 += 3.0;
    
    glEnd();

      在绘制完金子塔后,把它沿某一个方向旋转后如下图所示:

      

      如果我们在后面加上代码,把底面补全,画上一个四边形,此时加入的代码如下:

     /*底面四边形的绘制,使四棱锥封闭起来*/
    
        glBegin(GL_QUADS);
    
        glColor3f(0.0, 0.0, 1.0);//上顶点红色
    
        glVertex3f(-0.3, -0.3, 0.3);
    
        glColor3f(0.0, 1.0, 0.0);//左下点蓝色
    
        glVertex3f(0.3, -0.3, 0.3);
    
        glColor3f(0.0, 0.0, 1.0);//右下角绿色
    
        glVertex3f(0.3, -0.3, -0.3);
    
        glColor3f(0.0, 1.0, 0.0);
    
        glVertex3f(-0.3, -0.3, -0.3);
    
    glEnd();

      这时候的结果如下:

      

      绘制立方体

      绘制立方体的方法和四棱锥的方法类似,只不过这里是由6个正方形构成的封闭体,我们依次绘制出每个面即可,同样要注意的是绘制每个面时给出点的顺序要一致,绘制每个面的顺序倒不需要按照什么逆时针或者顺时针,什么顺序都行。

      计算好正方体的8个顶点坐标后就开始写代码了,代码如下:

    /*下面开始画立方体*/
    
        glLoadIdentity();
    
        glTranslated(0.5, 0, 0.5);//将绘制平面移动到屏幕的右半平面和外面
    
        glRotatef(rotate_angle2, -0.2, 0.2, -0.3);
    
        glBegin(GL_QUADS);
    
        //上顶面
    
        glColor3f(0.0, 1.0, 0.0);
    
        glVertex3f(-0.3, 0.3, -0.3);
    
        glVertex3f(-0.3, 0.3, 0.3);
    
        glVertex3f(0.3, 0.3, 0.3);
    
        glVertex3f(0.3, 0.3, -0.3);
    
        //下顶面
    
        glColor3f(0.0, 1.0, 0.0);
    
        glVertex3f(-0.3, -0.3, -0.3);
    
        glVertex3f(-0.3, -0.3, 0.3);
    
        glVertex3f(0.3, -0.3, 0.3);
    
        glVertex3f(0.3, -0.3, -0.3);
    
        //正前面
    
        glColor3f(1.0, 0.0, 0.0);
    
        glVertex3f(-0.3, 0.3, 0.3);
    
        glVertex3f(-0.3, -0.3, 0.3);
    
        glVertex3f(0.3, -0.3, 0.3);
    
        glVertex3f(0.3, 0.3, 0.3);
    
        //右侧面
    
        glColor3f(1.0, 1.0, 0.0);
    
        glVertex3f(0.3, 0.3, 0.3);
    
        glVertex3f(0.3, -0.3, 0.3);
    
        glVertex3f(0.3, -0.3, -0.3);
    
        glVertex3f(0.3, 0.3, -0.3);
    
        //背后面
    
        glColor3f(0.0, 1.0, 1.0);
    
        glVertex3f(-0.3, 0.3, -0.3);
    
        glVertex3f(0.3, 0.3, -0.3);
    
        glVertex3f(0.3, -0.3, -0.3);
    
        glVertex3f(-0.3, -0.3, -0.3);
    
        //左侧面
    
        glColor3f(1.0, 0.0, 1.0);
    
        glVertex3f(-0.3, 0.3, -0.3);
    
        glVertex3f(-0.3, -0.3, -0.3);
    
        glVertex3f(-0.3, -0.3, 0.3);
    
        glVertex3f(-0.3, 0.3, 0.3);
    
        rotate_angle2 -= 3;
    
    glEnd();

      其效果如下:

       

      当两者放在一起,且经过不同轴的旋转后图像如下:

      

      实验主要部分代码如下(附录有工程code下载地址):

    #include "glwidget.h"
    #include "ui_glwidget.h"
    
    #include <QtGui>
    #include <QtCore>
    #include <QtOpenGL>
    
    GLWidget::GLWidget(QGLWidget *parent) :
        QGLWidget(parent),
        ui(new Ui::GLWidget)
    {
      //  setCaption("The Opengl for Qt Framework");
        ui->setupUi(this);
        fullscreen = false;
        rotate_angle1 = 0.0;
        rotate_angle2 = 0.0;
    }
    
    //这是对虚函数,这里是重写该函数
    void GLWidget::initializeGL()
    {
        setGeometry(300, 150, 640, 480);//设置窗口初始位置和大小
        glShadeModel(GL_SMOOTH);//设置阴影平滑模式
        glClearColor(0.0, 0.0, 0.0, 0);//改变窗口的背景颜色,不过我这里貌似设置后并没有什么效果
        glClearDepth(1.0);//设置深度缓存
        glEnable(GL_DEPTH_TEST);//允许深度测试
        glDepthFunc(GL_LEQUAL);//设置深度测试类型
        glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);//进行透视校正
    }
    
    void GLWidget::paintGL()
    {
        //glClear()函数在这里就是对initializeGL()函数中设置的颜色和缓存深度等起作用
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        /*下面开始画四棱锥*/
        glLoadIdentity();//重置当前的模型观察矩阵
        glTranslatef(-0.5, 0.0, -0.5);//将绘制平面移动到屏幕的左半平面和里面
        glRotatef(rotate_angle1, 0.2, 0.2, 0.0);
        glBegin(GL_TRIANGLES);
        /*前正面的绘制*/
        glColor3f(1.0, 0.0, 0.0);//上顶点红色
        glVertex3f(0.0, 0.3, 0.0);
        glColor3f(0.0, 0.0, 1.0);//左下点蓝色
        glVertex3f(-0.3, -0.3, 0.3);
        glColor3f(0.0, 1.0, 0.0);//右下角绿色
        glVertex3f(0.3, -0.3, 0.3);
        /*右侧面的绘制*/
        glColor3f(1.0, 0.0, 0.0);//上顶点红色
        glVertex3f(0.0, 0.3, 0.0);
        glColor3f(0.0, 0.0, 1.0);//左下点蓝色
        glVertex3f(0.3, -0.3, 0.3);
        glColor3f(0.0, 1.0, 0.0);//右下角绿色
        glVertex3f(0.3, -0.3, -0.3);
        /*后侧面的绘制*/
        glColor3f(1.0, 0.0, 0.0);//上顶点红色
        glVertex3f(0.0, 0.3, 0.0);
        glColor3f(0.0, 0.0, 1.0);//左下点蓝色
        glVertex3f(0.3, -0.3, -0.3);
        glColor3f(0.0, 1.0, 0.0);//右下角绿色
        glVertex3f(-0.3, -0.3, -0.3);
        /*左侧面的绘制*/
        glColor3f(1.0, 0.0, 0.0);//上顶点红色
        glVertex3f(0.0, 0.3, 0.0);
        glColor3f(0.0, 0.0, 1.0);//左下点蓝色
        glVertex3f(-0.3, -0.3, -0.3);
        glColor3f(0.0, 1.0, 0.0);//右下角绿色
        glVertex3f(-0.3, -0.3, 0.3);
        rotate_angle1 += 3.0;
        glEnd();
        /*底面四边形的绘制,使四棱锥封闭起来*/
        glBegin(GL_QUADS);
        glColor3f(0.0, 0.0, 1.0);//上顶点红色
        glVertex3f(-0.3, -0.3, 0.3);
        glColor3f(0.0, 1.0, 0.0);//左下点蓝色
        glVertex3f(0.3, -0.3, 0.3);
        glColor3f(0.0, 0.0, 1.0);//右下角绿色
        glVertex3f(0.3, -0.3, -0.3);
        glColor3f(0.0, 1.0, 0.0);
        glVertex3f(-0.3, -0.3, -0.3);
        glEnd();
    
        /*下面开始画立方体*/
        glLoadIdentity();
        glTranslated(0.5, 0, 0.5);//将绘制平面移动到屏幕的右半平面和外面
        glRotatef(rotate_angle2, -0.2, 0.2, -0.3);
        glBegin(GL_QUADS);
        //上顶面
        glColor3f(0.0, 1.0, 0.0);
        glVertex3f(-0.3, 0.3, -0.3);
        glVertex3f(-0.3, 0.3, 0.3);
        glVertex3f(0.3, 0.3, 0.3);
        glVertex3f(0.3, 0.3, -0.3);
        //下顶面
        glColor3f(0.0, 1.0, 0.0);
        glVertex3f(-0.3, -0.3, -0.3);
        glVertex3f(-0.3, -0.3, 0.3);
        glVertex3f(0.3, -0.3, 0.3);
        glVertex3f(0.3, -0.3, -0.3);
        //正前面
        glColor3f(1.0, 0.0, 0.0);
        glVertex3f(-0.3, 0.3, 0.3);
        glVertex3f(-0.3, -0.3, 0.3);
        glVertex3f(0.3, -0.3, 0.3);
        glVertex3f(0.3, 0.3, 0.3);
        //右侧面
        glColor3f(1.0, 1.0, 0.0);
        glVertex3f(0.3, 0.3, 0.3);
        glVertex3f(0.3, -0.3, 0.3);
        glVertex3f(0.3, -0.3, -0.3);
        glVertex3f(0.3, 0.3, -0.3);
        //背后面
        glColor3f(0.0, 1.0, 1.0);
        glVertex3f(-0.3, 0.3, -0.3);
        glVertex3f(0.3, 0.3, -0.3);
        glVertex3f(0.3, -0.3, -0.3);
        glVertex3f(-0.3, -0.3, -0.3);
        //左侧面
        glColor3f(1.0, 0.0, 1.0);
        glVertex3f(-0.3, 0.3, -0.3);
        glVertex3f(-0.3, -0.3, -0.3);
        glVertex3f(-0.3, -0.3, 0.3);
        glVertex3f(-0.3, 0.3, 0.3);
        rotate_angle2 -= 3;
        glEnd();
    }
    
    //该程序是设置opengl场景透视图,程序中至少被执行一次(程序启动时).
    void GLWidget::resizeGL(int width, int height)
    {
        if(0 == height)
            height = 1;//防止一条边为0
        glViewport(0, 0, (GLint)width, (GLint)height);//重置当前视口,本身不是重置窗口的,只不过是这里被Qt给封装好了
        glMatrixMode(GL_PROJECTION);//选择投影矩阵
        glLoadIdentity();//重置选择好的投影矩阵
       // gluPerspective(45.0, (GLfloat)width/(GLfloat)height, 0.1, 100.0);//建立透视投影矩阵
        glMatrixMode(GL_MODELVIEW);//以下2句和上面出现的解释一样
    
        glLoadIdentity();
    
    
    }
    void GLWidget::keyPressEvent(QKeyEvent *e)
    {
        switch(e->key())
        {
            //F1键为全屏和普通屏显示切换键
            case Qt::Key_F1:
                fullscreen = !fullscreen;
                if(fullscreen)
                    showFullScreen();
                else
                {
                    setGeometry(300, 150, 640, 480);
                    showNormal();
                }
                updateGL();
                break;
            //Ese为退出程序键
            case Qt::Key_Escape:
                close();
        }
    }
    
    GLWidget::~GLWidget()
    {
        delete ui;
    }

      总结:本文在前面文章绘制2D图像和旋转的基础上,增加一维的坐标就可以绘制出3D图形即旋转了。在画3D图时,必须将OpenGL屏幕想象成一张很大的画纸,后面还带着许多透明的层。差不多就是个由大量的点组成的立方体。这些点从左至右、从上至下、从前到后的布满了这个3D图的表面。

      参考资料:

      http://nehe.gamedev.net/ 

      http://www.owlei.com/DancingWind/

      http://www.qiliang.net/old/nehe_qt/

      附录:

      实验工程code下载

  • 相关阅读:
    LeetCode Count of Range Sum
    LeetCode 158. Read N Characters Given Read4 II
    LeetCode 157. Read N Characters Given Read4
    LeetCode 317. Shortest Distance from All Buildings
    LeetCode Smallest Rectangle Enclosing Black Pixels
    LeetCode 315. Count of Smaller Numbers After Self
    LeetCode 332. Reconstruct Itinerary
    LeetCode 310. Minimum Height Trees
    LeetCode 163. Missing Ranges
    LeetCode Verify Preorder Serialization of a Binary Tree
  • 原文地址:https://www.cnblogs.com/tornadomeet/p/2654327.html
Copyright © 2011-2022 走看看