Qt OpenGL教程
最近一段时间除了学习Qt,翻译Qt文档之外,由于工作和兴趣的原因,开始着手看Qt OpenGL编程。在网上搜索了有关OpenGL的教程,发现NeHe的OpenGL教程的还很不错,作者是NeHe。上面有很多种语言的实现,但是没有Qt和Gtk的,所以我就想着手写这个Qt OpenGL教程,每课的内容和NeHe是一样的。另外,介绍NeHe的一个中文翻译站点CSDN-CKer翻译的NeHe的OpenGL教程,翻译人是CKer,在我学习这个教程的过程中,给了我很大的帮助。
下面就是Qt OpenGL教程的内容:
Qt OpenGL的准备工作
第一课:创建一个OpenGL窗口
第二课:你的第一个多边形
第三课:上
第四课:旋转
第五课:向三维进军
第六课:纹理映射
第七课:纹理滤波、光源和键盘控制
第八课:融合
第九课:在三维空间中移动位图
第十课:载入一个三维世界并在其中移动
第十一课:旗的效果(波动纹理)
第十二课:显示列表
第十三课:位图字体
第十四课:轮廓字体
第十五课:使用纹理映射的轮廓字体
第十六课:看起来很棒的雾
因为本教程是从NeHe的OpenGL教程迁移过来的,代码变为Qt实现的。所以有的课程一时还没有实现成功,所以可能有些教程是跳跃的。
因本人时间有限,所以难免有错误出现,如果您发现了这些错误,或者有什么建议,请来信指教,谢谢。
Qt OpenGL的准备工作
因为Qt存在很多版本,另外它支持的平台也很多,到目前为止我只实验了几个组合,所以就先把这些列出来吧,欢迎大家补充。
Unix/X11
Linux
Qt:自由版或者企业版都支持OpenGL模块,而专业版则不能。我现在使用的是3.1.0自由版和企业版。
gcc:编译器。我现在使用的是3.2。
X:Linux下的图形环境。我现在使用的是4.2.0。
Mesa:自由的OpenGL。我现在使用的是5.0。
Windows
Qt:企业版支持OpenGL模块,而专业版则不能。我现在使用的是3.1.0企业版。
Microsoft Visual Studio:编译器。我现在使用的是6.0。
创建一个OpenGL窗口
我假设您对Qt编程已经有了一定的了解,如果您还没有熟悉Qt编程,建议您先学习一下Qt编程的基础知识。
Qt中已经包含了OpenGL模块,具体情况您可以参考Qt OpenGL模块的相关内容。
NeHeWidget类
这就是我们继承QGLWidget类得到的OpenGL窗口部件类。
(由nehewidget.h展开。)
#include <qgl.h>
class NeHeWidget : public QGLWidget
{
    Q_OBJECT
因为QGLWidget类被包含在qgl.h头文件中,所以我们的类就需要包含这个头文件。Q_OBJ
ECT是Qt中的一个专用的宏,具体说明请参见Qt的文档。
public:
   
