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();
}
//運行截圖: