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,是光射入非金属材质后在内部发生散射, 最后射出物体并进入视野中产生的现象, 即光从表面进入物体经过内部散射,然后又通过物体 ...
随机推荐
- dotnet core 运行程序注意事项
.net core 程序 debug版本无法直接运行,因为没有相关的dll,只有在进入项目文件夹那一层,执行 dotnet run 来运行,会自动链接 当前用户的个人文件夹下的 .nuget/.pac ...
- loj2256 「SNOI2017」英雄联盟
真的是裸背包啊-- #include <iostream> #include <cstdio> using namespace std; typedef long long l ...
- 如何高效的学习 TensorFlow ?
1.https://www.zhihu.com/question/41667903?from=profile_question_card 2.http://cn.udacity.com/course/ ...
- 和为s的两个数字 【微软面试100题 第十四题】
题目要求: 输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s.如果有多对数字的和等于s,输出任意一对即可. 例如输入数组{1,2,4,7,11,15}和数字15.由于4+1 ...
- alidoing --使用JS实现多语言框架、喜欢的请进、、瓦特平台!
大家好! 多语言实现的案例:http://alidoing.com/或者http://www.alidoing.com/ 图:切换语言界面 JS代码实现: 1.首先新建一个对象langobj,当然对象 ...
- Selenium WebDriver-操作下拉框内容
操作下拉框中的内容 #encoding=utf-8 import unittest import time import chardet from selenium import webdriver ...
- JDBC 学习笔记(一)—— JDBC 基础
1. 什么是 JDBC JDBC,Java Database Connectivity(Java 数据库连接),是一组执行 SQL 语句的 Java API. JDBC,是 Java SE(Java ...
- iOS学习笔记24-不断进化的屏幕适配
一.屏幕适配 iOS的屏幕适配可以分为3大块,代表着不同时期的屏幕适配主流: AutoResizing:在iOS6之前,完全能够胜任,因为当时苹果只有3.5寸屏,加上比较少的支持横屏,它有非常大的局限 ...
- [CODEVS1912] 汽车加油行驶问题(分层图最短路)
传送门 吐槽:神tm网络流 dis[i][j][k] 表示到 (i, j) 还有 k 油的最优解 然后跑spfa,中间分一大堆情况讨论 1.当前队头还有油 1.目标点有加油站——直接过去 2.目标点每 ...
- Github与Eclipse连接(方法2成功:Pleiades)
2018-3-7 第1次尝试 主要参考这位大神的笔记:http://blog.csdn.net/zhangdaiscott/article/details/16939165 方法非常简单,从官网htt ...