📄 tutorial_22.htm
字号:
<li>使用漫射光颜色调制(相乘)片断颜色T0c</li>
<li>混合1 颜色设置:</li>
<li>(T0c * C0a + T0c * Fda - 0.5 )*2</li>
<li>0.5 平衡损失的掐除值</li>
<li>乘以2加亮图像颜色</li>
</ul>
结束理论讲解(凹凸映射)<font size="-1"><br>
<br>
</font>虽
然我们做了一些改动,使得这个程序的实现与TNT的实现不一样,但它能工作与各种不同的显卡上。在这里我们将学到两三件事,凹凸映射在大多数显卡上是一个
多通道算法(在TNT系列,可以使用一个2纹理通道实现),现在你应该能想到多重纹理的好处了吧。我们将使用一个三通道非多重纹理的算法实现,这个算法可
以被改写为使用一个2纹理通道实现的算法。 <p>现在必须告诉你,我们将要做一些矩阵和向量的乘法,但那没有什么可担心的,所有的矩阵和向量都使用齐次坐标。</p></td>
<td background="Tutorial_22_files/r.png"><img src="Tutorial_22_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_22_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_22_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_22_files/br.png" height="28" width="28"></td></tr></tbody></table><font color="#aaffaa" size="3">
<pre><font color="#ffffaa">// 计算向量v=v*M(左乘)</font>
void VMatMult(GLfloat *M, GLfloat *v) {
GLfloat res[3];
res[0]=M[ 0]*v[0]+M[ 1]*v[1]+M[ 2]*v[2]+M[ 3]*v[3];
res[1]=M[ 4]*v[0]+M[ 5]*v[1]+M[ 6]*v[2]+M[ 7]*v[3];
res[2]=M[ 8]*v[0]+M[ 9]*v[1]+M[10]*v[2]+M[11]*v[3];
v[0]=res[0];
v[1]=res[1];
v[2]=res[2];
v[3]=M[15];
}
</pre>
</font><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_22_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_22_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_22_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_22_files/l.png"><img src="Tutorial_22_files/l.png"></td>
<td valign="top" width="100%"><p>开始理论讲解(凹凸映射)</p>
<p>开始,让我们看看它的算法</p>
<ol>
<li>所有的向量必须在物体空间或则世界空间中</li>
<li>计算向量v,由灯的位置减去当前顶点的位置</li>
<li>归一化向量v</li>
<li>把向量v投影到切空间中</li>
<li>安向量v在切空间中的投影偏移纹理坐标</li>
</ol>
这看起来不错,它基本上和Michael I. Gold介绍的方法差不多。但它有一个缺点,它只对xy平面进行投影,这对我们的应用还是不够的。 <p>但
这个实现在计算漫射光的方法和我们是一样的,我们不能存储漫射因子,所以我们不能使用Michael I.
Gold介绍的方法,因为我们想让它在任何显卡上运行而不仅仅是TNT系列。为什么不光照计算留到最后呢?这在简单的几何体绘制上是可行的,如果你需要渲
染几千个具有凹凸贴图的三角形,你会感到绘制的速度不够快,到那时你需要改变这种渲染过程,寻找其它的方法。</p>
<p>在我们的实现里,它看起来和上面的实现差不多,除了投影部分,我们将使用我们自己的近似。</p>
<ul type="disc">
<li>我们使用模型坐标,这种设定可以使得灯光位置相对于物体不变。</li>
<li>我们计算当前的顶点坐标</li>
<li>接着计算法线,并使它单位化</li>
<li>创建一个正投影矩阵,把灯光方向变为切空间</li>
<li>计算纹理坐标的偏移量,ds = s点乘v*MAX_EMBOSS, dt=t点乘v*MAX_EMBOSS</li>
<li>在通道2中,把偏移量添加到纹理坐标</li>
</ul>
<b><u>为什么更好:</u></b> <ul type="disc">
<li>更快</li>
<li>看起来好看</li>
<li>这个方法可以工作与各种表面</li>
<li>可以运行于各种显卡</li>
<li>最大化的兼容</li>
</ul>
<b><u>缺陷:</u></b> <ul type="disc">
<li>并不是完全的物理模拟</li>
<li>残留一些人为的假相</li>
</ul>
<font size="-1"><img src="Tutorial_22_files/image008.jpg" border="0" height="243" width="412">
<br>
<br>
</font>这个示意图显示了我们坐标系统,你可以通过相减相邻的坐标来获得s,t向量,但必须保证他们构成右手系和归一化。<font size="-1"><br>
<br>
</font>结束理论讲解(凹凸映射)<font size="-1"> <br>
<br>
</font>下面让我们看看如何生成偏移量,首先创建一个函数创建凹凸映射:
<p></p></td>
<td background="Tutorial_22_files/r.png"><img src="Tutorial_22_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_22_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_22_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_22_files/br.png" height="28" width="28"></td></tr></tbody></table>
<font color="#aaffaa" size="3">
</font><pre><font color="#aaffaa" size="3"><font color="#ffffaa">// 设置纹理偏移,都为单位长度</font>
<font color="#ffffaa">// n : 表面的法向量</font>
<font color="#ffffaa">// c : 当前的顶点纹理坐标,返回纹理坐标的偏移量</font>
<font color="#ffffaa">// l : 灯光的位置</font>
<font color="#ffffaa">// s : s方向</font>
<font color="#ffffaa">// t : t方向</font>
void SetUpBumps(GLfloat *n, GLfloat *c, GLfloat *l, GLfloat *s, GLfloat *t) {
GLfloat v[3]; <font color="#ffffaa">// 灯光方向</font>
GLfloat lenQ; <font color="#ffffaa">// 灯光方向向量的长度,使用它来单位化</font>
<font color="#ffffaa">// 计算灯光方向</font>
v[0]=l[0]-c[0];
v[1]=l[1]-c[1];
v[2]=l[2]-c[2];
lenQ=(GLfloat) sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
v[0]/=lenQ;
v[1]/=lenQ;
v[2]/=lenQ;
<font color="#ffffaa">// 把方向向量投影到s,t方向 </font>
c[0]=(s[0]*v[0]+s[1]*v[1]+s[2]*v[2])*MAX_EMBOSS;
c[1]=(t[0]*v[0]+t[1]*v[1]+t[2]*v[2])*MAX_EMBOSS;<br>}</font></pre>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_22_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_22_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_22_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_22_files/l.png"><img src="Tutorial_22_files/l.png"></td>
<td valign="top" width="100%">那看起来复杂么,但为了理解这个效果理论是必须的。(我在写这篇教程的时候也学习了它)。
<p>我在程序运行的时候,总喜欢在屏幕上显示标志,现在我们有了两个,使用doLogo函数创建它。</p>
<p>下面的函数显示两个标志:一个OpenGL的标志,一个多重纹理的标志,如果可以使用多重纹理,则标志使用alpha混合,并看起来半透明。为了让它在屏幕的边沿显示我们使用混合并禁用光照和深度测试。</p>
<p></p>
<p></p></td><td background="Tutorial_22_files/r.png"><img src="Tutorial_22_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_22_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_22_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_22_files/br.png" height="28" width="28"></td></tr></tbody></table>
<font color="#aaffaa" size="3">
</font><pre><font color="#aaffaa" size="3">void doLogo(void) {
<font color="#ffffaa">// 必须最后在调用这个函数,以公告板的形式显示两个标志</font>
glDepthFunc(GL_ALWAYS);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glDisable(GL_LIGHTING);
glLoadIdentity();
glBindTexture(GL_TEXTURE_2D,glLogo);
glBegin(GL_QUADS);
glTexCoord2f(0.0f,0.0f); glVertex3f(0.23f, -0.4f,-1.0f);
glTexCoord2f(1.0f,0.0f); glVertex3f(0.53f, -0.4f,-1.0f);
glTexCoord2f(1.0f,1.0f); glVertex3f(0.53f, -0.25f,-1.0f);
glTexCoord2f(0.0f,1.0f); glVertex3f(0.23f, -0.25f,-1.0f);
glEnd();
if (useMultitexture) {
glBindTexture(GL_TEXTURE_2D,multiLogo);
glBegin(GL_QUADS);
glTexCoord2f(0.0f,0.0f); glVertex3f(-0.53f, -0.25f,-1.0f);
glTexCoord2f(1.0f,0.0f); glVertex3f(-0.33f, -0.25f,-1.0f);
glTexCoord2f(1.0f,1.0f); glVertex3f(-0.33f, -0.15f,-1.0f);
glTexCoord2f(0.0f,1.0f); glVertex3f(-0.53f, -0.15f,-1.0f);
glEnd();
}
glDepthFunc(GL_LEQUAL);
}
</font></pre>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_22_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_22_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_22_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_22_files/l.png"><img src="Tutorial_22_files/l.png"></td>
<td valign="top" width="100%">现在到了绘制凹凸贴图的函数了,我们先来看看不使用多重映射的方法,它通过三个通道实现。在第一步,我们先取得模型变换矩阵的逆矩阵!</td>
<td background="Tutorial_22_files/r.png"><img src="Tutorial_22_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_22_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_22_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_22_files/br.png" height="28" width="28"></td></tr></tbody></table>
<font color="#aaffaa" size="3">
<pre>bool doMesh1TexelUnits(void) {
GLfloat c[4]={0.0f,0.0f,0.0f,1.0f}; <font color="#ffffaa">// 保存当前的顶点</font>
GLfloat n[4]={0.0f,0.0f,0.0f,1.0f}; <font color="#ffffaa">// 保存法线</font>
GLfloat s[4]={0.0f,0.0f,0.0f,1.0f}; <font color="#ffffaa">// s纹理坐标方向</font>
GLfloat t[4]={0.0f,0.0f,0.0f,1.0f}; <font color="#ffffaa">// t</font><font color="#aaffaa" size="3"><font color="#ffffaa">纹理坐标方向</font></font>
GLfloat l[4]; <font color="#ffffaa">// 保存灯光方向</font>
GLfloat Minv[16]; <font color="#ffffaa">// 保存模型变换矩阵的逆</font>
int i;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); <font color="#ffffaa">// 清空背景颜色和深度缓存</font>
<font color="#ffffaa">// 创建模型变换矩阵的逆</font>
glLoadIdentity();
glRotatef(-yrot,0.0f,1.0f,0.0f);
glRotatef(-xrot,1.0f,0.0f,0.0f);
glTranslatef(0.0f,0.0f,-z);
glGetFloatv(GL_MODELVIEW_MATRIX,Minv);
glLoadIdentity();
glTranslatef(0.0f,0.0f,z);
glRotatef(xrot,1.0f,0.0f,0.0f);
glRotatef(yrot,0.0f,1.0f,0.0f);
<font color="#ffffaa">// 设置灯光的位置</font>
l[0]=LightPosition[0];
l[1]=LightPosition[1];
l[2]=LightPosition[2];
l[3]=1.0f;
VMatMult(Minv,l);
</pre>
</font>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_22_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_22_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_22_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_22_files/l.png"><img src="Tutorial_22_files/l.png"></td>
<td valign="top" width="100%"><u>通道1:</u> <ul type="disc">
<li>使用凹凸纹理</li>
<li>禁止混合</li>
<li>禁止光照</li>
<li>使用无偏移的纹理坐标</li>
<li>绘制几何体</li>
</ul>
这将渲染一个无凹凸贴图的几何体</td>
<td background="Tutorial_22_files/r.png"><img src="Tutorial_22_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_22_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_22_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_22_files/br.png" height="28" width="28"></td></tr></tbody></table><font color="#aaffaa" size="3"><pre> glBindTexture(GL_TEXTURE_2D, bump[filter]);
glDisable(GL_BLEND);
glDisable(GL_LIGHTING);
doCube();
</pre></font><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_22_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_22_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_22_files/tr.png" height="28" width="28"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td background="Tutorial_22_files/l.png"><img src="Tutorial_22_files/l.png"></td>
<td valign="top" width="100%"><u>通道2:</u> <ul type="disc">
<li>使用反转的纹理凹凸贴图</li>
<li>设置混合因子为1,1</li>
<li>使用光照</li>
<li>使用偏移纹理坐标</li>
<li>绘制几何体</li>
</ul>
这将绘制一个具有凹凸贴图的几何体,但没有颜色 <font size="-1"> </font><font face="Tahoma,Verdana,sans-serif" size="-1"><br>
<br>
</font></td>
<td background="Tutorial_22_files/r.png"><img src="Tutorial_22_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_22_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_22_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_22_files/br.png" height="28" width="28"></td></tr></tbody></table><font color="#aaffaa" size="3">
</font><pre><font color="#aaffaa" size="3"> glBindTexture(GL_TEXTURE_2D,invbump[filter]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -