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下载

  • 相关阅读:
    《ERP从内部集成起步》读书笔记——第5章 MRP系统的时间概念 5.1 时间三要素 5.1.1 计划期
    MVC 图片上传小试笔记
    MVC3 something about form
    dotnetcharting.dll 菜鸟笔记
    MVC 下分离业务逻辑,优化修改
    看不见的女朋友
    相信自己
    肉体的痛苦给心灵的折磨一个宣泄的出口
    八零后为什么比我们那时还艰难
    一个人住七年
  • 原文地址:https://www.cnblogs.com/tornadomeet/p/2654327.html
Copyright © 2011-2022 走看看