投影纹理映射 (projective texture mapping):就是把纹理投射到场景的物体上,就像一个投影机把幻灯片投影到其他物体上一样。
如下图:用左边的纹理图像投影到一个茶壶上
投影纹理的实现方法:
其实最重要的一点就是确定纹理坐标,纹理坐标的确定依赖于物体表面点的相对位置和投影机的位置。在OpenGL中我们可以定义一个camera,我们定义一个中心在投影机位置的坐标空间,viewMatrix(V)把世界坐标系的点转换到投影机的坐标系中,然后定义一个投影矩阵(P)。这样P*V就把点转化到投影空间,但规格化的投影空间是[-1,1],而纹理坐标是[0,1],因此我们需要把 这个视景体转化到[0,1]中,我们可以先把其缩小1/2,然后再平移1/2,这样就转化到了[0,1]上。如图:
注意:由于坐标是齐次坐标系(homogeneous),在我们用其访问纹理坐标前需要除以w。
应用程序设置代码片段
vec3 projPos = vec3(5.0f,5.0f,5.0f); vec3 projAt = vec3(-2.0f,-4.0f,0.0f); vec3 projUp = vec3(0.0f,1.0f,0.0f); mat4 projView = glm::lookAt(projPos, projAt, projUp);print(projView); mat4 projProj = glm::perspective(30.0f, 1.0f, 0.2f, 1000.0f);print(projProj); mat4 projScaleTrans = glm::translate(vec3(0.5f)) * glm::scale(vec3(0.5f)); prog.setUniform("ProjectorMatrix", projScaleTrans * projProj * projView); // Load texture file glActiveTexture(GL_TEXTURE0); TGAIO::loadTex("../media/texture/flower.tga"); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
顶点shader
#version 430 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; }
片元shader
#version 430 in vec3 EyeNormal; // Normal in eye coordinates in vec4 EyePosition; // Position in eye coordinates in vec4 ProjTexCoord; layout(binding=0) uniform sampler2D ProjectorTex; struct MaterialInfo { vec3 Kd; vec3 Ks; vec3 Ka; float Shininess; }; uniform MaterialInfo Material; struct LightInfo { vec3 Intensity; vec4 Position; }; uniform LightInfo Light; layout( location = 0 ) out vec4 FragColor; vec3 phongModel( vec3 pos, vec3 norm ) { vec3 s = normalize(vec3(Light.Position) - pos); vec3 v = normalize(-pos.xyz); vec3 r = reflect( -s, norm ); vec3 ambient = Light.Intensity * Material.Ka; float sDotN = max( dot(s,norm), 0.0 ); vec3 diffuse = Light.Intensity * Material.Kd * sDotN; vec3 spec = vec3(0.0); if( sDotN > 0.0 ) spec = Light.Intensity * Material.Ks * pow( max( dot(r,v), 0.0 ), Material.Shininess ); return ambient + diffuse + spec; } void main() { vec3 color = phongModel(vec3(EyePosition), EyeNormal); vec4 projTexColor = vec4(0.0); if( ProjTexCoord.z > 0.0 ) projTexColor = textureProj( ProjectorTex, ProjTexCoord ); FragColor = vec4(color,1.0) + projTexColor * 0.5; }
在片元着色器中,if( ProjTexCoord.z > 0.0 ) 意思是如果ProjTexCoord.z 为负,则说明在投影机的后面,我们不需要查找对应的纹理了。
textureProj 函数是用来访问纹理的(传入的纹理坐标是投影坐标系下的坐标),在前面我们提到,在平移缩放投影矩阵后,我们需要除以其坐标中的w项,而textureProj 会为我们做这些。
在本例子中有一个很大的缺点,投影纹理(projected texture) 将会投射到场景中的任何物体上,即便有物体遮挡。例如,我们可以让上图的地板向下移动一些。结果如图:
总结:
投影纹理映射真正的流程是 “ 根据投影机(视点相机)的位置、投影角度,物体的坐标,求出每个顶点所对应的纹理坐标,然后依据纹理坐标去查询纹理值 ” ,也就是说,不是将纹理投影到墙上,而是把墙投影到纹理上。投影纹理坐标的求得,也与纹理本身没有关系,而是由投影机的位置、角度,以及 3D 模型的顶点坐标所决定
projtexcoord=偏移矩阵 * 光源投影矩阵 * 光源观察矩阵 * 建模矩阵
http://blog.csdn.net/zhuyingqingfen/article/details/19331721
相关推荐
内容包含了glm glut 等库,用vs2008 基于OpenGL 4.0 ,可以直接运行,包含所有源码,里面含有很多使用性技巧
非常不好找的 opengl 4.0 shading language cookbook 源码 GLSL COOKBOOK 源码 opengl 4.0 shading language cookbook 源码 GLSL COOKBOOK 源码 opengl 4.0 shading language cookbook 源码 GLSL COOKBOOK 源码 ...
投影纹理可以实现许多有趣的效果,比如模仿聚光效果,用glsl实现可以更加灵活。
If you are an OpenGL programmer looking to use the modern features of GLSL 4.0 to create real-time, three-dimensional graphics, then this book is for you. Familiarity with OpenGL programming, along ...
简单glsl shader 自己编写,实现太空看地球效果 白天、黑夜、云彩多重纹理混合 参见opengl shading language第二版
opengl编程入门,glsl语言的hello world,着色器,glsl语言简介
本教程将介绍如何使用GLSL在OpenGL 4.0中渲染3D模型。本教程中的代码基于漫反射教程中的代码https://blog.csdn.net/weixin_44210987/article/details/109300986。 在之前的教程中,我们已经渲染过3D模型,但是它们...
用VB.net OpenTK写的一个GLSL版本330 + VAO的使用方法DEMO。可以简单了解着色模型ShaderModel的DEMO。并且shader实现了一个模糊效果。
GLSL之多重纹理演示 http://www.cnblogs.com/zengqh/
#include <GL/glut.h> #include<iostream> #include <fstream> #include <cstdlib> #include <vector> #include <string> using namespace std; class POINT { public: float x,y,z; }; const static int NumOf...
这源码是OpenGL4.6着色语言精通_第三版的全部源代码,利用GLSL 4.6和C++ 17构建高质量实时三维图形。主要重点是OpenGL着色语言(GLSL)。因此,我们不花时间讨论用OpenGL编程的基础。在这个我认为读者对在OpenGL中...
将鱼眼全景图显示在一个球体上,从而肉眼能够感受到鱼眼视觉效果。
OpenGL提供了强大的可编程着色语言:GLSL(OpenGL Shading Language)。<br>这是GLSL快速参考。<br>
OpenGL Course GLSL 教程
本人学习OpenGL及GLSL后写的一个多重纹理的程序,通过这个程序可以帮助初学者很好地理解GLSL的多重纹理机制,代码注释清晰,重用性强!
stl、obj、3DS三种3D模型加载,使用OpenGl+GLSL框架并添加双层纹理,并完成逐顶点光照和逐像素光照(GouraudShading+PhongS)