Projective Texture的原理与实现
http://blog.csdn.net/xukunn1226/article/details/775644
对上图可以这么理解,Camera用于物体顶点坐标到规范化设备的生成,Projector用于物体顶点纹理坐标的生成。而在不同模式下纹理坐标的生成方式是不同。
根据glTexGen的不同参数GL_OBJECT_LINEAR,GL_EYE_LINEAR来确定纹理生成的函数。在Projective texture mapping一文中给出的纹理坐标生成公式是:
注意:此处Vo是基于物体坐标系的,无论物体在人眼坐标系中如何变换,其物体坐标是不变的,根据公式其纹理坐标也是不变的。所以在GL_OBJECT_LINEAR模式下看到的纹理是紧贴在物体表面的。而Ve是基于人眼坐标系的,在Projector设置好位置后是基于人眼坐标不变的。
我们来看Object Linear模式下纹理坐标是如何生成的:
此处的M(Model Matrix)是模型变换矩阵,不同于OPENGL的MODELVIEW MATRIX(这在模型变换的基础上还进行了视图变换)。顶点坐标左乘M后变换到World Space,为什么要变换到World Space呢??这是因为Camera和Projector都是通过gluLookAt而定义在世界坐标中,这就像座桥梁,唯有通过它才能使得人眼视图体中的顶点转换到Projector定义的视图体内,才能进一步求出相应的纹理坐标。Vp是projector的view matrix(由gluLookAt定义),累加左乘得到projector space中的坐标。Pp是projector的projection matrix(由gluPerspective定义),累加左乘得到projector clip space中的坐标。最后累加偏移矩阵,使纹理坐标的s、t、r映射到[0,1]内。
本文关注的是Eye Linear模式下纹理坐标的生成,有了以上对Object Linear的理解就好办了,公式如下:
Eye Linear模式是把人眼坐标下的顶点左乘OPENGL的MODELVIEW逆矩阵转换到world space中。Eye Linear和Object Linear的最后一项略有不同,Ve-1是Camera视图矩阵的逆矩阵,目的是把人眼坐标下的顶点转换到世界坐标系中(还记得为什么一定要转换到世界坐标中吗?桥梁的作用,前面已经讲过了^_^)。总之,无论何种模式下使用何种方法都需要把物体顶点转换到世界坐标系中,这样才能通过累加Vp(Projector的view matrix)、Pp(Projector的projection matrix)、偏移矩阵得到纹理坐标。
Pointer在其BLOG中对上述问题也有详细的描述[4],有很好的启发作用。值得拜读!
纹理坐标的自动生成大致就如此了,看点代码或许能更好的理解吧!
//----------------------------------------ProjTexture.h------------------------------------
/********************************************************
Usage Instruction:
//in init()
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, ......, texImage);
ProjectiveTexture lightmap;
lightmap.SetupTexture(id);
lightmap.SetupMatrix(Camera* lightCam);
//in the render pipe loop...
lightmap.SetupMatrix(lightCam);
lightmap.BeginRender();
draw scene...
lightmap.EndRender();
********************************************************/
#ifndef _PROJTEXTURE_H_
#define _PROJTEXTURE_H_
#include "stdafx.h"
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glext.h>
#include "Camera.h"
class ProjectiveTexture
{
private:
GLuint textureID;
float matrix[16];
public:
ProjectiveTexture() {}
virtual ~ProjectiveTexture() { glDeleteTextures(1, &textureID); }
//绑定纹理,设置纹理单元过滤操作、环境应用等参数
void SetupTexture(GLuint id)
{
textureID = id;
glBindTexture(GL_TEXTURE_2D, id);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
// glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}
//lightCam是我们定义的一个Camera类,此处代表Projector
void SetupMatrix(Camera* lightCam)
{
glMatrixMode(GL_TEXTURE);
glPushMatrix();
static float biasMatrix[16] = { 0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0 };
static double modelviewMatrix[16];
static double projMatrix[16];
//获得Projector的模型视图矩阵,用于把world space的顶点转换到projector space
lightCam->GetModelViewMatrix(modelviewMatrix);
//获得Projector的投影矩阵,用于把projector space的顶点转换到projector clip space
lightCam->GetProjectionMatrix(projMatrix);
glLoadMatrixf(biasMatrix);
glMultMatrixd(projMatrix);
glMultMatrixd(modelviewMatrix);
glGetFloatv(GL_TEXTURE_MATRIX, matrix); //获得纹理矩阵
glPopMatrix();
}
void BeginRender()
{
static float planeS[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
static float planeT[4] = { 0.0f, 1.0f, 0.0f, 0.0f };
static float planeR[4] = { 0.0f, 0.0f, 1.0f, 0.0f };
static float planeQ[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
glBindTexture(GL_TEXTURE_2D,textureID);
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);
glTexGenfv(GL_S,GL_EYE_PLANE,planeS);
glTexGenfv(GL_T,GL_EYE_PLANE,planeT);
glTexGenfv(GL_R,GL_EYE_PLANE,planeR);
glTexGenfv(GL_Q,GL_EYE_PLANE,planeQ);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glEnable(GL_TEXTURE_GEN_R);
glEnable(GL_TEXTURE_GEN_Q);
glMatrixMode(GL_TEXTURE);
glLoadMatrixf(matrix); // load our texture matrix
//渲染管线就像流水线,顶点是我们的操作对象,何时把相关的操作传入渲染管线,
//何时把不必要的操作卸下是我们该考虑的。物体顶点坐标应该是在模型视图矩阵
//(GL_MODELVIEW)转换到世界坐标,然后进入纹理矩阵模式下求出纹理坐标
glMatrixMode(GL_MODELVIEW);
}
void EndRender()
{
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glDisable(GL_TEXTURE_GEN_R);
glDisable(GL_TEXTURE_GEN_Q);
}
};
#endif
void ProjectiveTextureViewer::Init()
{
glEnable(GL_CULL_FACE);
glGenTextures(1, &texdecal);
glBindTexture(GL_TEXTURE_2D, texdecal);
read_ppm("Data//decal_image.ppm");
glGenTextures(1, &texspotlight);
glBindTexture(GL_TEXTURE_2D, texspotlight);
read_ppm("Data//spotlight_image.ppm");
……
……
……
pLightMap = new Camera(); //create Projector
lightmap.SetupTexture(texspotlight); //ProjectiveTexture lightmap
lightmap.SetupMatrix(pLightMap);
}
void ProjectiveTextureViewer::Draw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
//画一个圆球,代表Projector
glPushMatrix();
glMultMatrixd(pLightMap->frame()->matrix());
glColor3f(1.0, 1.0, 0.0);
gluSphere(q, 0.02, 12, 12);
glPopMatrix();
//因为Projector是可以控制的,所以需要实时更新纹理矩阵
lightmap.SetupMatrix(pLightMap);
lightmap.BeginRender();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glMultMatrixd(pRoom->matrix());
DrawRoom2();
glPopMatrix();
glPushMatrix();
glMultMatrixd(pObject->matrix());
DrawObject2();
glPopMatrix();
lightmap.EndRender();
}
现在来看看效果图吧:)
黄色小球为Projector(可控),ProjectiveTexture用的是一张笑脸纹理。
上面三副图从不同角度给出了投影纹理的效果图,效果还是可以的。这里没有考虑遮挡的问题,导致墙上的一些纹理本应被立方体阻挡的也渲染出来了,或许获取一个基于Projector的depth map可以解决,这就该是Shadow Mapping了,有待解决^_^,希望高人可以指点一下了!!
又一问题,从这两张图中可以看出Reverse Projection的问题,当Projector出现在两堵墙的同侧,墙上的纹理方向一致,如果Projector出现在两堵墙的中间,则一个沿着projector的视线方向,另一个则为相反方向,通过定义一个裁剪平面能否解决这个问题呢?思考一下……
只是简单实现了一个投影纹理,发现问题还是瞒多的,fighting……
see also:
[1]、http://dev.gameres.com/Program/Visual/3D/ProjectTexture.htm
[2]、http://www.bluevoid.com/opengl/sig00/advanced00/notes/node81.html
[3]、http://www.nvidia.com/object/Projective_Texture_Mapping.html
[4]、http://pointer.cnblogs.com/archive/2004/12/30/84367.html
Projective Texture的原理与实现的更多相关文章
- Projective Texture的原理与实现 【转】
Projective Texture是比较常见的一种技术,实现起来代码也就区区的不过百行,了解其原理及技术细节是我们的重点,知其然,知其所以然. 粗略的说就是想象场景 ...
- 投影纹理映射(Projective Texture Mapping)
摘抄“GPU Programming And Cg Language Primer 1rd Edition” 中文名“GPU编程与CG语言之阳春白雪下里巴人” 投影纹理映射( Projective ...
- 投影纹理映射(Projective Texture Mapping) 【转】
摘抄“GPU Programming And Cg Language Primer 1rd Edition” 中文名“GPU编程与CG语言之阳春白雪下里巴人” 投影纹理映射( Projective ...
- OpenGL 4.0 GLSL 实现 投影纹理映射(Projective Texture Mapping) (转)
http://blog.csdn.net/zhuyingqingfen/article/details/19331721 分类: GLSL 投影纹理映射 (projective texture ...
- Projective Texture Mapping - 投影纹理
昨天导师让写一个投影纹理,将一个相机渲染的图片的一部分投影到另外一个相机里面,目的是无缝的拼接. 投影纹理就和shadow map一样,都是将片元转换到另外一个相机/光源坐标系下,投影后找到对应的纹素 ...
- 3DShader之投影贴图(Projective Texturing)
相信大家都应该玩过CS或者CF吧,游戏里面有个喷图功能,就是按一个T键就能在墙上或者地板上喷出自己预先设定的图案. 而刚好这就是我们这个Shader所需实现的内容.由于没有潜伏者的贴图,我只有从这个图 ...
- OpenGL阴影,Shadow Mapping(附源程序)
实验平台:Win7,VS2010 先上结果截图(文章最后下载程序,解压后直接运行BIN文件夹下的EXE程序): 本文描述图形学的两个最常用的阴影技术之一,Shadow Mapping方法(另一种是Sh ...
- shader 4 杂 一些和函数名词、数据结构
Normal: 法线 Normao mapping: 法线贴图 Lighting mapping: 光照贴图 Bump mapping: 凹凸贴图:模拟粗糙外表面的技术. FX-Water ...
- (转)GEM -次表面散射的实时近似
次表面散射(Subsurface Scattering),简称SSS,或3S,是光射入非金属材质后在内部发生散射, 最后射出物体并进入视野中产生的现象, 即光从表面进入物体经过内部散射,然后又通过物体 ...
随机推荐
- frequentism-and-bayesianism-chs-ii
frequentism-and-bayesianism-chs-ii 频率主义 vs 贝叶斯主义 II:当结果不同时 这个notebook出自Pythonic Perambulations的博文 ...
- nginx配置解读
nginx.conf基本配置 ##Start. ##Basic 基础配置 user www www; #运行用户 worker_processes ; #启动进程,通常设置成和cpu的数量相等 wor ...
- 关于IE下AJAX的问题探讨
今天JS练手的时候,想封装一个发送AJAX请求的对象,当然,是想要兼容全浏览器的.代码如下: var Ajax = { xhr: null, callback: null, XMLHttp: func ...
- Sqli-labs less 45
Less-45 同样的,45关与43关的payload是一样的,只不过45关依旧没有报错信息. 登录 username:admin Password:c');create table less45 l ...
- close和shutdown的区别
转的,没验证 close(sock_fd)会把sock_fd的内部计数器减1当sock_fd的内部计数器为0时, 才调用shutodwn(), 并最终释放文件描述符调用shutdown()只是进行了T ...
- 分布式数据存储 - Zabbix监控MySQL性能
Zabbix如何监控mysql性能,我们可以使用mysql自带的模板,可以监控如下内容:OPS(增删改查).mysql请求流量带宽,mysql响应流量带宽,最后会附上相应的监控图! 编写check_m ...
- codeforces 455B A Lot of Games(博弈,字典树)
题目 参考自博客:http://blog.csdn.net/keshuai19940722/article/details/38455269 //字典树,博弈 根据当前节点的后续来确定当前节点的状态, ...
- [你必须知道的.NET]第三十一回,深入.NET 4.0之,从“新”展望
发布日期:2009.05.22 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. /// <summary> /// 本文开始,将以& ...
- ibatis2.3中#和$符号的区别(转)
在Ibatis中我们使用SqlMap进行Sql查询时需要引用参数,在参数引用中遇到的符号#和$之间的区分为,#可以进行与编译,进行类型匹配,而$不进行数据类型匹配,例如: select * from ...
- python urllib2的proxyhandler
1. 再a方法中新建了个opener,使用了代理: proxydict = {} proxydict['http'] = "http://%s:%s"%(ip,port) #pri ...