Qt_OpenGL:光照紋理濾波色彩混合小測

Qt_OpenGL:光照紋理濾波色彩混合小測


此測試程序包含了光照、紋理濾波和色彩融合等知識點。

//.h

#ifndef GLWIDGET_H
#define GLWIDGET_H

#include <QtOpenGL>
#include <QWidget>

class GLWidget : public QGLWidget
{
    Q_OBJECT

public:
    explicit GLWidget(QGLWidget *parent = 0);
    ~GLWidget();

protected:
    void initializeGL();
    void paintGL();
    void resizeGL(int width, int height);
    void keyPressEvent(QKeyEvent *e);
    void loadTextures();
    bool fullscreen;
    GLuint texture[3];

private:
    float rotate_angle;
    float zoom;
    float rotate_speed;
    int filter;
    bool light;
    bool blend;

};

#endif // GLWIDGET_H

//.cpp

<pre name="code" class="cpp"><pre name="code" class="cpp">#include "glwidget.h"
#include <QtGui>
#include <QtCore>
#include <QtOpenGL>
#include <glut.h>

static const GLfloat light_ambient[4]={0.5, 0.5, 0.5, 1.0};
static const GLfloat light_diffuse[4]={1.0, 1.0, 1.0, 1.0};
static const GLfloat light_position[4]={0.0, 0.0, 2.0, 0.0};

GLWidget::GLWidget(QGLWidget *parent) :
    QGLWidget(parent)
{
  //  setCaption("The Opengl for Qt Framework");
    fullscreen = false;
    rotate_angle = 0.0;
    zoom = -5.0;
    rotate_speed = 3.0;
    filter = 0;
    light = false;
    blend = false;
}

void GLWidget::initializeGL()
{
    setGeometry(300, 150, 500, 500);//設置窗口初始位置和大小
    loadTextures();
    glEnable(GL_TEXTURE_2D);//允許採用2D紋理技術
    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);//進行透視校正

    /*opengl中支持8個光源,即GL_LIGHT0~GL_LIGHT7*/
    glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient);//指定光源1的環境光參數
    glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse);//指定光源1的漫射光參數
    glLightfv(GL_LIGHT1, GL_POSITION, light_position);//指定光源1的位置
    glEnable(GL_LIGHT1);//允許光源1的使用
  //  glEnable(GL_LIGHTING);//我們還需要啓動總光源開關,默認的時候不開,後面的L鍵來控制開啓和關閉

    glColor4f(1.0, 1.0, 1.0, 0.5);//後面的步驟都是以全亮繪製物體,並且50%的透明度
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
}

void GLWidget::paintGL()
{
    //glClear()函數在這裏就是對initializeGL()函數中設置的顏色和緩存深度等起作用
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    /*下面開始畫立方體,並對其進行紋理映射*/
    glLoadIdentity();
    glTranslatef(0.0, 0.0, zoom);
    glRotatef(rotate_angle, -0.4f, 0.4f, -1.0f);
    glBindTexture(GL_TEXTURE_2D, texture[filter]);//這句代碼一定要,因爲在initializeGL()函數中已綁定一個固定的紋理目標了
    glBegin(GL_QUADS);
    //上頂面
    glNormal3f(0.0, 1.0, 0.0);//該函數指定是法線的方向爲向量(x, y, z)方向,在使用光源且對空間物體進行紋理映射時,
                              //每個面都需要指定其法線的方向,否則會出現各種意外的結果。
    glTexCoord2f(0.0, 1.0);//將2D的紋理座標映射到3D的空間物體表面上
    glVertex3f(-1.0f, 1.0f, -1.0f);
    glTexCoord2f(0.0, 0.0);
    glVertex3f(-1.0f, 1.0f, 1.0f);
    glTexCoord2f(1.0, 0.0);
    glVertex3f(1.0f, 1.0f, 1.0f);
    glTexCoord2f(1.0, 1.0);
    glVertex3f(1.0f, 1.0f, -1.0f);
    //下頂面
    glNormal3f(0.0, -1.0, 0.0);
    glTexCoord2f(0.0, 1.0);
    glVertex3f(-1.0f, -1.0f, -1.0f);
    glTexCoord2f(0.0, 0.0);
    glVertex3f(-1.0f, -1.0f, 1.0f);
    glTexCoord2f(1.0, 0.0);
    glVertex3f(1.0f, -1.0f, 1.0f);
    glTexCoord2f(1.0, 1.0);
    glVertex3f(1.0f, -1.0f, -1.0f);
    //正前面
    glNormal3f(0.0, 0.0, 1.0);
    glTexCoord2f(0.0, 1.0);
    glVertex3f(-1.0f, 1.0f, 1.0f);
    glTexCoord2f(0.0, 0.0);
    glVertex3f(-1.0f, -1.0f, 1.0f);
    glTexCoord2f(1.0, 0.0);
    glVertex3f(1.0f, -1.0f, 1.0f);
    glTexCoord2f(1.0, 1.0);
    glVertex3f(1.0f, 1.0f, 1.0f);
    //右側面
    glNormal3f(1.0, 0.0, 0.0);
    glTexCoord2f(0.0, 1.0);
    glVertex3f(1.0f, 1.0f, 1.0f);
    glTexCoord2f(0.0, 0.0);
    glVertex3f(1.0f, -1.0f, 1.0f);
    glTexCoord2f(1.0, 0.0);
    glVertex3f(1.0f, -1.0f, -1.0f);
    glTexCoord2f(1.0, 1.0);
    glVertex3f(1.0f, 1.0f, -1.0f);
    //背後面
    glNormal3f(0.0, 0.0, -1.0);
    glTexCoord2f(0.0, 1.0);
    glVertex3f(-1.0f, 1.0f, -1.0f);
    glTexCoord2f(0.0, 0.0);
    glVertex3f(1.0f, 1.0f, -1.0f);
    glTexCoord2f(1.0, 0.0);
    glVertex3f(1.0f, -1.0f, -1.0f);
    glTexCoord2f(1.0, 1.0);
    glVertex3f(-1.0f, -1.0f, -1.0f);
    //左側面
    glNormal3f(-1.0, 0.0, 0.0);
    glTexCoord2f(0.0, 1.0);
    glVertex3f(-1.0f, 1.0f, -1.0f);
    glTexCoord2f(0.0, 0.0);
    glVertex3f(-1.0f, -1.0f, -1.0f);
    glTexCoord2f(1.0, 0.0);
    glVertex3f(-1.0f, -1.0f, 1.0f);
    glTexCoord2f(1.0, 1.0);
    glVertex3f(-1.0f, 1.0f, 1.0f);
    glEnd();
    rotate_angle += rotate_speed;
}

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())
    {
        /*L鍵位開啓光照的開關*/
        case Qt::Key_L:
            light = !light;
            if(!light)
                glDisable(GL_LIGHTING);
            else
                glEnable(GL_LIGHTING);
            updateGL();
            break;
        /*B鍵位選擇是否採用色彩融合*/
        case Qt::Key_B:
            blend = !blend;
            if(blend)
                {
                    glEnable(GL_BLEND);
                    glDisable(GL_DEPTH_TEST);
                }
            else
                {
                    glDisable(GL_BLEND);
                    glEnable(GL_DEPTH_TEST);
                }
            updateGL();
            break;
        /*F鍵位選擇紋理濾波的方式*/
        case Qt::Key_F:
            filter += 1;
            if(filter > 2)
                filter = 0;
            updateGL();
            break;
        /*PageUp鍵爲將木箱移到屏幕內部方向*/
        case Qt::Key_PageUp:
            zoom -= 0.2;
            updateGL();
            break;
        /*PageDown鍵爲將木箱移到屏幕外部方向*/
        case Qt::Key_PageDown:
            zoom += 0.2;
            updateGL();
            break;
        /*Up鍵爲加快立方體旋轉的速度*/
        case Qt::Key_Up:
            rotate_speed += 1.0;
            updateGL();
            break;
        /*Down鍵爲減慢立方體旋轉的速度*/
        case Qt::Key_Down:
            rotate_speed -= 1.0;
            updateGL();
            break;
        /*F1鍵爲全屏和普通屏顯示切換鍵*/
        case Qt::Key_F1:
            fullscreen = !fullscreen;
            if(fullscreen)
                showFullScreen();
            else
            {
                setGeometry(300, 150, 500, 500);
                showNormal();
            }
            updateGL();
            break;
        /*Ese爲退出程序鍵*/
        case Qt::Key_Escape:
            close();
    }
}

/*加載紋理*/
void GLWidget::loadTextures()
{
    QImage tex, buf;
    if(!buf.load(":resources/c.jpg"))
   // if(!buf.load(":resources/c.jpg"))
    {
        qWarning("Cannot open the image...");
        QImage dummy(128, 128, QImage::Format_RGB32);//當沒找到所需打開的圖片時,創建一副128*128大小,深度爲32位的位圖
        dummy.fill(Qt::green);
        buf = dummy;
    }
    tex = convertToGLFormat(buf);//將Qt圖片的格式buf轉換成opengl的圖片格式tex
    glGenTextures(3, &texture[0]);//開闢3個紋理內存,索引指向texture[0]

    /*建立第一個紋理*/
    glBindTexture(GL_TEXTURE_2D, texture[0]);
    glTexImage2D(GL_TEXTURE_2D, 0, 3, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    /*建立第二個紋理*/
    glBindTexture(GL_TEXTURE_2D, texture[1]);
    glTexImage2D(GL_TEXTURE_2D, 0, 3, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    /*建立第三個紋理*/
    glBindTexture(GL_TEXTURE_2D, texture[2]);
    gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, tex.width(), tex.height(), GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());
    //該函數對所加載的紋理像素沒有要求是2的n次方,可以是任意的像素
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
    //mipmap方式是當物體很遠時,也能保留很好的細節,所以它的運算量很大,速度很慢,這裏GL_LINEAR_MIPMAP_NEAREST是混合使用
}

GLWidget::~GLWidget()
{
}



//main.cpp

#include "glwidget.h"
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsItem>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    GLWidget w;
    w.show();
    return a.exec();
}

//運行截圖:


發佈了207 篇原創文章 · 獲贊 34 · 訪問量 55萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章