Projective Texture(投影贴图)是一项重要的基础技术;尽管在固定管线时代就可以很容易的实现;然而在可编程管线时代,在shader中灵活的运用Projective Texture,是实现各种高级效果的一项基础操作;当然,它本身的效果也很“cool”;另外,对于已经算不上新鲜技术的“shadow mapping”,Projective Texture是必须的一项操作,就是把光源观察方向所得到的Depth Texture(深度贴图)投射到光源的观察的空间;
在固定管线中实现Projective Texture非常简单:
首先要打开纹理自动生成,并设置相关参数:
static GLfloat sPlane[4] = { 1, 0, 0, 0 };
static GLfloat tPlane[4] = { 0, 1, 0, 0 };
static GLfloat rPlane[4] = { 0, 0, 1, 0 };
static GLfloat qPlane[4] = { 0, 0, 0, 1 };
glTexGenfv(GL_S, GL_EYE_PLANE, sPlane);
glTexGenfv(GL_T, GL_EYE_PLANE, tPlane);
glTexGenfv(GL_R, GL_EYE_PLANE, rPlane);
glTexGenfv(GL_Q, GL_EYE_PLANE, qPlane);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glEnable(GL_TEXTURE_GEN_R);
glEnable(GL_TEXTURE_GEN_Q);
这样就可以把纹理从眼睛的观察方向投射到场景中去,如果要从光源方向投射纹理,就要使用glActiveTextureARB首先把那一层的纹理单元激活,然后载入光源方向的透视观察矩阵,最后别忘了glEnable(GL_TEXTUREn_ARB);
然而,现在的各种特效,不用shader实现,太费劲了;当进入可编程管线时,上面的设置的自动纹理生成将不起作用;需要自己在shader中实现投影的采样;然而,这一切在GLSL中实现非常容易:
以下代码实现了把一个纹理投向一个指定的观察方向,需要预先把要使用的投影观察矩阵载入GL_TEXTURE0_ARB
//Vertex Shader
uniform mat4 camMatInv;
uniform mat4 camMat;
varying vec4 ProjTextureCoord;
void main(void)
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
vec4 pos = gl_ModelViewMatrix*gl_Vertex;//观察坐标
pos = camMatInv*pos;//世界坐标
ProjTextureCoord= gl_TextureMatrix[0]*pos;//纹理坐标;
ProjTextureCoord.z += 0.99;
}
//Fragment Shader
varying vec4 ProjTextureCoord;
uniform sampler2D ProjectiveTexture;
void main(void)
{
vec4 test = ProjTextureCoord;
test.x = test.x/test.w;
test.y = test.y/test.w;
vec4 tex_color= texture2DProj( ProjTextureCoord,ProjectiveTexture);
//防止纹理扩出边界和映射到后方表面上
if(test.x<0.0) tex_color.rgb = 1.0;
if(test.x>1.0) tex_color.rgb = 1.0;
if(test.y<0.0) tex_color.rgb = 1.0;
if(test.y>1.0) tex_color.rgb = 1.0;
if(test.z<0.0) tex_color.rgb = 1.0;
gl_FragColor = gl_Color*tex_color;
}