📄 tutorial_22.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><html><head><!-- 这篇文章由Dancingwind翻译,作者的联系方式zhouwei02@mails.tsinghua.edu.cn --><title>NeHe OpenGL教程第二十二课,DancingWind翻译</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<style type="text/css">
A:link {COLOR: #ccaaff; TEXT-DECORATION: none}
A:visited {COLOR: #ccaaff; TEXT-DECORATION: none}
A:active {COLOR: #ccaaff; TEXT-DECORATION: none}
A:hover {COLOR: #ffccaa; TEXT-DECORATION: none}
</style></head><body bgcolor="#000000" text="#ffffff"><br><br>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td height="130" width="326"><img src="Tutorial_22_files/logo.png" height="130" width="326"></td>
<td align="center" valign="middle" width="75%"><font color="#ffccaa" size="+3"><b><i>第22课</i></b></font></td>
</tr></tbody></table>
<!-- 上边框-->
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td><img src="Tutorial_22_files/tl.jpg" height="28" width="28"></td>
<td width="100%"><img src="Tutorial_22_files/tc.gif" height="28" width="100%"></td>
<td><img src="Tutorial_22_files/tr.gif" 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.gif"><img src="Tutorial_22_files/l.gif" height="28" width="28"></td>
<!-- 中部文字部分-->
<td valign="top" width="100%">
<table border="0" width="100%">
<tbody><tr>
<td width="31%"><img src="Tutorial_22_files/lesson22.jpg" height="180" width="240"></td>
<td width="69%"><p><font class="head">凹凸映射,多重纹理扩展:</font></p>
<p><font size="3">这是一课高级教程,请确信你对基本知识已经非常了解了。这一课是基于第六课的代码的,它将建立一个非常酷的立体纹理效果。</font></p></td>
</tr>
</tbody></table>
</td>
<!-- 中部右边框-->
<td background="Tutorial_22_files/r.gif"><img src="Tutorial_22_files/r.gif" height="28" width="28"></td>
</tr>
</tbody>
</table>
<!-- 下边框-->
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td><img src="Tutorial_22_files/bl.gif" height="28" width="28"></td>
<td width="100%"><img src="Tutorial_22_files/bc.gif" height="28" width="100%"></td>
<td><img src="Tutorial_22_files/br.gif" height="28" width="28"></td>
</tr>
</tbody>
</table>
<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%">这一课由Jens Schneider所写,它基本上是由第6课改写而来的,在这一课里,你将学习:
<ul>
<li>怎样控制多重纹理</li>
<li>怎样创建一个“假”的凹凸映射</li>
<li>怎样做一个标志,它看起来在你的场景上方</li>
<li>怎样使矩阵变化更有效率</li>
<li>基本的多通道渲染</li>
</ul>
因为上面提到的很多方面是高级渲染得内容,我们在讲述的时候会先说明理论,接着在分析代码 。如果你已经熟悉了这些理论,你可以跳过他们,直接看代码。当你遇到什么问题的时候,不妨回过头来看看这些理论。<br>
最后这份代码超过了1200行,大部分我们在前面的教程中遇到过了。我不会解释每一行代码,只在重要的地方做些提示,好了,让我们开始吧。</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>#include <string.h> <font color="#ffffaa">// 字符串处理函数</font></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%">MAX_EMBOSS常量定义了突起的最大值</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>#define MAX_EMBOSS (GLfloat)0.01f <font color="#ffffaa">// 定义了突起的最大值</font>
</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%">好了,现在我们准备使用GL_ARB_multitexture这个扩展,它非常简单。
<p>大
部分图形卡不止一个纹理单元,为了利用这个功能,你必须检查GL_ARB_multitexture是否被支持,它可以使你同时把2个或多个不同的纹理映
射到OpenGL图元上。开起来这个功能好像没有太大的作用,但当你使用多个纹理时,如果能同时把这些纹理值混合,而不使用费时的乘法运算,你将会得到很
高的速度提高。</p>
<p>现在回到我们的代码,__ARB_ENABLE用来设置是否使用ARB扩展。如果你想看你的OpenGL扩
展,只要把#define
EXT_INFO前的注释去掉就行了。接着,我们在运行检查我们的扩展,以保证我们的程序可以在不同的系统上运行。所以我们需要一些内存保存扩展名的字符
串,他们是下面两行。接着我们用一个变量multitextureSupported来标志当前系统是否能使用multitexture扩展,并用
maxTexelUnits记录运行系统的纹理单元,这个值最少是1。</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>#define __ARB_ENABLE true <font color="#ffffaa">// 使用它设置是否使用ARB扩展</font>
<font color="#ffffaa">// #define EXT_INFO // 把注释去掉,可以在启动时查看你的扩展</font>
#define MAX_EXTENSION_SPACE 10240 <font color="#ffffaa">// 保存扩展字符</font>
#define MAX_EXTENSION_LENGTH 256 <font color="#ffffaa">// 每个扩展字符串最大的长度</font>
bool multitextureSupported=false; <font color="#ffffaa">// 标志是否支持多重渲染</font>
bool useMultitexture=true; <font color="#ffffaa">// 如果支持,是否使用它</font>
GLint maxTexelUnits=1; <font color="#ffffaa">// 纹理处理单元的个数</font>
</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%">下
面的函数定义用来使用OpenGL的扩展函数,你可以把PFN-who-ever-reads-this看成是预先定义的函数类型,因为我们不清楚是否能
得到这些函数的实体,所以先把他们都设置为NULL。glMultiTexCoordifARB函数是glTexCoordif函数的扩展,它门的功能相
似,其中i为纹理坐标的维数,f为数据的类型。最后两个函数用来激活纹理处理单元,可以使用特定的纹理单元来邦定纹理。<br>
顺便说一句,ARB是"Architectural Review
Board"的缩写,用来定义这个组织提出的对OpenGL的扩展,并不强制OpenGL的实现必须包含这个功能,但他们希望这个功能得到广泛的支持。当
前,只有multitexture被加入到ARB中,这从另一个方面支持multitexture的扩展将大大的提高渲染速度。</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">PFNGLMULTITEXCOORD1FARBPROC glMultiTexCoord1fARB = NULL;
PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB = NULL;
PFNGLMULTITEXCOORD3FARBPROC glMultiTexCoord3fARB = NULL;
PFNGLMULTITEXCOORD4FARBPROC glMultiTexCoord4fARB = NULL;
PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = NULL;
PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB= NULL;
</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%">下面我们来定义一些全局变量:<font size="-1"> </font> <ul>
<li>filter定义过滤器类型
</li><li>texture[3]保存三个纹理
</li><li>bump[3]保存三个凹凸纹理
</li><li>invbump[3]保存三个反转了的凹凸纹理
</li><li>glLogo保存标志
</li><li>multiLogo保存多重纹理标志
</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>GLuint filter=1; <font color="#ffffaa"> // 定义过滤器类型</font>
GLuint texture[3]; <font color="#ffffaa">// 保存三个纹理</font>
GLuint bump[3]; <font color="#ffffaa"> //保存三个凹凸纹理</font>
GLuint invbump[3]; <font color="#ffffaa">// 保存三个反转了的凹凸纹理</font>
GLuint glLogo; <font color="#ffffaa">// glLogo保存标志</font>
GLuint multiLogo; <font color="#ffffaa"> // multiLogo保存多重纹理标志</font>
GLfloat LightAmbient[] = { 0.2f, 0.2f, 0.2f}; <font color="#ffffaa">// 环境光</font>
GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f}; <font color="#ffffaa">// 漫射光</font>
GLfloat LightPosition[] = { 0.0f, 0.0f, 2.0f}; <font color="#ffffaa">// 光源位置</font>
GLfloat Gray[] = { 0.5f, 0.5f, 0.5f, 1.0f};
</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%">下面一块代码用来保存立方体的纹理和坐标,每5个数字描述一个顶点,包含2D的纹理坐标和3D的顶点坐标。</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>
GLfloat data[]= {
<font color="#ffffaa">// 前面</font>
0.0f, 0.0f, -1.0f, -1.0f, +1.0f,
1.0f, 0.0f, +1.0f, -1.0f, +1.0f,
1.0f, 1.0f, +1.0f, +1.0f, +1.0f,
0.0f, 1.0f, -1.0f, +1.0f, +1.0f,
<font color="#ffffaa">// 背面</font>
1.0f, 0.0f, -1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f, +1.0f, -1.0f,
0.0f, 1.0f, +1.0f, +1.0f, -1.0f,
0.0f, 0.0f, +1.0f, -1.0f, -1.0f,
<font color="#ffffaa">// 上面</font>
0.0f, 1.0f, -1.0f, +1.0f, -1.0f,
0.0f, 0.0f, -1.0f, +1.0f, +1.0f,
1.0f, 0.0f, +1.0f, +1.0f, +1.0f,
1.0f, 1.0f, +1.0f, +1.0f, -1.0f,
<font color="#ffffaa">// 下面</font>
1.0f, 1.0f, -1.0f, -1.0f, -1.0f,
0.0f, 1.0f, +1.0f, -1.0f, -1.0f,
0.0f, 0.0f, +1.0f, -1.0f, +1.0f,
1.0f, 0.0f, -1.0f, -1.0f, +1.0f,
<font color="#ffffaa">// 右面</font>
1.0f, 0.0f, +1.0f, -1.0f, -1.0f,
1.0f, 1.0f, +1.0f, +1.0f, -1.0f,
0.0f, 1.0f, +1.0f, +1.0f, +1.0f,
0.0f, 0.0f, +1.0f, -1.0f, +1.0f,
<font color="#ffffaa">// 左面</font>
0.0f, 0.0f, -1.0f, -1.0f, -1.0f,
1.0f, 0.0f, -1.0f, -1.0f, +1.0f,
1.0f, 1.0f, -1.0f, +1.0f, +1.0f,
0.0f, 1.0f, -1.0f, +1.0f, -1.0f
};
</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>首先,我们假定一个字符串包含了所有的扩展名,各个扩展名之间用'\n'分开。我们所要做的就是在其中查找是否有我们需要的扩展。如果成功找到则返回TRUE,否则返回FALSE。</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>bool isInString(char *string, const char *search) {
int pos=0;
int maxpos=strlen(search)-1;
int len=strlen(string);
char *other;
for (int i=0; i<len; i++) {
if ((i==0) || ((i>1) && string[i-1]=='\n')) { <font color="#ffffaa"> // 新的扩展名开始与这里</font>
other=&string[i];
pos=0; <font color="#ffffaa">// 开始新的比较</font>
while (string[i]!='\n') { <font color="#ffffaa">// 比较整个扩展名</font>
if (string[i]==search[pos]) pos++; <font color="#ffffaa">// 下一个字符</font>
if ((pos>maxpos) && string[i+1]=='\n') return true; <font color="#ffffaa">// 如果整个扩展名相同则成功返回</font>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -