发信人: yxy (田丝丝#冬眠的小肥鹰), 信区: GAME_Designer 
标  题: OPENGL(10) 
发信站: BBS 水木清华站 (Wed Jan 21 17:52:06 1998) 
 
OPENGL的纹理 
在3D图形中,纹理映射是广泛使用的。纹理映射也是相当复杂的过程: 
一 定义纹理 
二 控制滤波 
三 说明映射方式 
四 绘制场景给出顶点的纹理坐标和几何坐标 
注意!!纹理映射只能在RGBA模式下使用,不适用于颜色索引模式 
 
1.纹理定义 
void glTexImage2D( GLenum target, GLint level, GLint components,  
                   GLsizei width, GLsizei height, GLint border,  
                   GLenum format, GLenum type, const GLvoid *pixels );  
定义一个二维纹理映射。 
target是常数 GL_TEXTURE_2D 
level表示多级分辨率的纹理图象的级数。若只有一种分辨率,level为0。 
components是从1到4的整数,1:选择R;2:选择R A;3:选择R G B; 
                          4:选择R G B A; 
width height是纹理的尺寸。 
format和type描述映射格式和数据类型。它们与前面讲的glDrawPixels()中 
的意义相同。你可以把纹理当成贴图来看待。 
另外还有一维纹理定义: 
void glTexImage1D( GLenum target, GLint level, GLint components,  
                   GLsizei width, GLint border, GLenum format,  
                   GLenum type, const GLvoid *pixels );  
不同之处在于target是常数GL_TEXTURE_1D,例外提供的数据应该是一维数组。 
一般纹理数据维数应该是2的幂次,有时还要根据类型加上边界数据。 
 
2.纹理控制(滤波和重复与缩限) 
所有纹理控制通过: 
void glTexParameter{if}[v](GLenum target,GLenum pname,TYPE param); 
来实现,target可以是GL_TEXTURE_1D GL_TEXTURE_2D来说明是一维还是二维 
纹理。pname和param的可能取值见下: 
pname:                        param:     
GL_TEXTURE_WRAP_S             GL_CLAMP 
                              GL_REPEAT 
GL_TEXTURE_WRAP_T             GL_CLAMP 
                              GL_REPEAT 
GL_TEXTURE_MAG_FILTER         GL_NEAREST 
                              GL_LINEAR 
GL_TEXTURE_MIN_FILTER         GL_NEAREST 
                              GL_NEAREST_MIPMAP_NEAREST 
                              GL_NEAREST_MIPMAP_LINEAR 
                              GL_LINEAR_MIPMAP_NEAREST 
                              GL_LINEAR_MIPMAP_LINEAR 
2.1 滤波 
原始纹理图象是个方形图象,把它映射到奇形怪状的物体上,一般不可能图象 
上的一个象素对应屏幕的一个象素。因此局部放大缩小时,就要定义合适的滤 
波方式(以2D为例): 
void glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); 
void glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); 
前者是放大滤波(GL_TEXTURE_MAG_FILTER), 
后者是缩小滤波(GL_TEXTURE_MIN_FILTER); 
另外,GL_NEAREST是利用最坐标最靠近象素中心的纹理元素,这有可能使图样 
走型,但计算速度快;GL_LINEAR利用线形插值,效果好但计算量大。 
 
2.2重复与缩限 
纹理映射可以重复映射或者缩限映射,重复映射时纹理可以在自己的坐标S T方 
向重复。 
对于重复映射: 
void glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); 
void glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); 
参数GL_REPEAT改为GL_CLAMP,则缩限,所有大于1的纹理元素值置为1。所有小于 
0的纹理元素值置为0。 
 
3. 映射方式 
处理纹理本身图案颜色和物体本身颜色的关系: 
void glTexEnv{if}[v](GLenum target,GLenum pname,TYPE param); 
target必须是GL_TEXTURE_ENV; 
 
pname是GL_TEXTURE_ENV_MODE,则param可以是 GL_DECAL GL_MODULATE或 
GL_BLEND,说明纹理值与原来颜色不同的处理方式。 
pname是GL_TEXTURE_ENV_COLOR,则参数param是包含4个浮点数(R、G、B、A) 
的数组。这些值只在采用GL_BLEND纹理函数时才采用。 
 
4. 纹理坐标 
坐标的定义:纹理图象是方形的,纹理坐标可定义成s,t,r,q坐标,仿照齐次 
坐标系的x,y,z,w坐标。 
void glTexCoord{1234}{sifd}[v](TYPE coords); 
设置当前纹理坐标,此后调用glVertex*()所产生的顶点都赋予当前的纹理坐标。 
 
5. 坐标自动产生 
有时不需要为每个物体顶点赋予纹理坐标,可以使用 
void glTexGen{if}(GLenum coord,GLenum pname,TYPE param); 
coord为:GL_S GL_T GL_R或GL_Q,指明哪个坐标自动产生 
 
pname为GL_TEXTURE_GEN_MODE时 
param为常数:GL_OBJECT_LINEAR GL_EYE_LINEAR或GL_SPHERE_MAP,它们决定用 
哪个函数来产生纹理坐标 
 
pname为GL_OBJECT_PLANE或GL_EYE_PLANE,param时一个指向参数数组的指针。 
 
先请看一个简单的例子: 
//////////////////////////////////////////// 
//sample.cpp 
#include "glos.h" 
#include <GL/gl.h> 
#include <GL/glaux.h> 
#include "windows.h" 
void myinit(void); 
void CALLBACK  display(void); 
void CALLBACK  reshape(GLsizei w,GLsizei h); 
 
//创建纹理图象的子程序 
#define TEXTUREWIDTH 64 
#define TEXTUREHEIGHT 64 
GLubyte Texture[TEXTUREWIDTH][TEXTUREHEIGHT][3]; 
void makeTexture(void) 

 int i,j,r,g,b; 
 for(i=0;i<TEXTUREWIDTH;i++) 
 { 
  for(j=0;j<TEXTUREHEIGHT;j++) 
  { 
         r=(i*j)%255; 
         g=(4*i)%255; 
         b=(4*j)%255; 
         Texture[i][j][0]=(GLubyte)r; 
         Texture[i][j][1]=(GLubyte)g; 
         Texture[i][j][2]=(GLubyte)b; 
  }  
 } 

 
 
void myinit(void) 

        auxInitDisplayMode(AUX_SINGLE|AUX_RGBA); 
        auxInitPosition(0,0,500,500); 
        auxInitWindow("sample1"); 
        glClearColor(0.0,0.0,0.0,0.0); 
        glClear(GL_COLOR_BUFFER_BIT); 
 
//创建纹理图象的原始数据保存在Texture[][][]中 
        makeTexture(); 
        glPixelStorei(GL_UNPACK_ALIGNMENT,1); 
 
//定义二维纹理 
        glTexImage2D(GL_TEXTURE_2D,0,3,TEXTUREWIDTH, 
                         TEXTUREHEIGHT,0,GL_RGB,GL_UNSIGNED_BYTE, 
                                 &Texture[0][0][0]); 
//控制滤波 
        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP); 
        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); 
        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 
        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); 
 
//说明映射方式 
        glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL); 
 
//这个应该很熟了,启用纹理模式 
        glEnable(GL_TEXTURE_2D); 
//      glShadeModel(GL_FLAT); 

 
void CALLBACK reshape(GLsizei w,GLsizei h) 

 
glViewport(0,0,w,h); 
glMatrixMode(GL_PROJECTION); 
glLoadIdentity(); 
//定义立体视景体 
gluPerspective(60.0,1.0*(GLfloat)w/(GLfloat)h,1.0,30.0); 
glMatrixMode(GL_MODELVIEW); 
glLoadIdentity(); 
glTranslatef(0.0,0.0,-3.6); 

 
void CALLBACK display(void) 

  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 
 
   glBegin(GL_QUADS);//绘制四边形 
//先绘制正方形,用来显示实际未变形的纹理图样 
   glTexCoord2f(0.0,0.0);glVertex3f(-2.0,-1.0,0.0); 
   glTexCoord2f(0.0,1.0);glVertex3f(-2.0,1.0,0.0); 
   glTexCoord2f(1.0,1.0);glVertex3f(0.0,1.0,0.0); 
   glTexCoord2f(1.0,0.0);glVertex3f(0.0,-1.0,0.0); 
 
//绘制一个不规则四边形,用来显示纹理是如何随物体形状而变形的。 
   glTexCoord2f(0.0,0.0);glVertex3f(0.0,-1.0,0.0); 
   glTexCoord2f(0.0,1.0);glVertex3f(0.0,1.0,0.0); 
   glTexCoord2f(1.0,1.0);glVertex3f(1.41421,1.0,-1.41421); 
   glTexCoord2f(1.0,0.0);glVertex3f(1.41421,-1.0,-1.41421); 
   glEnd(); 
 
  glFlush(); 

void main(void) 

    myinit(); 
     
    auxReshapeFunc(reshape); 
    auxMainLoop(display); 

//end of sample 
/////////////////////////////////////////////////////////// 
从例子来看,除了纹理的定义和控制比较麻烦和不容易理解外,其应用是十分 
方便的。只须从纹理的坐标系选出合适点附在实际物体顶点上即可。对于复杂 
的纹理定义和控制,你也可以自行改变一些参数,看看效果如何。例如把 
GL_LINEAR改成GL_NEAREST,则纹理的明显变的粗糙,但计算结果却快的多。 
你也可以改动glTexCoord2f()的参数,看看如何选定纹理的一部分(例子中是 
选定全部纹理)来贴图。例如1.0改成0.5则选择实际纹理的左上1/4部分来贴图。 
下次将给出一个更复杂的纹理应用的例子和说明。18:03 98-1-21 
 
 
-- 
※ 来源:·BBS 水木清华站 bbs.net.tsinghua.edu.cn·[FROM: 166.111.74.90]