}
void NeHeWidget::initializeGL() {
loadGLTextures(); 载入纹理。
glEnable( GL_TEXTURE_2D );
启用纹理。如果没有启用的话,你的对象看起来永远都是纯白色,这一定不是什么好事。
glShadeModel( GL_SMOOTH );
glClearColor( 0.0, 0.0, 0.0, 0.5 ); glClearDepth( 1.0 );
glEnable( GL_DEPTH_TEST ); glDepthFunc( GL_LEQUAL );
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); }
现在您应该比较好的理解纹理映射(贴图)了。您应该掌握了给任意四边形表面贴上您所喜爱的图像的技术。一旦您对2D纹理映射的理解感到自信的时候,试试给立方体的六个面贴上不同的纹理。
当您理解纹理坐标的概念后,纹理映射并不难理解。 本课程的源代码。
纹理滤波、光源和键盘控制
这一课我会教您如何使用三种不同的纹理滤波方式。教您如何使用键盘来移动场景中的对象,还会教您在OpenGL场景中应用简单的光照。这一课包含了很多内容,如果您对前面的课程有疑问的话,先回头复习一下。进入后面的代码之前,很好的理解基础知识十分重要。
我们要在第一课的代码上进行改动就可以了。
我们将要增加一个loadGLTextures()函数来处理有关纹理操作的。我们将增加一些变量,稍后我们对这些变量进行解释。
NeHeWidget类
(由nehewidget.h展开。) protected:
void loadGLTextures();
在这个函数中我们会载入指定的图片并生成相应当纹理。 protected:
bool fullscreen;
GLfloat xRot, yRot, zRot; GLfloat zoom;
GLfloat xSpeed, ySpeed; GLuint texture[3]; GLuint filter;
bool light; };
上面就是添加的三个变量xRot、yRot、zRot来处理立方体在三个方向上的旋转。zoom是场景深入屏幕的距离。xSpeed和ySpeed是立方体在X轴和Y轴上旋转的速度。texture[3]用来存储三个纹理。filter表明的是使用哪个纹理。light是说明现在是否使用光源。 (由nehewidget.cpp展开。)
GLfloat lightAmbient[4] = { 0.5, 0.5, 0.5, 1.0 }; GLfloat lightDiffuse[4] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat lightPosition[4] = { 0.0, 0.0, 2.0, 1.0 }; 这里定义了三个数组,它们描述的是和光源有关的信息。
我们将使用两种不同的光。第一种称为环境光。环境光来自于四面八方。所有场景中的对象都处于环境光的照射中。第二种类型的光源叫做漫射光。漫射光由特定的光源产生,并在您的场景中的对象表面上产生反射。处于漫射光直接照射下的任何对象表面都变得很亮,而几乎未被照射到的区域就显得要暗一些。这样在我们所创建的木板箱的棱边上就会产生的很不错的阴影效果。
创建光源的过程和颜色的创建完全一致。前三个参数分别是RGB三色分量,最后一个是alpha通道参数。
因此,第一行有关lightAmbient的代码使我们得到的是半亮(0.5)的白色环境光。如果没有环境光,未被漫射光照到的地方会变得十分黑暗。
第二行有关lightDiffuse的代码使我们生成最亮的漫射光。所有的参数值都取成最大值1.0。它将照在我们木板箱的前面,看起来挺好。
第三行有关lightPosition的代码使我们保存光源的位置。前三个参数和glTranslate中的一样。依次分别是XYZ轴上的位移。由于我们想要光线直接照射在木箱的
正面,所以XY轴上的位移都是0.0。第三个值是Z轴上的位移。为了保证光线总在木箱的前面,所以我们将光源的位置朝着观察者(就是您哪。)挪出屏幕。我们通常将屏幕也就是显示器的屏幕玻璃所处的位置称作Z轴的0.0点。所以Z轴上的位移最后定为2.0。假如您能够看见光源的话,它就浮在您显示器的前方。当然,如果木箱不在显示器的屏幕玻璃后面的话,您也无法看见箱子。最后一个参数取为1.0。这将告诉OpenGL这里指定的坐标就是光源的位置,以后的教程中我会多加解释。
NeHeWidget::NeHeWidget( QWidget* parent, const char* name, bool fs ) : QGLWidget( parent, name ) {
xRot = yRot = zRot = 0.0; zoom = -5.0;
xSpeed = ySpeed = 0.0;
filter = 0;
light = false;
fullscreen = fs;
setGeometry( 0, 0, 640, 480 );
setCaption( \
if ( fullscreen ) showFullScreen(); }
我们需要在构造函数中给各个变量赋初值。xRot、yRot、zRot是0.0。zoom是-5.0。xSpeed和ySpeed都是0。filter是0。light是false。
void NeHeWidget::loadGLTextures() {
QImage tex, buf;
if ( !buf.load( \ {
qWarning( \not read image file, using single-color instead.\); QImage dummy( 128, 128, 32 ); dummy.fill( Qt::green.rgb() ); buf = dummy; }
tex = QGLWidget::convertToGLFormat( buf );
glGenTextures( 3, &texture[0] );
这一部分,上一章讲过了。我们这里创建了3个纹理。
glBindTexture( GL_TEXTURE_2D, texture[0] );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexImage2D( GL_TEXTURE_2D, 0, 3, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits() );
第六课中我们使用了线性滤波的纹理贴图。这需要机器有相当高的处理能力,但它们看起来很不错。这一课中,我们接着要创建的第一种纹理使用GL_NEAREST方式。从原理上讲,这种方式没有真正进行滤波。它只占用很小的处理能力,看起来也很差。唯一的好处是这样我们的工程在很快和很慢的机器上都可以正常运行。您会注意到我们在MIN和MAG时都采用了GL_NEAREST,你可以混合使用GL_NEAREST和GL_LINEAR。纹理看起来效果会好些,但我们更关心速度,所以全采用低质量贴图。MIN_FILTER在图像绘制时小于贴图的原始尺寸时采用。MAG_FILTER在图像绘制时大于贴图的原始尺寸时采用。
glBindTexture( GL_TEXTURE_2D, texture[1] );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexImage2D( GL_TEXTURE_2D, 0, 3, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits() );
这个纹理与第六课的相同,线性滤波。唯一的不同是这次放在了texture[1]中。因为这是第二个纹理。如果放在texture[0]中的话,它将覆盖前面创建的GL_NEAREST纹理。
glBindTexture( GL_TEXTURE_2D, texture[2] );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
这里是创建纹理的新方法。Mipmapping!您可能会注意到当图像在屏幕上变得很小的时候,很多细节将会丢失。刚才还很不错的图案变得很难看。当您告诉OpenGL创建一个 mipmapped的纹理后,OpenGL将尝试创建不同尺寸的高质量纹理。当您向屏幕绘制一个mipmapped纹理的时候,OpenGL将选择它已经创建的外观最佳的纹理(带有更多细节)来绘制,而不仅仅是缩放原先的图像(这将导致细节丢失)。
我曾经说过有办法可以绕过OpenGL对纹理宽度和高度所加的限制——64、128、256,等等。办法就是gluBuild2DMipmaps。据我的发现,您可以使用任意的位图来创建纹理。OpenGL将自动将它缩放到正常的大小。
因为是第三个纹理,我们将它存到texture[2]。这样本课中的三个纹理全都创建好了。 gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGB, tex.width(), tex.height(), GL_RGBA, GL_UNSIGNED_BYTE, tex.bits() );
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说教育文库Qt+OpenGL中文教程(8)在线全文阅读。
相关推荐: