1.
颜色
讲了这么多,突然想起自己忘记了介绍颜色,在前面的例子中,我已经使用了glColor3f
这个函数。用这个函数为我绘制的立方体的面来配上颜色。
OpenGL
的颜色有两种模式,一是RGBA
,即使用RGB
作为颜色,最后面的A
为Alpha
,即透明度,其值都是[0 1]
之间;另一种是颜色表模式。还记得前面我写的例子中的SetupPixelFormat
函数,其中有个参数就是:
pfd->iPixelType=PFD_TYPE_RGBA;
表示我使用的是RGBA
模式。
除此以为,我还写了一个判断语句:
if (pfd->dwFlags&PFD_NEED_PALETTE)
{
SetLogicalPalette(); //
有必要的话设置逻辑调色板
}
在大多情况下,采用RGBA
模式比颜色表模式的要多,尤其许多效果处理,如阴影、光照、雾、反走样、混合等,采用RGBA
模式效果会更好些;另外,纹理映射只能在RGBA
模式下进行。下面提供几种运用颜色表模式的情况(仅供参考):
1
)若原来应用程序采用的是颜色表模式则转到OpenGL
上来时最好仍保持这种模式,便于移植。
2
)若所用颜色不在缺省提供的颜色许可范围之内,则采用颜色表模式。
3
)在其它许多特殊处理,如颜色动画,采用这种模式会出现奇异的效果。
2.
纹理
前面三节足够让我们建立一个立方体并旋转起来了,而且这个立方体还是彩色的,下面我们就该研究下纹理和打光的技术了。
纹理的图片尺寸必须是2
的N
次方,但最大不能超过256
象素,当然肯定有方法绕过这个限制,不过我现在也不知道,有知道的人请告诉一声。
首先是纹理,先在视图类中添加一个变量:
GLuint m_texture[1]; //
存储一个纹理
一个数组,这就意味着我们完全可以使用多个纹理咯,暂时使用一个先。
添加下面两个函数,用于将一个文件变成纹理:
AUX_RGBImageRec* CCOpenGLDemoView::LoadBMP(char *Filename)
{
FILE* File=NULL;
if (!Filename) //
文件名是否存在
{
return NULL;
}
File=fopen(Filename,"r"); //
读取文件
if (File) //
文件读取成功
{
fclose(File); //
关闭文件流
return auxDIBImageLoad(Filename); //
载入位图并返回指针
}
return NULL;
}
int CCOpenGLDemoView::LoadGLTextures()
{
int Status=FALSE; //
状态参数跟踪是否能够载入位图以及能否创建纹理
AUX_RGBImageRec* TextureImage[1]; //
设置纹理数组
memset(TextureImage,0,sizeof(void*)*1); //
清除图像记录
,
将指针设置为
NULL
if (TextureImage[0]=LoadBMP("mfc2.bmp")) //
载入位图
{
Status=TRUE;
glGenTextures(1,&m_texture[0]); //
创建纹理
glBindTexture(GL_TEXTURE_2D,m_texture[0]);//
根据来自位图的数据创建
NEAREST
纹理
glTexImage2D(GL_TEXTURE_2D, //
产生的是
2D
纹理
0, //
图像的详细程度,一般为
0
3, //
图像的成分,为
RGB
TextureImage[0]->sizeX, //
图像宽
TextureImage[0]->sizeY, //
图像高
0, //
图像边框
GL_RGB, //
图像是
RGB
三色组成
GL_UNSIGNED_BYTE, //
图像数据是无符号字节类型
TextureImage[0]->data); //
图像数据来源
//
采用
GL_LINEAR
使得纹理从很远处到离屏幕很近时都平滑显示
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); //
线形滤波
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); //
线形滤波
//
释放位图内存
if (TextureImage[0])
{
if (TextureImage[0]->data)
{
free(TextureImage[0]->data);
}
free(TextureImage[0]);
}
}
return Status;
}
在获得了纹理后,我们现在需要绑定纹理了,在InitOpenGL
中加入以下代码:
if (!LoadGLTextures())//
纹理是否载入
{
return FALSE;
}
glEnable(GL_TEXTURE_2D);//
启用纹理映射
在RenderScene
中选择纹理:
glBindTexture(GL_TEXTURE_2D, m_texture[0]); //
选择纹理
DrawQuads();
选择纹理后,我们就该贴纹理了,这个过程如下:
glTexCoord2f(1.0f,1.0f);glVertex3f(1.0f,1.0f,1.0f);
glTexCoord2f(0.0f,1.0f);glVertex3f(-1.0f,1.0f,1.0f);
glTexCoord2f(0.0f,0.0f);glVertex3f(-1.0f,-1.0f,1.0f);
glTexCoord2f(1.0f,0.0f);glVertex3f(1.0f,-1.0f,1.0f);
glColor3f(1.0f,0.0f,0.0f);
glTexCoord2f(1.0f,1.0f);glVertex3f(-1.0f,1.0f,-1.0f);
glTexCoord2f(0.0f,1.0f);glVertex3f(1.0f,1.0f,-1.0f);
glTexCoord2f(0.0f,0.0f);glVertex3f(1.0f,-1.0f,-1.0f);
glTexCoord2f(1.0f,0.0f);glVertex3f(-1.0f,-1.0f,-1.0f);
glColor3f(0.5f,1.5f,0.5f);
glTexCoord2f(1.0f,1.0f);glVertex3f(-1.0f,1.0f,1.0f);
glTexCoord2f(0.0f,1.0f);glVertex3f(-1.0f,1.0f,-1.0f);
glTexCoord2f(0.0f,0.0f);glVertex3f(-1.0f,-1.0f,-1.0f);
glTexCoord2f(1.0f,0.0f);glVertex3f(-1.0f,-1.0f,1.0f);
glColor3f(0.5f,0.0f,1.0f);
glTexCoord2f(1.0f,1.0f);glVertex3f(1.0f,1.0f,-1.0f);
glTexCoord2f(0.0f,1.0f);glVertex3f(1.0f,1.0f,1.0f);
glTexCoord2f(0.0f,0.0f);glVertex3f(1.0f,-1.0f,1.0f);
glTexCoord2f(1.0f,0.0f);glVertex3f(1.0f,-1.0f,-1.0f);
glColor3f(1.0f,1.0f,0.0f);
glTexCoord2f(1.0f,1.0f);glVertex3f(1.0f,1.0f,-1.0f);
glTexCoord2f(0.0f,1.0f);glVertex3f(-1.0f,1.0f,-1.0f);
glTexCoord2f(0.0f,0.0f);glVertex3f(-1.0f,1.0f,1.0f);
glTexCoord2f(1.0f,0.0f);glVertex3f(1.0f,1.0f,1.0f);
glColor3f(1.0f,0.0f,1.0f);
glTexCoord2f(1.0f,1.0f);glVertex3f(1.0f,-1.0f,1.0f);
glTexCoord2f(0.0f,1.0f);glVertex3f(-1.0f,-1.0f,1.0f);
glTexCoord2f(0.0f,0.0f);glVertex3f(-1.0f,-1.0f,-1.0f);
glTexCoord2f(1.0f,0.0f);glVertex3f(1.0f,-1.0f,-1.0f);
贴图必须是使用贴图坐标,其左下角为0 0
,右上角为1 1
。搞定,下面我们看看效果:
我们知道,对于一个物体而言,在远处与在近处的感觉肯定不一致,就纹理而言,在远处的物体纹理应该模糊一些,因此我们可以尝试使用不同清晰度的纹理来试验看看。下面的代码就是控制立方体的纹理,当然咯,你也可以学习到换不同纹理的方法,举一反三嘛。
首先要修改的是变量m_texture[1]
,请改为m_texture[3]
,因为我们将试验三种纹理方式。然后设置一个int
型视图类变量filter
,用于标识使用何种纹理。
将LoadGLTextures
的
glGenTextures(1,&m_texture[0]); //
创建纹理
修改为:
glGenTextures(3,&m_texture[0]); //
创建
3
个纹理
然后在第一个创建的纹理后面添加以下内容:
glBindTexture(GL_TEXTURE_2D,m_texture[1]);//
创建线性滤波纹理
glTexImage2D(GL_TEXTURE_2D,
0,
3,
TextureImage[0]->sizeX,
TextureImage[0]->sizeY,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
TextureImage[0]->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glBindTexture(GL_TEXTURE_2D,m_texture[2]);//
创建
MipMapped
纹理
glTexImage2D(GL_TEXTURE_2D,
0,
3,
TextureImage[0]->sizeX,
TextureImage[0]->sizeY,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
TextureImage[0]->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
然后将RenderScene
的glBindTexture
函数改为:
glBindTexture(GL_TEXTURE_2D, m_texture[filter]); //
选择纹理
控制filter
的操作就使用F5
键来进行:
case VK_F5:
filter++;
if (filter>2) {
filter=0;
}
break;
编译执行代码,按F5
,看看纹理是否会出现变化。
上面的例子是使用一个纹理的不同滤波方式,下面的例子我们使用两个纹理来试验看看。首先我改写LoadGLTextures
函数参数类型,改为:
LoadGLTextures(char* Filename)
然后我们再来改写这个函数的内容:
if (TextureImage[0]=LoadBMP(Filename)) //
载入位图
{
Status=TRUE;
这样载入的位图就不必使用默认位图mfc2.bmp
产生纹理了,而是根据文件名载入纹理。接下来我们添加一个视图类变量m_textureFilter
判别是当前使用的是哪一个纹理。在视图类的构造函数中设置为m_textureFilter=0
,用于标识默认纹理;在InitOpenGL
中添加以下一段(灰色部分),表示未使用纹理的标识:
if (!LoadGLTextures("mfc2.bmp"))//
纹理是否载入
{
m_textureFilter=-1;
return FALSE;
}
下面我添加一个菜单:
然后添加这个菜单的处理函数OnOpenglTexture
,改写这个函数:
void CCOpenGLDemoView::OnOpenglTexture()
{
// TODO: Add your command handler code here
int i;
//
如果未载入纹理或载入纹理为默认
if ((m_textureFilter==0)||(m_textureFilter==-1))
{
m_textureFilter=1;
//
载入新纹理
i=LoadGLTextures("Water.bmp");
}
else if(m_textureFilter==1) //
已经载入新纹理
{
m_textureFilter=0;
//
改为默认纹理
i=LoadGLTextures("mfc2.bmp");
}
}
编译运行,然后点击“变换纹理”,看看怎么样情况发生。

相关评论