  NeHeWidget( QWidget* parent = 0, const char* name = 0, bool fs = false );
  ~NeHeWidget();
protected:
  void initializeGL();
  void paintGL();
  void resizeGL( int width, int height );
因为QGLWidget类已经内置了对OpenGL的处理,就是通过对initializeGL()、paintGL()和resizeGL()这个三个函数实现的,具体情况可以参考QGLWidget类的文档。
因为我们的这个Qt OpenGL教程取材于NeHe OpenGL教程,所以这里就用这个NeHeWidget类来继承QGLWidget类来使用相关OpenGL的功能。
initializeGL()是用来初始化这个OpenGL窗口部件的,可以在里面设定一些有关选项。paintGL()就是用来绘制OpenGL的窗口了,只要有更新发生,这个函数就会被调用。resizeGL()就是用来处理窗口大小变化这一事件的,width和height就是新的大小状态下的宽和高了,另外resizeGL()在处理完后会自动刷新屏幕。
  void keyPressEvent( QKeyEvent *e );
这是Qt里面的鼠标按下事件处理函数。
protected:
  bool fullscreen;
用来保存窗口是否处于全屏状态的变量。
};
(由nehewidget.cpp展开。)
#include "nehewidget.h"
NeHeWidget::NeHeWidget( QWidget* parent, const char* name, bool fs )
    : QGLWidget( parent, name )
{
  fullscreen = fs;
保存窗口是否为全屏的状态。
  setGeometry( 0, 0, 640, 480 );
设置窗口的位置,即左上角为(0,0)点,大小为640*480。
setCaption( "NeHe's OpenGL Framework" );
设置窗口的标题为“NeHe's OpenGL Framework”。
  if ( fullscreen )
    showFullScreen();
如果fullscreen为真,那么就全屏显示这个窗口。
}
这个是构造函数,parent就是父窗口部件的指针,name就是这个窗口部件的名称,fs就是窗口是否最大化。
NeHeWidget::~NeHeWidget()
{
}
这个是析构函数。
void NeHeWidget::initializeGL()
{
  glShadeModel( GL_SMOOTH );
这一行启用smooth shading(阴影平滑)。阴影平滑通过多边形精细的混合彩,并对外部光进行平滑。我将在另一个教程中更详细的解释阴影平滑。
  glClearColor( 0.0, 0.0, 0.0, 0.0 );
这一行设置清除屏幕时所用的颜。如果您对彩的工作原理不清楚的话,我快速解释一下。彩值的范围从0.0到1.0。0.0代表最黑的情况,1.0就是最亮的情况。glClearColor后的第一个参数是红,第二个是绿,第三个是蓝。最大值也是1.0,代表特定颜分量的最亮情况。最后一个参数是Alpha值。当它用来清除屏幕的时候,我们不用关心第四个数字。现在让它为0.0。我会用另一个教程来解释这个参数。
通过混合三种原(红、绿、蓝),您可以得到不同的彩。希望您在学校里学过这些。因此,当您使用glClearColor(0.0, 0.0, 1.0, 0.0 ),您将用亮蓝来清除屏幕。如果您用glClearColor(0.5, 0.0, 0.0, 0.0 )的话,您将使用中红来清除屏幕。不是最亮(1.0),也不
是最暗 (0.0)。要得到白背景,您应该将所有的颜设成最亮(1.0)。要黑背景的话,您该将所有的颜设为最暗(0.0)。
  glClearDepth( 1.0 );
设置深度缓存。
  glEnable( GL_DEPTH_TEST );
启用深度测试。
  glDepthFunc( GL_LEQUAL );
所作深度测试的类型。
上面这三行必须做的是关于depth buffer(深度缓存)的。将深度缓存设想为屏幕后面的层。深度缓存不断的对物体进入屏幕内部有多深进行跟踪。我们本节的程序其实没有真正使用深度缓存,但几乎所有在屏幕上显示3D场景OpenGL程序都使用深度缓存。它的排序决定那个物体先画。这样您就不会将一个圆形后面的正方形画到圆形上来。深度缓存是Op
enGL十分重要的部分。
  glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
真正精细的透视修正。这一行告诉OpenGL我们希望进行最好的透视修正。这会十分轻微的影响性能。但使得透视图看起来好一点。
}
这个函数中,我们对OpenGL进行所有的设置。我们设置清除屏幕所用的颜,打开深度缓存,启用smooth shading(阴影平滑),等等。这个例程直到OpenGL窗口创建之后才会被调用。
void NeHeWidget::paintGL()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
清楚屏幕和深度缓存。
  glLoadIdentity();
重置当前的模型观察矩阵。
}
这个函数中包括了所有的绘图代码。任何您所想在屏幕上显示的东东都将在此段代码中出现。以后的每个教程中我都会在例程的此处增加新的代码。如果您对OpenGL已经有所了解的话,您可以在 glLoadIdentity()调用之后,函数返回之前,试着添加一些OpenGL代码来创建基本的形。如果您是OpenGL新手,等着我的下个教程。目前我们所作的全部就是将屏幕清除成我们前面所决定的颜,清除深度缓存并且重置场景。我们仍没有绘制任何东东。
void NeHeWidget::resizeGL( int width, int height )
{
  if ( height == 0 )
width的意思中文翻译
  {
    height = 1;
  }
防止height为0。
glViewport( 0, 0, (GLint)width, (GLint)height );
重置当前的视口(Viewport)。
glMatrixMode( GL_PROJECTION );
选择投影矩阵。
glLoadIdentity();
重置投影矩阵。
  gluPerspective( 45.0, (GLfloat)width/(GLfloat)height, 0.1, 100.0 );

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。