Projective texturing
当人们谈论 纹理的时候 大部分的 是指将纹理坐标应用到 物体表面,投影纹理是指纹理可以投影到物体表面,就好像幻灯片的投影一样。
投影纹理和普通的纹理是一样的 ,唯一的区别就在于纹理应用到几何物体的方式。和普通的纹理一样,投影纹理也需要给场景中的每一个三角面片赋予合理的纹理坐标。如果你能正确的获取纹理坐标,你就可以把纹理的正确部位赋给每一个三角面片。每一个三角面片都是从物体坐标系开始,然后赋予一系列的坐标变换。坐标变换可以把物体坐标系的顶点投影到屏幕坐标,这样三角面片就能光栅化并且呈现在屏幕上。如果你把视口当作一张纹理,那么很明显你需要做的就是把每个定点映射到这张纹理的像素上面。这样的运行机制对投影纹理也同样适用。应用一系列的坐标变换,把物体坐标系投影到2D空间(就是一张纹理)并且每一个顶点(object-space)都对应着纹理中的像素。接下来为每一个顶点分配纹理坐标,绘制的过程中把正确的纹理的每一个部分应用到三角面片。
实现投影纹理
实现投影纹理我们并不需要做太多其他的工作,只需要关注两个操作:
在vertex shader 计算投影纹理坐标
在 fragment shader 中实现投影纹理查询
在vertex shader 计算投影纹理坐标
TransformVertex=(ScaleMatrix*(Projector*(View*(Model*originalVertex))));
Relatively shader code: texCoordProj = mul(textureMatrix, position);
textureMatrix就是上面的转换矩阵
在 fragment shader 中实现投影纹理查询
float4 textureColor = tex2Dproj(projectiveMap,texCoordProj);
投影纹理有两个需要注意的问题:
一:投影纹理不存在被遮挡问题,假设projector 前面有两个物体,而且这两个物体之间有遮挡关系,投影纹理的效果也不会被遮挡
二:投影纹理采用的是齐次坐标系,当w分量为负数的时候会出现light 后面也会出现投影文理。解决的办法:适用culling 只绘制光源前面的物体 适用fragment shader 检查q是否为负数等等
vertex shader
uniform vec3 lightposition;
uniform mat4 texMatrix;
varying vec4 projtexcoord;
varying float light;
void main(void){
vec3 objPosition = vec3 (gl_ModelViewMatrix * gl_Vertex);
vec3 N = normalize (gl_NormalMatrix * gl_Normal);
vec3 L = normalize (lightposition - gl_Vertex.xyz);
light = max(dot(N, L), 0.0);
projtexcoord = texMatrix*vec4(objPosition,1.0);
gl_Position = ftransform();
}
uniform sampler2D ProjectiveTexture;
varying float light ;
varying vec4 projtexcoord;
void main(void){
vec4 texcolor=texture2DProj(ProjectiveTexture,projtexcoord);
gl_FragColor =light * texcolor;
}