12.5、纹理坐标
12.5.1 坐标定义
在绘制纹理映射场景时,不仅要给每个顶点定义几何坐标,而且也要定义纹理坐标。经过多种变换后,几何坐标决定顶点在屏幕上绘制的位置,而纹理坐标决定纹理图像中的哪一个纹素赋予该顶点。并且顶点之间的纹理坐标插值与基础篇中所讲的平滑着色插值方法相同。
纹理图像是方形数组,纹理坐标通常可定义成一、二、三或四维形式,称为s,t,r和q坐标,以区别于物体坐标(x, y, z, w)和其他坐标。一维纹理常用s坐标表示,二维纹理常用(s, t)坐标表示,目前忽略r坐标,q坐标象w一样,一半值为1,主要用于建立齐次坐标。OpenGL坐标定义的函数是:
void gltexCoord{1234}{sifd}[v](TYPE coords);
设置当前纹理坐标,此后调用glVertex*()所产生的顶点都赋予当前的纹理坐 标。对于gltexCoord1*(),s坐标被设置成给定值,t和r设置为0,q设置为1;用gltexCoord2*()可以设置s和t坐标值,r设 置为0,q设置为1;对于gltexCoord3*(),q设置为1,其它坐标按给定值设置;用gltexCoord4*()可以给定所有的坐标。使用适 当的后缀(s,i,f或d)和TYPE的相应值(GLshort、GLint、glfloat或GLdouble)来说明坐标的类型。注意:整型纹理坐标可以直接应用,而不是象普通坐标那样被映射到[-1, 1]之间。
12.5.2 坐标自动产生
在某些场合(环境映射等)下,为获得特殊效果需要自动产生纹理坐标,并不要求为用函数gltexCoord*()为每个物体顶点赋予纹理坐标值。OpenGL提供了自动产生纹理坐标的函数,其如下:
void glTexGen{if}[v](GLenum coord,GLenum pname,TYPE param);
自动产生纹理坐标。第一个参数必须是GL_S、GL_T、GL_R或GL_Q,它指 出纹理坐标s,t,r,q中的哪一个要自动产生;第二个参数值为GL_TEXTURE_GEN_MODE、GL_OBJECT_PLANE或 GL_EYE_PLANE;第三个参数param是一个定义纹理产生参数的指针,其值取决于第二个参数pname的设置,当pname为 GL_TEXTURE_GEN_MODE时,param是一个常量,即GL_OBJECT_LINEAR、GL_EYE_LINEAR或 GL_SPHERE_MAP,它们决定用哪一个函数来产生纹理坐标。对于pname的其它可能值,param是一个指向参数数组的指针。下面是一个运用自 动产生纹理坐标函数的实例:
例12-1 纹理坐标自动产生例程(texpot.c)
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void makeStripeImage(void);
void CALLBACK display(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
#define stripeImageWidth 64
GLubyte stripeImage[3*stripeImageWidth];
void makeStripeImage(void)
{
int j;
for (j = 0; j < stripeImageWidth; j++)
{
stripeImage[3*j] = 255;
stripeImage[3*j+1] =255-2*j;
stripeImage[3*j+2] =255;
}
}
/* 参数设置 */
GLfloat sgenparams[] = {1.0, 1.0, 1.0, 0.0};
void myinit(void)
{
glClearColor (0.0, 0.0, 0.0, 0.0);
makeStripeImage();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage1D(GL_TEXTURE_1D, 0, 3, stripeImageWidth, 0, GL_RGB, GL_UNSIGNED_BYTE, stripeImage);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGenfv(GL_S, GL_OBJECT_PLANE, sgenparams);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_1D);
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
glFrontFace(GL_CW);
glCullFace(GL_BACK);
glMaterialf (GL_FRONT, GL_SHININESS, 64.0);
}
void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix ();
glRotatef(25.0, 1.0, 0.0, 0.0);
auxSolidTeapot(1.5);
glPopMatrix ();
glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
float a=3.5;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho (-a, a, -a*(GLfloat)h/(GLfloat)w, a*(GLfloat)h/(GLfloat)w, -a, a);
else
glOrtho (-a*(GLfloat)w/(GLfloat)h, a*(GLfloat)w/(GLfloat)h, -a, a, -a, a);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void main(void)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 500, 500);
auxInitWindow (" Teapot TextureMapping");
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
} 以上程序运行结果是在屏幕上显示一个带条状纹理的茶壶。其中用到了前面所讲的一维纹理映射定义,以及本节的纹理坐标自动产生。