Projective Texture的原理与实现 【转】
对上图可以这么理解,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……
Projective Texture的原理与实现 【转】的更多相关文章
- Projective Texture的原理与实现
http://blog.csdn.net/xukunn1226/article/details/775644 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,是光射入非金属材质后在内部发生散射, 最后射出物体并进入视野中产生的现象, 即光从表面进入物体经过内部散射,然后又通过物体 ...
随机推荐
- install cinnamon on ubuntu 14.04
emotion: I feel not comfortable with ubuntu 14.04 default desktop unity,i still look for a alternati ...
- AtCoder Grand Contest 020
A - Move and Win Time limit : 1sec / Memory limit : 512MB Score : 300 points Problem Statement A gam ...
- [整理]linux中颜色的含义
蓝色(Blue): Directory 目录 绿色(Green): Executable or recognized data file 可执行文件,可执行的程序 天蓝(Sky Blue): Sy ...
- hihoCoder #1117 战争年代
题目大意 对一棵树的节点染色.初始时每个点都染成颜色 $0$,然后进行 $m$ 轮操作.第 $i$ 轮操作:从 $[0,d_i]$ 中随机选出一个整数 $d$,将距离点 $x_i$ 不超过 $d$ 的 ...
- Codeforces - Avito Code Challenge 2018
Portal A. Antipalindrome 暴力. B. Businessmen Problems 暴力. C. Useful Decomposition 居然不是C打头的?! 将一棵树划分成若 ...
- [TJOI2017] 城市 (树的直径,贪心)
题目链接 Solution 这道题,调了我一晚上... 一直80分 >_<|| ... 考虑到几点: 分开任意一条边 \(u\) ,那么其肯定会断成两棵树. 肯定是分开直径上的边最优,否则 ...
- 【bzoj2440】[中山市选2011]完全平方数 莫比乌斯反演
Description 小 X 自幼就很喜欢数.但奇怪的是,他十分讨厌完全平方数.他觉得这些数看起来很令人难受.由此,他也讨厌所有是完全平方数的正整数倍的数.然而这丝毫不影响他对其他数的热爱.这天是小 ...
- ELK安装文档
ELK安装文档: http://cuidehua.blog.51cto.com/5449828/1769525 如何将客户端日志通过ogstash-forwarder发送给服务端的logstash h ...
- xsy 1836 - Shop
from NOIP2016模拟题36 Description 商店里有n种背包和m种物品,物品体积为1到m,背包容积<=m 给出n个背包的容积 现在要求出这样一个物品集合,满足: 1)对于任意一 ...
- “百度杯”CTF比赛 十月场_Login
题目在i春秋ctf大本营 打开页面是两个登录框,首先判断是不是注入 尝试了各种语句后,发现登录界面似乎并不存在注入 查看网页源代码,给出了一个账号 用帐密登陆后,跳转到到member.php网页,网页 ...