学习OpenGL也有段时间了,前几篇将GL最基本的画图过程解析了一下,后面进阶的就随项目需要再学。因为之前一直是用glut这个实用工具包来开发很方便,但是会附带一个控制台的窗口,实在觉得有些low,因此就打算将GL嵌入到应用程序中去。
下面就把前几章学习的知识结合起来,在QT下实现GL的动画。之所以选QT而非MFC原因有2点,一则是QT是开源的,现在开源的东西都很热闹,所以我也凑凑热闹,之前用MFC做过别的上位机程序,我是个喜欢图新鲜的人;二则QT的移植性好,一次编译到处运行吧。
总结几处注意点:
1.glut的函数是一个也不能使用了,需要自己用QT的Widget类来创建应用窗口,同时再用QGLWidget类创建自己的GL类,将二者绑定在一起;
2.需要重载QGLWidget的三个重要函数initializeGL、resizeGL和paintGL;
3.glClear函数不属于initializeGL,即即使你写入它,在初始化的时候也不会被执行;
4.需要显示裁剪视口以及设定透视方法,这些在之前使用glut中函数的时候会被默认设置和创建窗口匹配。什么意思呢?就是如果不显示设定的话,你会被坐标定位搞得糊里糊涂。这个也是我第一次移植时候遇到的困扰,其实程序是正常运行的,但是要嘛图像歪斜要嘛看不到图像。如果以上一些设置成功,就能随心所欲绘制;
5.glut中的消息响应在QT中都有各自的类;
6.QT的类不比MFC类来的“苗条”,用到哪个查找哪个就ok。
最后上代码。
功能说明文件:
--use keyboard to control the cube
-w- accelerate the rolling speed;
-s- slow down the rolling speed;
-a- change the rolling direction;
-d- opposite with -a-;
-r- reset the initial state;
-c- change color
主函数文件:
#include<QApplication>
#include"myglwidget.h"
int main(int argc,char *argv[])
{
QApplication MyApp(argc,argv);
MyGLWidget MyGL;
MyGL.show();
return MyApp.exec();
}
自定义GL类头文件:
#ifndef MYGLWIDGET_H
#define MYGLWIDGET_H #include <QGLWidget>
#include<QTime>
#include<QTimerEvent>
#include<QKeyEvent>
class MyGLWidget : public QGLWidget
{
Q_OBJECT
public:
explicit MyGLWidget(QWidget *parent = ); signals:
private:
// GLfloat VertexData[24];
// GLubyte VertexIndex[6][4];
float m_rotate;
float m_speed;
bool m_angle;
GLubyte m_color_mode;
int m_T20msID;
void initializeGL();
void resizeGL(int w, int h);
void paintGL();
void timerEvent(QTimerEvent *);
void keyPressEvent(QKeyEvent *);
void Cross(GLfloat,GLubyte);
void ChangeColor(GLubyte mode,GLfloat value);
float GetRand(int,int);
void Draw(void);
void Cube(void);
public slots:
}; #endif // MYGLWIDGET_H
自定义GL类实现:
#include "myglwidget.h"
static GLfloat VertexData[] = {
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
};
static GLubyte VertexIndex[][] = {
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
};
MyGLWidget::MyGLWidget(QWidget *parent) :
QGLWidget(parent)
{
m_speed = 2.0;
m_angle = ;
m_color_mode = ;
m_rotate = ;
m_T20msID = ;
}
void MyGLWidget::initializeGL()
{
glClearColor(,,,);
glClearDepth();
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
m_T20msID = startTimer();
qsrand(QTime::currentTime().msec());
}
void MyGLWidget::resizeGL(int w, int h)
{
glViewport(,,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(w <= h)
glOrtho(-, , -(GLfloat)h/(GLfloat)w, (GLfloat)h/(GLfloat)w, -, );
else
glOrtho(-(GLfloat)w/(GLfloat)h, (GLfloat)w/(GLfloat)h, -, , -, );
}
void MyGLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
Draw();
}
void MyGLWidget::Cube(void)
{
//enable vertex_array
glEnableClientState(GL_VERTEX_ARRAY);
//load vertex_array data
glVertexPointer(,GL_FLOAT,*sizeof(GLfloat),VertexData);
//drawing operation
glDrawElements(GL_QUADS,sizeof(VertexData),GL_UNSIGNED_BYTE,VertexIndex);
}
void MyGLWidget::timerEvent(QTimerEvent *event)
{
if(m_T20msID == event->timerId())
{
updateGL();
}
}
float MyGLWidget::GetRand(int start, int end)
{
return start + (end - start)*qrand()/(RAND_MAX + 1.0);
}
void MyGLWidget::Cross(GLfloat coordinater,GLubyte face)
{
GLfloat rand;
switch(face)
{
//front
case : rand = (GetRand(,)-)/;
glBegin(GL_LINES);
glVertex3f(-0.5f,rand,coordinater);
glVertex3f(0.5f,rand,coordinater);
glEnd();
rand = (GetRand(,)-)/;
glBegin(GL_LINES);
glVertex3f(rand,0.5f,coordinater);
glVertex3f(rand,-0.5f,coordinater);
glEnd();
break;
//left
case : rand = (GetRand(,)-)/;
glBegin(GL_LINES);
glVertex3f(coordinater,-0.5f,rand);
glVertex3f(coordinater,0.5f,rand);
glEnd();
rand = (GetRand(,)-)/;
glBegin(GL_LINES);
glVertex3f(coordinater,rand,0.5f);
glVertex3f(coordinater,rand,-0.5f);
glEnd();
break;
case : rand = (GetRand(,)-)/;
glBegin(GL_LINES);
glVertex3f(-0.5f,coordinater,rand);
glVertex3f(0.5f,coordinater,rand);
glEnd();
rand = (GetRand(,)-)/;
glBegin(GL_LINES);
glVertex3f(rand,coordinater,0.5f);
glVertex3f(rand,coordinater,-0.5f);
glEnd();
break;
default:break;
}
}
void MyGLWidget::Draw()
{
m_rotate += (m_angle)?m_speed:-m_speed;
glRotatef(m_rotate,,,);
glRotatef(m_rotate,,,);
glRotatef(m_rotate,,,);
glColor3f(,,);
//front-red
Cube();
int i;
for(i=;i<;i++)
{
//glColor3f(0,GetRand(0,33)/100,0);
ChangeColor(m_color_mode,GetRand(,)/);
glLineWidth(GetRand(,));
Cross(0.5f,);
}
//back-green
for(i=;i<;i++)
{
//glColor3f(0,GetRand(0,20)/100,0);
ChangeColor(m_color_mode,GetRand(,)/);
glLineWidth(GetRand(,));
Cross(-0.5f,);
}
//left-blue
for(i=;i<;i++)
{
//glColor3f(0,GetRand(46,66)/100,0);
ChangeColor(m_color_mode,GetRand(,)/);
glLineWidth(GetRand(,));
Cross(-0.5f,);
}
//right
for(i=;i<;i++)
{
//glColor3f(0,GetRand(33,66)/100,0);
ChangeColor(m_color_mode,GetRand(,)/);
glLineWidth(GetRand(,));
Cross(0.5f,);
}
//up
for(i=;i<;i++)
{
//glColor3f(0,GetRand(80,100)/100,0);
ChangeColor(m_color_mode,GetRand(,)/);
glLineWidth(GetRand(,));
Cross(0.5f,);
}
//bottom
for(i=;i<;i++)
{
//glColor3f(0,GetRand(66,100)/100,0);
ChangeColor(m_color_mode,GetRand(,)/);
glLineWidth(GetRand(,));
Cross(-0.5f,);
} }
void MyGLWidget::ChangeColor(GLubyte mode,GLfloat value)
{
switch(mode)
{
case :glColor3f(,value,);
break;
case :glColor3f(value,,);
break;
case :glColor3f(,,value);
break;
case :glColor3f(value,value,);
break;
case :glColor3f(value,,value);
break;
case :glColor3f(,value,value);
break;
case :glColor3f(value,value,value);
default:break;
}
}
void MyGLWidget::keyPressEvent(QKeyEvent *event)
{
switch(event->key())
{
case Qt::Key_A:m_angle = ;
break;
case Qt::Key_W:m_speed += 0.5;
break;
case Qt::Key_D:m_angle = ;
break;
case Qt::Key_S:if((m_speed-0.25)<)
m_speed = ;
else
m_speed -= 0.25;
break;
case Qt::Key_R:m_speed = ;
m_angle = ;
break;
case Qt::Key_C:if(m_color_mode == )
m_color_mode = ;
else
m_color_mode++;
break;
case Qt::Key_F:showFullScreen();
break;
case Qt::Key_Escape:close();
default:break;
}
}