投影纹理映射(Projective Texture Mapping)(2)

下面以一个实际的例子来说明如何实现投影纹理映射(OpenGL+GLSL),其效果及开头所给出的图一。图中绘制了一个茶壶,然后从一个方向将一幅纹理图像投影到茶壶上面。

顶点着色器projtex.vs:

#version 400

layout (location = 0) in vec3 VertexPosition; 
layout (location = 1) in vec3 VertexNormal; 
 
out vec3 EyeNormal;      // Normal in eye coordinates 
out vec4 EyePosition;    // Position in eye coordinates 
out vec4 ProjTexCoord; 
 
uniform mat4 ProjectorMatrix;//用于计算投影纹理映射的矩阵 
 
uniform vec3 WorldCameraPosition; 
uniform mat4 ModelViewMatrix;//模型视图矩阵 
uniform mat4 ModelMatrix;//模型变换矩阵 
uniform mat3 NormalMatrix;//法线变换矩阵 
uniform mat4 ProjectionMatrix;//投影变换矩阵 
uniform mat4 MVP;//模型视图变换矩阵 
 
void main() 

    vec4 pos4 = vec4(VertexPosition,1.0); 
 
    EyeNormal = normalize(NormalMatrix * VertexNormal); 
    EyePosition = ModelViewMatrix * pos4; 
    ProjTexCoord = ProjectorMatrix * (ModelMatrix * pos4); 
    gl_Position = MVP * pos4; 

layout (location = 0) in vec3 VertexPosition; 
layout (location = 1) in vec3 VertexNormal; 
 
out vec3 EyeNormal;      // Normal in eye coordinates 
out vec4 EyePosition;    // Position in eye coordinates 
out vec4 ProjTexCoord; 
 
uniform mat4 ProjectorMatrix;//用于计算投影纹理映射的矩阵 
 
uniform vec3 WorldCameraPosition; 
uniform mat4 ModelViewMatrix;//模型视图矩阵 
uniform mat4 ModelMatrix;//模型变换矩阵 
uniform mat3 NormalMatrix;//法线变换矩阵 
uniform mat4 ProjectionMatrix;//投影变换矩阵 
uniform mat4 MVP;//模型视图变换矩阵 
 
void main() 

    vec4 pos4 = vec4(VertexPosition,1.0); 
 
    EyeNormal = normalize(NormalMatrix * VertexNormal); 
    EyePosition = ModelViewMatrix * pos4; 
    ProjTexCoord = ProjectorMatrix * (ModelMatrix * pos4); 
    gl_Position = MVP * pos4; 

上面的代码前两行是将法线和顶点坐标变换到eye space。

然后是计算投影纹理坐标:先将位于object space的坐标变换到world space,然后通过左乘纹理投影矩阵变换计算出纹理投影坐标。

最后计算内置的gl_Position即剪切平面坐标。

片断着色器projtex.fs(下面只列出一部分):

#version 400 
 
in vec3 EyeNormal;      // Normal in eye coordinates 
in vec4 EyePosition;    // Position in eye coordinates 
in vec4 ProjTexCoord; 
 
uniform sampler2D ProjectorTex; 
 
layout( location = 0 ) out vec4 FragColor; 
 
void main() { 
    vec3 color = phongModel(vec3(EyePosition), EyeNormal); 
 
    vec4 projTexColor = vec4(0.0); 
    if( ProjTexCoord.z > 0.0 ) 
        //textureProj:纹理坐标各分量会除以最后一个分量 
        projTexColor = textureProj( ProjectorTex, ProjTexCoord ); 
 
    FragColor = vec4(color,1.0) + projTexColor * 0.5; 

#version 400 
 
in vec3 EyeNormal;      // Normal in eye coordinates 
in vec4 EyePosition;    // Position in eye coordinates 
in vec4 ProjTexCoord; 
 
uniform sampler2D ProjectorTex; 
 
layout( location = 0 ) out vec4 FragColor; 
 
void main() { 
    vec3 color = phongModel(vec3(EyePosition), EyeNormal); 
 
    vec4 projTexColor = vec4(0.0); 
    if( ProjTexCoord.z > 0.0 ) 
        //textureProj:纹理坐标各分量会除以最后一个分量 
        projTexColor = textureProj( ProjectorTex, ProjTexCoord ); 
 
    FragColor = vec4(color,1.0) + projTexColor * 0.5; 

函数phongModel是计算phong光照模型的。

注意其中的textureProj函数,它专门用于投影纹理访问的。它的纹理坐标的各分量会除以最后一个分量,然后才访问纹理。

在这个例子中,我们假设投影仪位于(2.0,5.0,5.0),朝向是(-2.0,-4.0,0.0),方向(0.0,1.0,0.0)是向上的。我们采用了一个外部库GLM库来根据投影仪的这些信息计算出各个变换矩阵,代码如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/b4b6a29b4331243044d99af78fc60b94.html