📄 tutorial_36.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_36_files/logo.png" height="130" width="326"></td>
<td align="center" valign="middle" width="75%"><font color="#ffccaa" size="+3"><b><i>第36课
</i></b></font></td>
</tr></tbody></table>
<!-- 上边框-->
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td><img src="Tutorial_36_files/tl.jpg" height="28" width="28"></td>
<td width="100%"><img src="Tutorial_36_files/tc.gif" height="28" width="100%"></td>
<td><img src="Tutorial_36_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_36_files/l.gif"><img src="Tutorial_36_files/l.gif" height="28" width="28"></td>
<!-- 中部文字部分-->
<td valign="top" width="100%">
<table border="0" width="100%">
<tbody><tr>
<td width="32%"><img src="Tutorial_36_files/lesson36.jpg" height="180" width="240"></td>
<td width="68%"><p><font class="head">放射模糊和渲染到纹理:</font></p>
<p><font size="3">如何实现放射状的滤镜效果呢,看上去很难,其实很简单。把渲染得图像作为纹理提取出来,在利用OpenGL本身自带的纹理过滤,就能实现这种效果,不信,你试试。</font></p></td>
</tr>
</tbody></table>
</td>
<!-- 中部右边框-->
<td background="Tutorial_36_files/r.gif"><img src="Tutorial_36_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_36_files/bl.gif" height="28" width="28"></td>
<td width="100%"><img src="Tutorial_36_files/bc.gif" height="28" width="100%"></td>
<td><img src="Tutorial_36_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_36_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_36_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_36_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_36_files/l.png"><img src="Tutorial_36_files/l.png"></td>
<td valign="top" width="100%">嗨,
我是Dario
Corno,也因SpinningKids的rIo而为大家所知。首先,我想要解释我为什么决定写这点指南。我自1989年以来就从事scener的工
作。我想要你们去下载一些demo(示例程序,也就是演示——译者)以帮助你理解什么是Demo并且demo的效果是什么。 <p>Demos是被用来展示恰似风雅的技术一样无限并且时而严酷的译码。在今天的演示中你通常总可以发现一些真正迷人的效果。这不是一本迷人的效果指南,但结果将非常的酷!你能够从http://www.pouet.net和
http://ftp.scene.org. 发现大量的演示收集。<br>
既然绪论超出了我们探讨的范围,我们可以继续我们的指南了。 <br>
我将解释如何做一个看起来象径向模糊的eye candy 效果。有时它以测定体积的光线被提到。不要相信,它仅仅是一个冒牌的辐射状模糊;D<br>
辐射状模糊效果通常借助于模糊在一个方向上相对于模糊物的中心原始图象的每一个象素来做的。<br>
借助于现今的硬件用色彩缓冲器来手工作模糊处理是极其困难的(至少在某种程度上它被所有的gfx卡所支持),因此我们需要一些窍门来达到同样的效果。<br>
作为一个奖励当学习径向模糊效果时,你同样将学到如何轻松地提供材料的纹理。<br>
我决定在这篇指南中使用弹簧作为外形因为它是一个酷的外形,另外还因为我对立方体感到厌烦:}<br>
多留意这篇指南关于如何创建那个效果的指导方针是重要的。我不研究解释那些代码的详情。你应当用心记下它们中的大部分:}<br>
下面是变量的定义和用到的头文件。<br>
</p></td><td background="Tutorial_36_files/r.png"><img src="Tutorial_36_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_36_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_36_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_36_files/br.png" height="28" width="28"></td></tr></tbody></table>
<font color="#aaffaa" size="3">
<pre>#include <math.h> <font color="#ffffaa">// 数学库</font>
float angle; <font color="#ffffaa">// 用来旋转那个螺旋</font>
float vertexes[3][3]; <font color="#ffffaa">// 为3个设置的顶点保存浮点信息</font>
float normal[3]; <font color="#ffffaa">// 存放法线数据的数组</font>
GLuint BlurTexture; <font color="#ffffaa">// 存放纹理编号的一个无符号整型</font>
</pre>
</font>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_36_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_36_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_36_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_36_files/l.png"><img src="Tutorial_36_files/l.png"></td>
<td valign="top" width="100%">函数EmptyTexture()创建了一个空的纹理并返回纹理的编号。我们刚分配了一些自由空间(准确的是128*128*4无符号整数)。<br>
128*128是纹理的大小(128象素宽和高),4意味着为每一个象素我们想用4byte来存储红,绿,蓝和ALPHA组件。<br></td><td background="Tutorial_36_files/r.png"><img src="Tutorial_36_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_36_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_36_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_36_files/br.png" height="28" width="28"></td></tr></tbody></table>
<font color="#aaffaa" size="3">
<pre>GLuint EmptyTexture() <font color="#ffffaa">// 创建一个空的纹理</font>
{
GLuint txtnumber; <font color="#ffffaa"> // 纹理ID</font>
unsigned int* data; <font color="#ffffaa">// 存储数据</font>
<font color="#ffffaa">// 为纹理数据(128*128*4)建立存储区</font>
data = (unsigned int*)new GLuint[((128 * 128)* 4 * sizeof(unsigned int))];
</pre>
</font>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_36_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_36_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_36_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_36_files/l.png"><img src="Tutorial_36_files/l.png"></td>
<td valign="top" width="100%">在分配完空间之后我们用ZeroMemory函数清0,返回指针(数据)和被清0的存贮区的大小。<br>
另一半需注意的重要的事情是我们设置GL_LINEAR的放大率和缩放率的方法。因为我们将被我们的纹理要求投入全部的精力并且如果被滥用,GL_NEAREST会看起来非常糟糕。<br></td><td background="Tutorial_36_files/r.png"><img src="Tutorial_36_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_36_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_36_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_36_files/br.png" height="28" width="28"></td></tr></tbody></table>
<font color="#aaffaa" size="3">
<pre> ZeroMemory(data,((128 * 128)* 4 * sizeof(unsigned int))); <font color="#ffffaa">// 清除存储区</font>
glGenTextures(1, &txtnumber); <font color="#ffffaa">// 创建一个纹理</font>
glBindTexture(GL_TEXTURE_2D, txtnumber); <font color="#ffffaa">// 构造纹理</font>
glTexImage2D(GL_TEXTURE_2D, 0, 4, 128, 128, 0,
GL_RGBA, GL_UNSIGNED_BYTE, data); <font color="#ffffaa">// 用数据中的信息构造纹理</font>
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
delete [] data; <font color="#ffffaa">// 释放数据</font>
return txtnumber; <font color="#ffffaa">// 返回纹理ID</font>
}
</pre>
</font>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_36_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_36_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_36_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_36_files/l.png"><img src="Tutorial_36_files/l.png"></td>
<td valign="top" width="100%">这
个函数简单规格化法线向量的长度。向量被当作有3个浮点类型的元素的数组来表示,第一个元素表示X轴,第二个表示Y,第三个表示Z。一个规格化的向量
[Nv]被Vn表达为Vn=[Vox/|Vo|,Voy/|Vo|,Voz/|Vo|],这里Vo是最初的向量,|Vo|是该向量的系数(或长度),X,
Y,Z它的组件。之后由向量的长度区分每一个法线向量组件。<br></td><td background="Tutorial_36_files/r.png"><img src="Tutorial_36_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_36_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_36_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_36_files/br.png" height="28" width="28"></td></tr></tbody></table>
<font color="#aaffaa" size="3">
<pre>void ReduceToUnit(float vector[3]) <font color="#ffffaa">// 归一化一个法向量</font>
{ <font color="#ffffaa">// 一定长度的单位法线向量</font>
float length; <font color="#ffffaa">// 保存长度</font>
<font color="#ffffaa">// 计算向量</font>
length = (float)sqrt((vector[0]*vector[0]) + (vector[1]*vector[1]) + (vector[2]*vector[2]));
if(length == 0.0f) <font color="#ffffaa">// 避免除0错误</font>
length = 1.0f; <font color="#ffffaa">// 如果为0设置为1</font>
vector[0] /= length; <font color="#ffffaa">// 归一化向量</font>
vector[1] /= length;
vector[2] /= length;
}
</pre>
</font>
<table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_36_files/tl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_36_files/tc.png" height="28" width="100%"></td><td><img src="Tutorial_36_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_36_files/l.png"><img src="Tutorial_36_files/l.png"></td>
<td valign="top" width="100%">下面各项计算所给的3个顶点向量(总在3个浮点数组中)。我们有两个参数:v[3][3]和out[3]。当然第一个参数是一个m=3,n=3每一行代表三角形一个顶点的浮点矩阵。Out是我们要放置作为结果的法线向量的位置。<br>
相当简单的数学。我们将使用著名的交叉乘积运算。理论上说交叉乘积是两个向量——它返回另一个直交向量到两个原始向量——之间的操作。法线向量是一个垂直
物体表面的直交向量,是与该表面相对的(通常一个规格化的长度)。设想两个向量是在一个三角形的一侧的上方,那么这个三角形两边的直交向量(由交叉乘积计
算)就是那个三角形的法线。<br>
解释比实行还难。<br>
我们将着手从现存的顶点0到顶点1,从顶点1到顶点2找到那个向量。这是基本上通过减法——下一个顶点的每个组件减一个顶点的每个组件——作好了的。现在我们已经为我们的三角形的边找到了那个向量。通过交叉相乘我们为那个三角形找到了法线向量。<br>
看代码。<br>
V[0][ ]是第一个顶点,v[1][ ]是第二个顶点,v[2][ ]是第三个顶点。每个顶点包括:v[ ][0]是顶点的x坐标,v[ ][1]是顶点的y坐标,v[
][2]是顶点的z坐标。<br>
通过简单的减法从一个顶点的每个坐标到另一个顶点每个坐标我们得到了那个VECTOR。v1[0] = v[0][0] - v[1][0],这计算现存的从一个顶点到另一个顶点的向量的X组件,v1[1]
= v[0][1] - v[1][1]将计算Y组件,v1[2] = v[0][2] - v[1][2] 计算Z组件等等。<br>
现在我们有了两个向量,所以我们计算它们的交叉乘积得到那个三角形的法线。 <p>交叉相乘的规则是:<br>
out[x] = v1[y] * v2[z] - v1[z] * v2[y] </p>
<p>out[y] = v1[z] * v2[x] - v1[x] * v2[z] </p>
<p>out[z] = v1[x] * v2[y] - v1[y] * v2[x] </p>
<p><br>
我们最终得到了这个三角形的法线in out[ ]。<br>
</p>
</td><td background="Tutorial_36_files/r.png"><img src="Tutorial_36_files/r.png"></td></tr></tbody></table><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="Tutorial_36_files/bl.png" height="28" width="28"></td><td width="100%"><img src="Tutorial_36_files/bc.png" height="28" width="100%"></td><td><img src="Tutorial_36_files/br.png" height="28" width="28"></td></tr></tbody></table>
<font color="#aaffaa" size="3">
<pre>void calcNormal(float v[3][3], float out[3]) <font color="#ffffaa">// 用三点计算一个立方体法线</font>
{
float v1[3],v2[3]; <font color="#ffffaa">// 向量 1 (x,y,z) 和向量 2 (x,y,z)</font>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -