﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-C++ Programmer's Cookbook-随笔分类-Game/OpenGL</title><link>http://www.cppblog.com/mzty/category/5694.html</link><description>&lt;br/&gt;  
&lt;br/&gt;
&lt;a href = "http://www.cppblog.com/mzty/archive/2007/03/02/19109.html"&gt;&lt;font size = 5 color ="#00FFFF"&gt;{C++ 基础}&lt;font/&gt;&lt;/a&gt;

&lt;a href = "http://www.cppblog.com/mzty/archive/2007/08/13/29922.html"&gt;&lt;font size = 5 color ="#00FFFF"&gt;{C++ 高级}&lt;font/&gt;&lt;/a&gt;

&lt;a href = "http://www.cppblog.com/mzty/archive/2007/04/16/22064.html"&gt;&lt;font size = 5 color ="#00FFFF"&gt;{C#界面，C++核心算法}&lt;font/&gt;&lt;/a&gt;

&lt;a href = "http://www.cppblog.com/mzty/archive/2007/03/04/19163.html"&gt;&lt;font size = 5 color ="#00FFFF"&gt;{设计模式}&lt;font/&gt;&lt;/a&gt;

&lt;a href = "
http://www.cppblog.com/mzty/archive/2007/03/04/19167.html"&gt;&lt;font size = 5 color ="#FF0000"&gt;{C#基础}&lt;font/&gt;&lt;/a&gt;





</description><language>zh-cn</language><lastBuildDate>Tue, 20 May 2008 03:03:16 GMT</lastBuildDate><pubDate>Tue, 20 May 2008 03:03:16 GMT</pubDate><ttl>60</ttl><item><title>游戏引擎基础（十一）（最后的章节）</title><link>http://www.cppblog.com/mzty/archive/2007/12/04/37781.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Tue, 04 Dec 2007 05:31:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2007/12/04/37781.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/37781.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2007/12/04/37781.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/37781.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/37781.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 第11部份: 最后的章节前端　　你已经看到了菜单系统，你可能理解游戏内的头顶显示（HUDs）时常是游戏经历中被忽视和诽谤的部分。最近，这个领域开始被给人印象非常深刻的Black and White所关注，这款游戏实际上没有HUD。在Peter Molyneux经历了Dungeon Keeper以后，它在屏幕上大量的图标，他决定游戏的大部分被这些图标占用了，主要的屏幕没有被足够利用。因此他决定废除所...&nbsp;&nbsp;<a href='http://www.cppblog.com/mzty/archive/2007/12/04/37781.html'>阅读全文</a><img src ="http://www.cppblog.com/mzty/aggbug/37781.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2007-12-04 13:31 <a href="http://www.cppblog.com/mzty/archive/2007/12/04/37781.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏引擎基础（十）（人工智能和导航）</title><link>http://www.cppblog.com/mzty/archive/2007/12/04/37780.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Tue, 04 Dec 2007 05:29:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2007/12/04/37780.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/37780.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2007/12/04/37780.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/37780.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/37780.html</trackback:ping><description><![CDATA[<span>第</span><span>10</span><span>部分</span><span>: </span><span>人工智能和导航（路径发现）</span><span><br><br><br></span><strong><span>人工智能（</span></strong><strong><span>AI</span></strong><strong><span>）</span></strong><span><br></span><span>　　我们上面已经用了其他九个章节介绍了游戏引擎，现在让我们深入到非常有趣和重要的人工智能主题。人工智能如今正在变成被谈论得最多的仅次于游戏引擎渲染能力的游戏开发领域之一，确实如此。直到大约两年半以前，游戏似乎主要是在考虑你能够渲染多少个多边形，眼睛是多么的漂亮，和</span><span>&#8230; </span><span>好</span><span>&#8230;</span><span>劳拉的胸部是多么的有弹性</span><span>...</span><span>既然我们现在已经能够渲染出非常真实的乳房，中心就开始转移到我们实际上用那些多边形做什么了（即玩游戏）。因为它给你提供实际玩游戏的刺激作用和参与游戏世界中正在进行的事情，所以人工智能在这个领域非常关键。</span><span><br><br></span><span>　　人工智能包括了全部的东西，从在</span><span>Tetris</span><span>中决定哪一块新砖头掉落（这很大程度上知识一个随即数产生器），</span><span> </span><span>一直到创造基于小组的策略游戏，这些游戏和你交互，并且实际上在你玩的时候向你学习。人工智能包含了许多规则，如果你（作为一个游戏开发者）没有花费足够多的时间让它正确地工作，它会反过来在你屁股上咬一口。所以让我们谈论一些哪些规则？这样你能更好地理解人工智能系统会确实是多么的复杂。为了避免法律上的纠纷，我们将使用一个假设的游戏而不是一个真实的游戏作为例子。</span><span><br><br></span><span>　　假设我们的游戏中有坏份子生活在</span><span>3D</span><span>世界中，干着他们的事情，而且如果你打搅了他们的正常次序他们就会反抗你（玩家）。你必须决定的第一件事情就是他们正在从事的到底是什么事情呢？他们正在守卫什么东西吗？在巡查？在计划一个聚会？在购买食品杂货？在整理床铺？建立行为的基线是游戏开发者的工作之一。一旦有了这个，你就总有</span><span>NPC</span><span>（非玩家角色）或计算机控制的</span><span>&#8216;</span><span>人</span><span>&#8217;</span><span>能够恢复去做的事情，玩家与他们的交互就应当能被完成。</span><span> <br><br></span><span>　　一旦我们知道一个</span><span>NPC</span><span>角色需要做什么</span><span> — </span><span>比如它在守卫一扇门，并且在这个区域小巡逻，</span><span>NPC</span><span>也必须有</span><span>&#8216;</span><span>世界意识</span><span>&#8217;</span><span>。游戏设计者需要决定</span><span>NPC</span><span>的人工智能将如何看见世界，和它的知识范围。你将会仅仅说</span><span>&#8220;</span><span>计算机知道正在进行的每件事情</span><span>&#8221; </span><span>吗？这通常被认为是一件糟糕的事情，因为非常明显计算机能够看见和听见你不能看见和听见的事情，这被当成是在作弊。不是一种有趣的经历。或者你将模拟他的视野，这样他只能够对他能看见的事物作出反应吗？当有墙壁出现时这里就有问题了，因为你开始进入那些我在第九部分提到的</span><span>&#8216;</span><span>追踪</span><span>&#8217;</span><span>例程，看看</span><span>NPC</span><span>是否试图对被墙壁挡住的人作出反应。这是一个很明显的人工智能问题，但是当涉及到门和窗户时，这个甚至变得更加复杂了。</span><span> <br><br></span><span>　　当你开始为</span><span>AI</span><span>刺激例程增加听觉意识时，这依然变得更加复杂了。但是，这个意识是那些关键的</span><span>&#8220;</span><span>小事情</span><span>&#8221;</span><span>之一，这些使得假想的游戏世界似乎更加真实，或者能够去除怀疑的悬念。如果你碰到过这样的事情，请举手：你在枪战中跟一个</span><span>NPC</span><span>交战，免除了一个</span><span>NPC</span><span>，你绕着角落行走并遇到了另外一个</span><span>NPC</span><span>依然保持他的缺省行为模式，没有意识到刚刚发生的事情。现在，枪是嘈杂的事物，枪战可能已经明显地提醒了一个</span><span>&#8220;</span><span>倾听</span><span>&#8221;</span><span>的</span><span>NPC</span><span>有些事情正在进行。避免这种事情的技巧在于找到一个有效的方式来决定声源（即你武器的发射）的距离是否足够接近到</span><span>NPC</span><span>能够听见。</span><span><br><br></span><span>　　接下来就是决策例程。当我们的巡逻</span><span>NPC</span><span>角色能够听到但不能看见某物时，你试图实现什么样的行为呢？他去寻找它吗？不理睬它？你如何决定什么是重要的声音他应该去或者不去调查？如同你看见的一样，这会很快变得非常的复杂。有很多方法来建造处理这些事情的代码，但通常这样是一个好主意，建立一个不是对特定的</span><span>NPC</span><span>而是对所有的</span><span>NPC</span><span>都起作用的系统，该系统基于你能够在游戏引擎以外的文本文件中建立的属性。这样就不需要程序员为一个给定的角色而改变</span><span>AI</span><span>，并且如果你对游戏代码做了改动，它将立即自动地应用到所有的角色，这在大多数情况下是一件好事情。</span><span> <br><br></span><span>　　其他的世界意识问题会冒出来，比如这样的情形，两个守卫彼此紧挨着站立，你用狙击武器干掉了一个，而另外一个站在哪儿完全不知已经发生的事情。再者，遵守真实世界行为的细节是一款好游戏和一款伟大游戏的之间的区别。</span><span> <br><br></span><span>　　让我们说你已经把所有的刺激</span><span>-</span><span>响应部分准备好了</span><span>—</span><span>你已经扫描了世界，决定</span><span>NPC</span><span>应当对正在进行的一些事情作出反应</span><span>—</span><span>他听到了玩家角色发出了声响</span><span>—</span><span>并且你（游戏开发者）决定了他应当对这个做些什么</span><span>—</span><span>他将去调查。现在更加复杂的事情来了。他如何离开现在的位置，到达他认为发出声音的地方，而不会想通常的数字傻瓜一样跑到墙壁里面，碰到家具呢？继续往下看</span><span>&#8230;<br><br><br></span><strong><span>有关正确的路径</span></strong><strong><span> --- </span></strong><strong><span>世界导航</span></strong><span><br></span><span>　　快速，准确的世界导航</span><span>( </span><span>也叫做路径</span><span>-</span><span>发现</span><span>) </span><span>近来已经成为游戏开发者的圣杯。</span><span> </span><span>让它看起来非常信服是一件非常困难的事情。你需要有局部世界的地理知识</span><span>—</span><span>墙壁的位置，台阶，悬崖和建筑物等的边缘。你也需要世界中的对象的知识</span><span>—</span><span>比如家具，汽车，尤其是其他人的位置。真正最后的因素是问题所在，一会儿我们将回到这一点上。</span><span> <br><br></span><span>　　世界导航通常被分为两个领域，世界导航和局部导航。二者实际上只是范围上的区别，但大多数的程序员分别对待它们，因为这样处理起来容易一些。世界导航例程处理理解房间，门和一般的地理学，并计算出让玩家或者角色从世界中的</span><span>A</span><span>点到达</span><span>B</span><span>点的一条路径。</span><span>&#8220;</span><span>它将让你从</span><span>A</span><span>点到达</span><span>B</span><span>点</span><span>&#8221;</span><span>，这是一句很容易说的话，不是吗？说起来容易，但做起来很困难。理解世界是一个非常复杂问题，我已经看到过许多尝试过的解决办法。</span><span>QuakeIII</span><span>的机器人遵照建造的预先处理过的地图，一般的说法，使用原来地图的地面。预处理器检测地面元素，由地图建造者作上标记，并自己建造一个只使用地面的世界简化地图。机器人并不关心墙壁，因为他们从不接近它们，就像他们遵照地面的地图一样，设计上已经把避免墙壁构造在里面了。</span><span> <br><br></span><span>　　其他方法在地图本身里面建造一些小的结点，</span><span>AI</span><span>可以追随它们。这些结点通常被建造在彼此的视线里面，有从一个结点到其他所有结点的连接，角色</span><span>AI</span><span>能够直接</span><span>&#8216;</span><span>看见</span><span>&#8217;</span><span>，所以你就确保了从一个结点移动到另外一个结点时</span><span>AI</span><span>不会试图穿越墙壁。如果有门或者降落物，你能够事先用这些结点对路径的信息编码，于是</span><span>NPC</span><span>能够采用适当的行为</span><span>—</span><span>等候电梯，打开一扇门，或者从一点跳到另外一点。这实际上是</span><span>HereticII</span><span>使用的系统，也是</span><span>Raven</span><span>在他们其他的大多数游戏中使用的系统。</span><span> <br><br></span><span>　　关于这个主题，</span><span>3D Realms</span><span>的</span><span>Jess Crable</span><span>，现在为</span><span>Duke Nukem Forever</span><span>工作，如是说：</span><span> <br><br></span><span>　　</span><span>"</span><span>导航在许多方面是个巨大的挑战，主要是当游戏中有大量正在发生的事情和一些非计划性的东西，比如障碍。为了避免和（或）真实地对非计划性的障碍物导航（例如像另外的</span><span>AI</span><span>），</span><span>AI</span><span>需要很好地知道正在它周围发生的事情。比较而言另外一个巨大的挑战就是真实感。如果</span><span>AI</span><span>正在表现玩家在实际生活中看到的一些东西，比如说一个人，或者一条狗，</span><span> </span><span>那么让它看上去真实可信就更加困难。</span><span>"<br><br></span><span>　　然后就是局部导航。我们可能有一条路径让我们的</span><span> NPC </span><span>从他在世界中的位置，移动到他认为听到声音的地方，但你不能盲目地按照这个执行并期望得到看起来不错的结果。这种性质的路径倾向于非常特定于一个给定的目的。当你沿着走廊从一个房间跑到另外一个房间时，它很好，但如果你试图指导他穿越一个巨大的房间时，路径结点方法容易最终得到一些看起来很奇怪的发现路径。这些路径也不是动态的。因为他们被预先建造，他们不容易考虑到世界的任何动态变化。桌子可能有被移动过了，椅子被破坏了，墙壁被摧残，当然，人们会移动。这就是局部导航不同于世界导航的地方。它必须考虑局部世界并导航</span><span>NPC</span><span>在里面穿越。它必须知道周围的环境，存在哪些可以选择的路径，并决定选择哪一条。</span><span> <br><br></span><span>　　在局部导航中最大的问题是其他的</span><span>NPC</span><span>。给定一个发现路径的具体例程，如果你在相同的一般区域中有不止一个</span><span>NPC</span><span>，他们都试图到达世界的同一地点，结果是他们都非常容易有相同的路径。然后他们试图沿着这个路径行进，结果彼此遇到一起，然后花费他们所有的时间试图将彼此分开，并且一旦成功地分开了，他们再次试图到达目标，然后我们又再次看到同样的事情发生。这一切看起来都是非常的愚蠢，这不是大多数人想要的效果。所以需要一些路径发现中的变化来避免这种情形，需要一些妥善处理避免的代码。有大量能够帮助解决这种情形的算法。</span><span><br><br><br></span><strong><span>人工智能和角色动画问题</span></strong><span><br></span><span>　　当然，当角色自己在世界中行走时你必须完全地决定你想要角色播放什么动画。听起来无足轻重？不是的。关于这个主题，</span><span>Raven</span><span>的</span><span> Chris Reed—Soldier of FortuneII</span><span>使用名为</span><span>LICH</span><span>的</span><span>AI</span><span>系统的现在的负责人</span><span>—</span><span>如是说：</span><span> <br><br></span><span>　　</span><span>"</span><span>此刻我能告诉你，我们在平滑移动上正有着最大的困难。在一个多丘陵的长满草的丛林中试图让五个角色在彼此附近行走是一个非常困难的问题。让底层系统完美是重要的，因为除非角色在较低层次上（避免墙壁，适当的动画）看起来真实，他们不能够有效地表达任何较高层次决定的智能。由于这个单独的原因，动画和底层的移动是最重要的和最难实现的。它确实需要完美。</span><span>"<br><br></span><span>　　因此我们已经让我们的角色从</span><span>A</span><span>点到达了</span><span>B</span><span>点，他自己穿越世界，在途中避免障碍物，正确播放动画，现在到达了这里。他看见了你。接下来做什么呢？很明显更多的是作出决策。他将向你射击。太棒了。你回应射击。现在干什么？当他试着逃走的时候，现在你再次经历全部同样的事情。</span><span> <br><br></span><span>　　为了让这些情形看起来令人信服，你看见了这里必须要处理的大量问题。如果你建立你的</span><span>AI</span><span>使用没有动画的行为让</span><span>NPC</span><span>执行，这能被混合。一些</span><span>Soldier of Fortune</span><span>中的</span><span>AI</span><span>就是这样的例子。他们受到了指责，因为坏家伙没有以适当的方式对刺激作出反应。当他们明显应该这样做的时候，敌方</span><span>NPC</span><span>不扫射，或者不逃跑。部分问题是他们没有扫射敌人</span><span>NPC</span><span>的动画，或者让他们往回跑，因为空间的问题。因此世界上所有最伟大的</span><span>AI</span><span>代码都不能够解决这个问题。这是所有要考虑的重要事情。</span><span> <br><br></span><span>　　想知道隐藏的难点吗？看看我前面所有的描述，然后试着将它应用到一组</span><span>NPC</span><span>上，这些</span><span>NPC</span><span>彼此必须说话，设定目标，彼此沟通，但不妨碍彼此的方式。一旦你这么做了，试试那些代码，作为玩家的队友做上面所描述的这些，然而不要在枪战中妨碍他。现在这是复杂的。然后这成为乐趣。这是最困难的部分。</span><span>Raven</span><span>的</span><span> Chris Reed</span><span>关于</span><span>AI&#8216;</span><span>感觉</span><span>&#8217;</span><span>的一些评论：</span><span> <br><br></span><span>　　</span><span>"</span><span>我认为反馈是</span><span>AI</span><span>的一个极大的问题。如果角色对于他周围环境的变化不产生反应，游戏的真实感就被完全打破了。这有许多明显的例子</span><span>(</span><span>听见枪炮声，看见同伴被击中</span><span>...)</span><span>，以及一些更加微妙的事情</span><span>(</span><span>当两个人通过门厅时看着彼此并点头致意</span><span>)</span><span>。玩家是乐意接受一些生硬和可预测性的，但是这些事物容易把游戏带到现实生活。</span><span>"<br><br></span><span>　　并且</span><span>Jess Crable </span><span>赞同：</span><span><br><br></span><span>　　</span><span>"</span><span>平衡是非常重要的</span><span>&#8230; </span><span>对玩家将会有多大的乐趣至关重要，但还有其他的问题要平衡。游戏玩家时常说他们想在游戏中看见更加真实的人工智能。然而，太多的真实感开始把乐趣带走。在这两者之间必须要有一个好的平衡。变化和随机同样也很重要</span><span>—</span><span>行为的变化，和保持在可信范围内的一定程度的不可预测性。</span><span>"<br><br><br></span><strong><span>游戏规则与自然发生的游戏</span></strong><span><br></span><span>　　在我们关于</span><span>AI</span><span>的所有描述中，我们采用的是</span><span>FPS</span><span>的方式。有不止一种的</span><span>AI</span><span>。我们已经描述的是处理</span><span>3D</span><span>世界一组规则。</span><span>AI</span><span>远远不止这些。时常最好的</span><span>AI</span><span>实际上非常的简单。它就是一组规则，玩家必须响应和处理的响应（或开始）动作的规则。</span><span> <br><br></span><span>　　这里应当处理一个被称为</span><span>&#8220;</span><span>自然发生的游戏</span><span>&#8221;</span><span>的专业术语。</span><span> </span><span>自然发生的游戏本质上创造游戏将遵守的规则，那将会造成游戏程序员不能预见的情形。</span><span> <br><br></span><span>　　举例来说，象棋能被认为是自然发生的游戏。有一组规则，但游戏能够陷入各种程序员不能够以个别方式处理的情形。你不能为每一种可能的棋局情形编码规则。很清楚，游戏玩家每次不会总是面临相同的游戏情景。一定程度上，进行中的游戏情形会根据他的行动而发生变化。</span><span>Black and White</span><span>是这种情形的一个完美的例子，和</span><span>The Sims</span><span>一样</span><span>—</span><span>游戏有它自己的规则，但你如何运用和调和他们是你自己的事情。实际上，你在玩游戏的过程中创造着游戏，而不是照着游戏设计者</span><span>/</span><span>程序员已经为你定义的路线进行。</span><span> <br><br></span><span>　　有可能把基于规则的，自然发生的游戏方式和</span><span>FPS</span><span>环境混合在一起。</span><span>Half Life</span><span>中的一些海军陆战队士兵的行为就是这样做的</span><span>—</span><span>压制火力和侧翼攻击从设定的规则中动态完成。它看起来是动态的，而且一定程度上它是这样。然而，在</span><span>FPS</span><span>世界中仅仅有一组规则时常是不够的。几何和其他</span><span>AI</span><span>时常能够打败简单的规则，这让保持正确并依然有趣变得更加困难。所以对那些可怜的</span><span>AI</span><span>程序员有一些同情心吧。他们的工作不容易。</span><span> <br><br><br></span><span>　　好吧，下面还有一个章节，仅仅还剩下一个章节了。在最后的章节里，我们将讨论头顶显示，菜单系统，游戏定制和配置，游戏引擎版权与建造，最后是游戏</span><span>&#8220;mods&#8221;</span><span>。</span><span> <br><br></span><img src ="http://www.cppblog.com/mzty/aggbug/37780.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2007-12-04 13:29 <a href="http://www.cppblog.com/mzty/archive/2007/12/04/37780.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏引擎基础（九）（现成产品与定做的游戏引擎设计工具，游戏特定主题）</title><link>http://www.cppblog.com/mzty/archive/2007/12/04/37779.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Tue, 04 Dec 2007 05:28:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2007/12/04/37779.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/37779.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2007/12/04/37779.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/37779.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/37779.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 第9部分: 现成产品与定做的游戏引擎设计工具，游戏特定主题现成产品与定做的设计工具　　我们从第8部份的脚本引擎来到这一章节中的许多主题，我们认为那些铁杆游戏玩家和有志成为游戏开发者的那些人将会发现它们相当有趣。我们将开始讨论现成产品与定制的设计工具。 　　你的工具的选择是你引擎设计的一个非常重要的部份，因为这是你将用来给你的游戏产生内容的东西，是最耗时的部份。在这个过程中有助于节省时间和资源的任何...&nbsp;&nbsp;<a href='http://www.cppblog.com/mzty/archive/2007/12/04/37779.html'>阅读全文</a><img src ="http://www.cppblog.com/mzty/aggbug/37779.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2007-12-04 13:28 <a href="http://www.cppblog.com/mzty/archive/2007/12/04/37779.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏引擎基础（八）（脚本系统）</title><link>http://www.cppblog.com/mzty/archive/2007/12/04/37778.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Tue, 04 Dec 2007 05:27:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2007/12/04/37778.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/37778.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2007/12/04/37778.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/37778.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/37778.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 第8部份: 脚本系统脚本系统　　我们从第七部分的游戏网络问题来到了脚本系统，因为其呈现的故事叙述机会，最近已经形成一种很大的游戏元素。在一个需要以受控制的方式解释的情景，预先编制的电影脚本是解决问题的方法。在电影中，这通常用来处理或者由主角向一个伙伴解释情形，或者敌人对英雄解释。当然，有其它的方法来做这件事情 -- 叙事者，倒叙，等等 &#8211; 但通常是使用实时情景的人们和事件来完成。当然，...&nbsp;&nbsp;<a href='http://www.cppblog.com/mzty/archive/2007/12/04/37778.html'>阅读全文</a><img src ="http://www.cppblog.com/mzty/aggbug/37778.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2007-12-04 13:27 <a href="http://www.cppblog.com/mzty/archive/2007/12/04/37778.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏引擎基础（七）（网络和连线游戏环境）</title><link>http://www.cppblog.com/mzty/archive/2007/12/04/37777.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Tue, 04 Dec 2007 05:24:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2007/12/04/37777.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/37777.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2007/12/04/37777.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/37777.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/37777.html</trackback:ping><description><![CDATA[<span>第</span><span>7</span><span>部份</span><span>: </span><span>网络和连线游戏环境</span><span><br><br><br></span><strong><span>网络游戏</span></strong><span><br></span><span>　　我记得一些年前坐在</span><span>GDC</span><span>（游戏开发者大会）听负责开发</span><span>X-Wing Vs TIE Fighter</span><span>的家伙们题为</span><span>&#8220;</span><span>淹没在</span><span>Internet&#8221; </span><span>的演讲，全是关于让网络游戏实时地在</span><span>Internet</span><span>上工作的东西。他们选择那个题目是多么的正确啊。当它开始处理数据包的丢失，乱序，潜伏（一个数据包发送到它的目的地所花的时间）等等时，它确实淹没了。然而它是可能的。对于</span><span>Internet</span><span>需要一些聪明和经验，但它是肯定可能的。看看今天大量的连线游戏，从</span><span>Quake III</span><span>，</span><span>Unreal Tournament</span><span>，</span><span>Counter Strike</span><span>一直到</span><span>EverQuest</span><span>和</span><span>Ultima Online</span><span>。</span><span> <br><br></span><span>　　如今大多数真正有长久生命力的游戏都至少有一些连线成分。最纯粹的单人游戏容易玩一次，也许两次，或者甚至三次如果它是非常好的游戏，但一旦游戏结束，就被束之高阁了。如果你想要有任何长久生命力，那么多人连线游戏就是形势的核心所在，并且那意味着和</span><span>Internet</span><span>打交道，为编码者打开了那个潘多拉的盒子。</span><span> <br><br></span><span>　　那么跟</span><span>Internet</span><span>打交道包括些什么呢？首先是要理解</span><span>Internet</span><span>是怎么工作的，和点对点与客户机</span><span>/</span><span>服务器体系结构的快速讨论。点对点就是你在两台机器上运行游戏，并简单地在它们之间共享输入。每个单独的游戏假定它是正确的，并仅仅在它一幀接一幀的刷新中合并来自另外一台机器的输入。客户机</span><span>/</span><span>服务器是一台机器有效地运行游戏，别的机器仅仅是一个终端，接受来自玩家的输入，并渲染服务器让它渲染的任何东西。</span><span> <br><br></span><span>　　客户机</span><span>/</span><span>服务器的优点是每台机器都将会展现相同的游戏，因为所有的处理都在一个地方完成，没有跨越多台机器，你可以不用考虑每台机器相互之间的同步问题。不足之处是，服务器本身需要有一些重要的</span><span>CPU</span><span>可用时间来处理每一个连接的客户机，和一个合适的网络连接来确保每一个客户机及时地接收到它的更新。</span><span><br><br><br></span><strong><span>了解</span></strong><strong><span>IP</span></strong><span><br></span><span>　　我们都已经听说过</span><span>TCP/IP</span><span>（传输控制协议</span><span>/</span><span>网间协议）和</span><span>UDP</span><span>（用户数据包协议），</span><span> </span><span>在</span><span>Web</span><span>网络上有大量关于这些协议的深奥的技术资讯。实际上，在</span><span>Cisco</span><span>网站上有一些极好的</span><span>TCP/IP</span><span>指导。我们将在较高层面上介绍一些</span><span>TCP/IP</span><span>的基本知识，目的是让你更好地了解使用这些标准协议的网络游戏设计者面临的挑战。</span><span> <br><br></span><span>　　</span><span>TCP/IP</span><span>和</span><span>UDP/IP</span><span>是两层的通信协议系统。</span><span>IP</span><span>层负责网际数据包的传输。</span><span>UDP</span><span>或者</span><span>TCP</span><span>层将大的数据包传给</span><span>IP</span><span>，</span><span>IP</span><span>将数据包分割为小的子数据包，为每个数据包加上一个信封，计算出目的地的</span><span>IP</span><span>地址，应该如何到达那里，然后将数据包发送到你的</span><span>ISP</span><span>，或者不管怎样你连接到网络。</span><span> </span><span>这实在象是在一张明信片上写下你要发送的，贴上邮票，写上地址，塞进一个邮箱，它就送走了。</span><span> <br><br></span><span>　　</span><span>UDP</span><span>和</span><span>TCP</span><span>是从你编码者或者游戏接收数据包的高层协议，并决定该如何处理这些数据包。</span><span>UDP</span><span>和</span><span>TCP</span><span>的区别在于</span><span>TCP</span><span>保证数据包的传送和有序，而</span><span>UDP</span><span>不保证。</span><span>UDP</span><span>是一条直接和</span><span>IP</span><span>对话的小路，而</span><span>TCP</span><span>是在你和</span><span>IP</span><span>之间的一个接口。它像是在你和你的邮件之间有一个管理员助手。使用</span><span>UDP</span><span>你会自己为你的信打字，把它们放进一个信封等等。使用</span><span>TCP</span><span>你会仅仅向你的管理员口授信稿，管理员会做全部的工作并追踪确认信件送到了。</span><span> <br><br></span><span>　　然而，所有这些令人惊奇的为你完成的工作伴随着代价。为了确定数据包通过</span><span>Internet</span><span>完好无损地送到了目的方，</span><span>TCP</span><span>期待从目的方为它发送的每个数据包发回一个应答包（网络用语是</span><span>ACK</span><span>）。如果它在一定时间内没有收到</span><span>ACK</span><span>，它就停止发送任何新的数据包，重新发送丢失的数据包，并且将继续这样做直到收到目的方的回应。当你访问一个网页时，我们都已经看到了这种情形，在半途中下载停止了一会然后又重新开始了。可能是一个数据包在什么地方丢失了（假定不时</span><span>ISP</span><span>的问题），在任何更多的数据包被发送以前</span><span>TCP</span><span>要求重新发送它。</span><span> <br><br></span><span>　　这一切的问题是，在认识到出了差错的发送者和实际上正在送达的数据包之间出现了延迟。有时这能花上数秒钟，如果你仅仅只是下载一个文件或一个网页，这不是什么大碍，但如果这是一个游戏数据包而且每秒至少有十次，那么你真的是遇到麻烦了，尤其是因为它停止了其他一切事情。实际上就是这个问题所以几乎没有游戏选择使用</span><span>TCP</span><span>作为它们主要的</span><span>Internet</span><span>协议，除非它不是一个实时动作游戏。大多数游戏使用</span><span> UDP--</span><span>他们不能保证有序或可靠送达，但它确实很快</span><span>—</span><span>或者结果是至少通常比</span><span>TCP/IP</span><span>更快。现在我们了解这些了，接下来呢？</span><span><br><br><br></span><strong><span>客户端预测</span></strong><span><br></span><span>　　因为</span><span> UDP </span><span>明显的是快速响应游戏的方式，我们将必须自己处理数据包的丢失和乱序。边而且这是技巧所在。不用说出太多的代码秘密，我就能说有方法。作为开始，有客户端预言，一个被谈论得相当多的词语。当你作为一个客户端连接到一个大的服务器，但是不能连贯地看见来自服务器的更新，客户端预言开始起作用了。正在你的电脑上运行的游戏部分看着你正给它的输入，并在缺乏来自服务器的任何弃绝信息的情况下，对它认为将继续进行的事情作出</span><span>&#8216;</span><span>最好的猜测</span><span>&#8217;</span><span>。它将会显示被猜测的数据，然后当它得到来自服务器的世界的最新状态时，改正它自己，如果需要。你可能会对这个方法的效力感到惊讶。大体而言，大部分时间数据包不容易丢失</span><span>—</span><span>大多数时候是一秒的几十分之一，这种情况下游戏没有太多的时间偏离服务器实际上认为正在发生的事情。偏离确实会随着时间变的比较大，大多数游戏里面有一个超时功能，当出现很长时间没有来自服务器的联络时就停止游戏。</span><span> <br><br></span><span>　　你正在创造的游戏类型在这里有关系</span><span> -- </span><span>第一人称射击游戏不需要这样有效的客户端预言，因为它多数情况下仅仅处理</span><span>&#8220;</span><span>我在哪儿，我是否要射击？</span><span>&#8221;</span><span>。在第三人称游戏中，你必须更加精确，因此你能够正确地预测你的角色正在播放的动画，并且动作流畅。在这种情形中流畅的动画是完全必要的。</span><span>Heretic II</span><span>在这方面有很大的问题，并且是当它开始网络编码时</span><span>Raven</span><span>一直不得不处理的最困难的事情之一。</span><span> <br><br></span><span>　　当然如果你有一个很不错的网络连接，比如宽带连接，那么这个问题就远没有那么重要。对比较大的数据包有一个更宽的管道，对你的网络连通时间更快速。事实上，宽带对于游戏的主要优点不比较胖的管道多，但大大减少了延迟，特别是你到</span><span>ISP</span><span>的第一跳上。对于</span><span>56K </span><span>调制解调器，第一跳典型的延迟是</span><span>100ms</span><span>，这已经严重地增加了你到网络上任意一台游戏服务器的潜在连通时间。对于宽带连接比如像</span><span>DSL</span><span>，第一跳的延迟时间多半是</span><span>20ms</span><span>。使用</span><span>Windows</span><span>中一个叫做</span><span>TraceRoute</span><span>（</span><span>TRACERT.EXE</span><span>）的命令行程序并指定一个目标</span><span>IP</span><span>地址或者域名，你能够找出你的第一跳的连通时间。仔细观察第一跳，因为这几乎总是你到你的</span><span>ISP</span><span>的网络连通时间。并且观察你在你的</span><span>ISP</span><span>的网络内部用了多少跳直到你看见在一个给定跳上列出的一个不同的域名。</span><span> <br><br></span><span>　　请注意，宽带并不总是能解决延迟问题。你仍然受最慢的路由器</span><span>/</span><span>服务器和数据包从服务器穿越网络到达你的跳数（反之亦然）的支配。有一个宽带连接确实容易缓和这些，但不可能它们最后就消失了。当然，如果你打算要运行某种服务器，你将会需要一个具有足够快速的向上游的数据速率的带宽，因为仅仅一个调制解调器不能够处理一个服务器产生的负荷。</span><span> <br><br></span><span>　　值得一提的是，如果你想要在</span><span>PS2</span><span>或者</span><span>Xbox</span><span>上面玩网络游戏，你将需要一个宽带连接，因为它们两者都不支持调制解调器。</span><span><br><br><br></span><strong><span>包大小，智能数据传输，和反作弊</span></strong><span><br></span><span>　　别的必须被处理的事情是数据包的大小。如果你在一个游戏里面</span><span>64</span><span>个人都在跑来跑去相互攻击，从一台机器发送到另外一台机器的数据包能变得相当大，达到了一些调制解调器没有带宽处理这些数据的程度。这正在变得特别和那些有着很大的地表系统的游戏有关。这里增加的问题是，因为你有这个很好的地表系统，你能够看得很远，因此能够看见许多其他游戏玩家，使得你为了精确渲染所需要的来自服务器的数据数量以很快的速率增长。我们能做什么呢？</span><span> <br><br></span><span>　　好吧，首先必要的是只发送绝对必须的东西给任何给定的客户端，因此他仅仅得到从他的角度观察游戏所需要的东西。发送在他视野以外的人们的数据没有一点意义</span><span>—</span><span>他将看不见这些。同时，你最好确保只发送那些每幀之间实际上发生改变的数据。如果一个家伙仍然在播放相同的动画，重新发送数据没有意义。当然，如果数据包丢失时这确实带来一些问题，但这就是为什么好的网络程序员被支付很多金钱，来处理类似这样的东西。</span><span> <br><br></span><span>　　还有一些其他的事情也要处理。最近已经有大量的令人苦恼的连线作弊正在发生。这是某些人修改游戏以给他们不正当利益的地方。尽管严格意义上这不是网络的一部分，但它确实发生了。有时人们会创作一些模块，允许他们立即瞄准进入视野的任何人，或者简单地允许他们看穿墙壁，或者让其他游戏玩家看不见他们自己。大部份时间这些事情可以在网络层内部或者在服务器上被处理。任何有</span><span>100%</span><span>命中率的人被简单地踢出游戏，因为在人力所及的范围内那是不可能的。</span><span><br><br></span><span>　　游戏开发者必须尽一切可能制止作弊行为，但很不幸，人做的东西可以被人突破。所有你能做的就是让作弊变得困难，当确实发生时去尝试发现它。</span><span> <br><br></span><span>　　好吧，现在就到这里了。在第</span><span>8</span><span>部分中，我们将会看看游戏脚本系统的趣味世界，根据游戏过程中出现的事件来渲染或使能预先定义的场景和行为，协助故事叙述。</span><span><br><br></span><img src ="http://www.cppblog.com/mzty/aggbug/37777.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2007-12-04 13:24 <a href="http://www.cppblog.com/mzty/archive/2007/12/04/37777.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏引擎基础（六）（声音系统，音频APIs）</title><link>http://www.cppblog.com/mzty/archive/2007/12/04/37776.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Tue, 04 Dec 2007 05:20:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2007/12/04/37776.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/37776.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2007/12/04/37776.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/37776.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/37776.html</trackback:ping><description><![CDATA[<span>第</span><span>6</span><span>部分</span><span>: </span><span>声音系统，音频</span><span>APIs<br><br><br></span><strong><span>声音系统</span></strong><span><br></span><span>　　由于人们玩的游戏在种类和技术上的进步，声音和音乐近几年来在游戏中正逐渐变得重要起来（声音是一个实际游戏的可玩特点，比如在</span><span>Thief</span><span>和其它同类游戏中的听觉提示）。现在四声道环绕系统在游戏玩家的宝库中是负担得起的和平常的事。给定空间的声音，噪音的障碍和闭塞，和动态的音乐，如今许多游戏使用这些提高玩家情绪上的反应，更多的关注投入到这个领域就不足为奇了。</span><span><br><br></span><span>　　现在在</span><span>PC</span><span>竞技场中，游戏玩家实际上只有一种声音卡可以选择</span><span> -- PC</span><span>声卡制造商创新公司（</span><span>Creative Labs</span><span>）的</span><span>Sound Blaster Live</span><span>！</span><span> </span><span>从旧的时间个人计算机声音卡片制造业者有创造力的中心</span><span>. </span><span>多年来创新公司已经为</span><span>DirectX</span><span>提供了他们的</span><span>EAX</span><span>声音扩展，并且他们是发起新的</span><span>OpenAL</span><span>（开放音频库</span><span>Open Audio Library</span><span>）的创立者。就如同</span><span>OpenGL</span><span>是一个图形</span><span>API</span><span>一样，</span><span>OpenAL</span><span>，像它起来听一样，是一个声音系统的</span><span>API</span><span>。</span><span>OpenAL </span><span>被设计为支持大多数通常声卡的许多特征，而且在一个特定的硬件特征不可得时提供一个软件替代。</span><span><br><br></span><span>　　为了更好的定义</span><span> OpenAL</span><span>，我向创新公司的</span><span>Garin Hiebert</span><span>询问了其定义</span><span>: <br><br></span><span>　　</span><span>"</span><span>这里借用我们的</span><span> <span>" OpenAL </span></span><span>规格和叁考</span><span>" </span><span>的一个定义</span><span>: <br><br></span><span>　　</span><span>OpenAL </span><span>是对音频硬件的一个软件接口</span><span>,</span><span>给程序员提供一个产生高质量多通道输出的能力。</span><span>OpenAL </span><span>是在模拟的三维环境里产生声音的一种重要方法。它想要跨平台并容易使用，在风格和规范上与</span><span>OpenGL</span><span>相似。任何已经熟悉</span><span>OpenGL</span><span>的程序员将发现</span><span>OpenAL</span><span>非常熟悉。</span><span> <br><br></span><span>　　</span><span>OpenAL API</span><span>能容易地被扩展适应插件技术</span><span>.</span><span>创新公司已经把</span><span>EAX</span><span>支持加入到这套</span><span>API</span><span>了，程序员可以用来给他们的声音环境增加复杂的反响，比赛和障碍效果。</span><span><br><br></span><span>　　如同</span><span>Jedi Knight II: Outcast </span><span>一样，连同</span><span>Eagle </span><span>世界</span><span>/</span><span>声音特征编辑器</span><span>,Soldier of Fortune II </span><span>以这个新系统为特征。什么是</span><span>Eagle</span><span>？</span><span> </span><span>在介绍这个以前，让我们讨论一些其他的系统，并定义一些声音术语。</span><span> <br><br><br></span><span>　　另外的一个系统是</span><span>Miles</span><span>声音系统。</span><span>Miles</span><span>是一家公司，它为你的代码生产插件，在充分利用每块声卡时处理所有必须的到特定声音卡的说话（比如</span><span>Sound Blaster Live</span><span>！系列，或者老的</span><span>A3D</span><span>声卡）。它非常像一个</span><span>API</span><span>前端，捆绑了一些额外的特征在里面。</span><span> </span><span>在其他事物当中</span><span>Miles</span><span>让你存取一些事物像</span><span>MP3</span><span>解压缩。</span><span> </span><span>它是很好的解决方案，但像任何事一样，它花费金钱并是你的代码和硬件之间的额外一层。虽然对於快速的声音系统制造，它非常有用，而且他们有段时间了，因此他们的确精通自己的业务。</span><span><br><br><br></span><strong><span>声音术语</span></strong><span><br></span><span>　　让我们开始障碍和闭塞。它们听起来一样，但不是这样。闭塞基本上意谓着一个声音在播放时听者在他们之间有一些闭合的障碍物。</span><span> <br><br></span><span>　　比如说，在</span><span>NOLF2</span><span>的一个屏幕镜头上你听到房子里面坏蛋的声音。你能听到他们，但是他们的声音相当低沉而沙哑。障碍是相似的，但是你和声音之间的障碍物并不是闭合的。一个好的例子就是在你和声源之间有一根柱子。由于房间中的回声你仍然听得到这个声音，但是它和声音直接传递到你的耳朵里是不同的。当然这确实依赖于知道在你的耳朵和声源之间的直线上是什么。而且根据房间的大小，声源到你的距离等等，需要的处理能变得相当耗时。后面我们将会谈到跟踪</span><span>--</span><span>足可以说它时常是比较慢的幀速率的原因。</span><span>Quake III </span><span>里面的</span><span>A3D </span><span>代码做了这些事情，关闭这些选项通常能够提高幀速率。</span><span>Tribe 2 </span><span>是这种弊病的另外一个受害者。关闭</span><span>3D</span><span>声音选项则你的幀速率立即好转，这在你考虑</span><span>Tribes</span><span>世界有多大和你能看见多远时有意义。</span><span> <br><br></span><span>　　接着是声音物质的特征。大部分声卡可以让你能够用可定义的过滤器作用于声音从而修正播放的声音。例如，在水下，或者在一个布料遮盖的房间中，或者在一个长的走廊中，或者在歌剧院，听到的声音有着很大的不同。能够根据你所处的环境改变你听到声音的方式是相当不错的。</span><span> <br><br></span><span>　　我们回到</span><span>Eagle&#8230; </span><span>这是一个编辑器，允许多数第一人称射击游戏地图设计者将他们的地图导入到这个工具，然后构造简化的几何形体来为实际游戏引擎中的</span><span>EAX</span><span>代码产生一个声音地图。其思想是你不需要一个真实的图形地图的复杂几何形体来模拟声音环境。你也能够给产生的简化地图分配声音物质，这样声音环境就能够动态地改变。我亲眼目睹了这在</span><span>Soldier of Fortune</span><span>和</span><span>Unreal Tournament</span><span>上的示范，确实相当引人注目。</span><span> </span><span>我这在财富和</span><span> Unreal </span><span>巡回赛和它的军人上真的对示范是证人相当醒目</span><span>. </span><span>当你跳入水中时，听到所有的声音改变，这是一个非常令人沉浸的经历。</span><span> <br><br></span><span>　　好，让我们继续吧。</span><span> <br><br></span><span>　　对于游戏机，由于静态的硬件，你的各种可能性会更受限制</span><span> — </span><span>尽管在</span><span>PlayStation 2</span><span>和</span><span>Xbox</span><span>上，硬件相当不错。我说的限制，仅仅是指扩展，而不是它所能够做的。我一点也不会感到惊讶看到这些游戏机上的游戏很快支持杜比数字</span><span>5.1</span><span>（</span><span>Dolby Digital 5.1</span><span>）输出。</span><span>Xbox </span><span>，由于它的</span><span> MCP </span><span>音频处理器，能够将任何游戏音频编码为</span><span>5.1</span><span>，并且游戏不需要特别编码就能利用这个特征。杜比（</span><span>Dolby</span><span>）把</span><span>ProLogic II </span><span>带到了</span><span> PS2 </span><span>上，并与</span><span>Factor 5</span><span>合作为</span><span>GameCube</span><span>游戏实现了</span><span>ProLogic II</span><span>。在</span><span> Xbox </span><span>之上，</span><span>Halo, Madden 2002 </span><span>和</span><span> Project Gotham Racing</span><span>等游戏都有</span><span>5.1</span><span>杜比数字音频内容。</span><span>DTS</span><span>最近也为</span><span> PS2 </span><span>游戏开发者发布了</span><span>SDK</span><span>，为这个平台上的游戏带来了降低了比特率的</span><span>DTS</span><span>音频版本。</span><span><br><br><br></span><strong><span>位置的声音</span></strong><strong><span>--</span></strong><strong><span>一个复杂的世界</span></strong><span><br></span><span>　　现在有一些很少有处理的声音空间化问题。我说的是把声音放在一个真实的</span><span>3D</span><span>世界中。有四个扬声器在你周围是一个很棒的开始，但这仍然只是在二维方向。在你的上方和下方没有扬声器，你没有真正获得</span><span>3D</span><span>声音。有一些声音调制过滤器试图解决这个问题，但实际上没有真实东西的代替物。当然真实地大多数游戏多半只是在二维方向上，因此这仍然不是太大的问题。</span><span> <br><br></span><span>　　实际上任何声音系统最重要的特征之一是把声音混合在一起。根据你所处的位置，空间中声音的位置，每个声音的音量大小，一旦你决定了实际上你能够听到的声音，然后你必须混合这些声音。通常声音卡自己处理这些，这首先是声音卡存在的主要原因。然而，外面有一些引擎决定首先用软件做一次</span><span>&#8216;</span><span>预混合</span><span>&#8217;</span><span>。直到你着眼于一点点历史以前，这并没有真正地带来多大的意义。</span><span><br><br></span><span>　　当声音卡最初问世的时候，有许多不同的混合方法。一些声卡可以混合</span><span>8</span><span>种声音，一些单位</span><span>16</span><span>种，一些</span><span>32</span><span>种，等等。</span><span> </span><span>如果你总想听到</span><span>16</span><span>种可能的声音，但你不知道声音卡是否能够处理，那么你回到了尝试和试验的道路上</span><span> <span>— </span></span><span>就是你自己用软件混合。这实际上是</span><span>Quake III</span><span>声音系统的工作方式，但提一个问题</span><span>:"Quake III</span><span>是为</span><span>A3D</span><span>和</span><span>Sound Blaster Live</span><span>！声卡世界发布的，这比以前更加标准化，为什么还这样做？</span><span>" </span><span>这是个好问题。实际上</span><span>Quake III</span><span>的声音系统几乎每行代码都和</span><span>Quake II</span><span>中的声音系统一样。而且</span><span>Quake I</span><span>，甚至</span><span>Doom</span><span>也是这样。你想一想，向上直到</span><span> A3D </span><span>声卡和</span><span> SB Live! </span><span>声卡，许多年来声音系统的需求没有真正地改变过。两个扬声器，二维方向，音量简单地随着距离减小。从</span><span>Doom</span><span>一直到</span><span>Quake III</span><span>没有发生太大变化。而且在游戏行业中，如果不是迫不得已，别理会它。</span><span><br><br></span><span>　　通常你会仅仅使用</span><span>DirectSound</span><span>为你做声音混合，因为它会可以使用的声音硬件，或者转而依靠软件，很多地方就像</span><span>DirectX</span><span>为</span><span>3D</span><span>显示卡所做的一样。在</span><span> 90% </span><span>的声音情形中，依靠软件混合对你的幀速率没有真正发生太多不同。当</span><span>DirectSound</span><span>在一些狂热的编码者眼中甚至还不是一丝光线时，</span><span>Doom</span><span>引擎就已经产生了。它从来没有得到更新过，因为它从来就没有真的需要更新。</span><span> <br><br></span><span>　　当然，你可以使用</span><span> SoundBlaster Live</span><span>！声卡的一些聪明特征，例如房间的回声特性</span><span>: </span><span>一块石窟，或一个礼堂，一个巨穴</span><span>, </span><span>一个足球体育馆等。而且你真的应该使用由硬件提供的混合器，毕竟，那是它存在的目的。这种方法的一个不足之处是程序本身时常无法获得混合结果，因为混合是在声卡内部完成而不是在主存。如果由于某种原因你需要看到产生的音量，你是运气不好。</span><span><br><br><br><strong><span>Music Tracks in Games</span></strong></span><strong><span>（游戏中的音轨）</span></strong><span><br></span><span>　　我们没有过多的谈到游戏中的音乐生成。传统的有两种方法，一种是简单的音乐</span><span> .wav </span><span>文件</span><span>(</span><span>或同等物</span><span>)</span><span>。它被预先制作做好，准备运行，和最小忙乱。然而，这些在内存和回放时间方面很昂贵。第二种方式用预设的样本编码</span><span>MIDI</span><span>音轨。这时常比较节省内存，但缺点是必须同时把一些声音混合在一起，因而会把声音通道用光。</span><span> <br><br></span><span>　　动态音乐就是根据在游戏中目睹的行动改变你的音乐的能力，比如探险用慢节奏的音乐，战斗用快节奏的音乐。预先制作的音乐的一个困难之处是要合拍，因此你可以从一段音乐渐弱到另一段音乐，这对于</span><span>MIDI</span><span>音轨比较容易。尽管时常你足够快速地淡出，或者一段音乐在播放另一段音乐之前已经消失了，你能侥幸不被察觉。</span><span><br><br></span><span>　　在我们离开这个主题之前，顺便说一下，值得一提的是存在一些公司专门为你的游戏创作特定意义的音乐。</span><span>FatMan(<a href="http://www.fatman.com/" target=_blank><span>www.fatman.com</span></a>) </span><span>就是一家这样的公司。音乐可能比其他别的东西更加容易外包，这是他们存在的方式。</span><span> <br><br></span><span>　　最后，游戏现在的事情自然是</span><span>MP3</span><span>格式，允许巨大的</span><span>11 </span><span>：</span><span>1</span><span>的声音样本压缩，然而在送到声音卡之前只花费</span><span>CPU</span><span>很少的时间解压缩。当我在</span><span>Rave Software</span><span>工作时，在</span><span>Star Trek Voyager: Elite Force </span><span>中，我们设法用</span><span>MP3</span><span>在一张</span><span>CD</span><span>上面完全支持三种语言，仍然为较多的图形留有空间。主要地，我们</span><span> MP3 </span><span>只用于非玩家角色（</span><span>NPC</span><span>）的语音，由于游戏的全部音频效果</span><span>MP3</span><span>流和动态解压缩超出了硬件的处理能力，虽然在将来这是肯定可能的。比较新的格式，如来自</span><span> Dolby </span><span>的</span><span> AAC </span><span>和来自微软的</span><span>WMA</span><span>，以将近两倍</span><span>MP3</span><span>的压缩率提供了相等或者更高的音频质量（实际上一半的比特率），可能应用到将来的游戏中。</span><span> <br><br></span><span>　　以上是这一章节的内容，下面将是网络和连线游戏环境的开发。</span><span> <br><br></span><img src ="http://www.cppblog.com/mzty/aggbug/37776.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2007-12-04 13:20 <a href="http://www.cppblog.com/mzty/archive/2007/12/04/37776.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏引擎基础（四）（模型与动画，细节级别）</title><link>http://www.cppblog.com/mzty/archive/2007/12/04/37770.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Tue, 04 Dec 2007 05:18:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2007/12/04/37770.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/37770.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2007/12/04/37770.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/37770.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/37770.html</trackback:ping><description><![CDATA[<span>第</span><span>4</span><span>部份</span><span>: </span><span>模型与动画，细节级别</span><span><br><br><br></span><strong><span>角色建模与动画</span></strong><span><br></span><span>　　你的角色模型在屏幕上看起来怎么样</span><span>,</span><span>怎样容易创建它们</span><span>,</span><span>纹理</span><span>,</span><span>以及动画对于现代游戏试图完成的</span><span>`</span><span>消除不可信</span><span>`</span><span>因素来说至关重要。角色模型系统逐渐变得复杂起来</span><span>, </span><span>包括较高的多边形数量模型</span><span>, </span><span>和让模型在屏幕上移动的更好方式。</span><span><br><br></span><span>　　如今你需要一个骨骼模型系统，有骨架和网格细节层次，单个顶点骨架的评估，骨架动画忽略，以及比赛中停留的角度忽略。而这些甚至还没有开始涉及一些你能做的很好的事情，像动画混合，骨架反向运动学（</span><span>IK</span><span>），和单个骨架限制，以及相片真实感的纹理。这个清单还能够继续列下去。但是真的，在用专业行话说了所有这些以后，我们在这里真正谈论的是什么呢？让我们看看。</span><span> <br><br></span><span>　　让我们定义一个基于网格的系统和一个骨骼动画系统作为开始。在基于网格的系统，对于每一个动画幀，你要定义模型网格的每个点在世界中的位置。举例来说，你有一个包含</span><span>200 </span><span>个多边形的手的模型，有</span><span> 300 </span><span>个顶点</span><span>(</span><span>注意，在顶点和多边形之间通常并不是</span><span>3</span><span>个对</span><span>1</span><span>个的关系，因为大量多边形时常共享顶点</span><span> &#8211; </span><span>使用条形和扇形，你能大幅减少顶点数量</span><span>)</span><span>。如果动画有</span><span> 10 </span><span>幀，那么你就需要在内存中有</span><span>300</span><span>个顶点位置的数据。</span><span> </span><span>总共有</span><span>300 x 10 = 3000 </span><span>顶点，每个顶点由</span><span>x</span><span>，</span><span>y</span><span>，</span><span>z</span><span>和颜色</span><span>/alpha</span><span>信息组成。你能看见这个增长起来是多么的快。</span><span>Quake I</span><span>，</span><span>II</span><span>和</span><span> III </span><span>都使用了这种系统，这种系统确实有动态变形网格的能力，比如使裙子摆动，或者让头发飘动。</span><span><br><br></span><span>　　相比之下，在骨骼动画系统，网格是由骨架组成的骨骼</span><span>( </span><span>骨架是你运动的对象</span><span>)</span><span>。</span><span> </span><span>网格顶点和骨架本身相关，所以它们在模型中的位置都是相对于骨架，而不是网格代表每个顶点在世界中的位置。因此，如果你移动骨架，组成多边形的顶点的位置也相应改变。这意谓着你只必须使骨骼运动，典型情况大约有</span><span> 50 </span><span>个左右的骨架</span><span>—</span><span>很明显极大地节省了内存。</span><span><br><br><br></span><strong><span>骨骼动画附加的好处</span></strong><span><br></span><span>　　骨骼动画的另一个优点是能够根据影响顶点的一些骨架来分别</span><span>&#8220;</span><span>估价</span><span>&#8221; </span><span>每个顶点。例如，双臂的骨架运动，肩，脖子而且甚至躯干都能在肩中影响网格。当你移动躯干的时候，网格就活像一个角色一样移动。总的效果是</span><span>3D</span><span>角色能够实现的动画更加流畅和可信，且需要更少的内存。每个人都赢了。</span><span> <br><br></span><span>　　当然这里的缺点是，如果你想要使有机的东西运动且很好，比如说头发，或者披肩，为了让它看起来自然，你最后不得不在里面放置数量惊人的骨架，这会抬高一些处理时间。</span><span> <br><br></span><span>　　基于骨骼的系统能带给你的一些其他事情是</span><span>&#8216;</span><span>忽略</span><span>&#8217;</span><span>特定层次骨架的能力</span><span> -- </span><span>说</span><span>,"</span><span>我不关心动画想要对这块骨架所做的事情，我想要让它指向世界中的一个特定点</span><span>"</span><span>。这很棒。你能让模型着眼于世界中的事件，或者使他们的脚在他们站着的地面保持水平。这一切非常微妙，但它可以帮助带给场景附加的真实感。</span><span><br><br></span><span>　　在骨骼系统，你甚至可以指定</span><span>"</span><span>我需要把这个特别的动画用於模型的腿，而一个不同的携枪或射击动画在模型躯干上播放，且那家伙（角色）叫喊的不同动画效果在模型的头部播放</span><span>"</span><span>。非常妙。</span><span>Ghoul2 ( </span><span>在</span><span>Soldier of Fortune II: Double Helix and Jedi Knight I: Outcast</span><span>中使用了</span><span>Raven</span><span>的动画系统</span><span> ) </span><span>拥有所有这些好东西，且特别被设计为允许程序员使用所有这些忽略能力。这对动画的节省像你一样难以相信。像你一样的动画上的这次救援不相信</span><span>. Raven</span><span>有一个角色行走的动画和一个站立开火的动画，并在它同时行走和开火形下把这两个动画合并，而不是需要一个动画表示角色行走并开火。</span><span><br><br><br><strong><span>More Skeletons in the Closet</span></strong><br></span><span>　　先前描述的效果可以通过具有层次的骨骼系统来完成。这是什么意思呢？意思是每块骨架实际上的位置相对于它的父亲，而不是每个骨架直接位于空间中的地方。这意谓着如果你移动父亲骨架，那么它所有的子孙骨架也跟着移动，在代码上不需要任何额外的努力。这是让你能够在任何骨架层次改变动画，而且通过骨骼其余部分向下传递的东西。</span><span> <br><br></span><span>　　创建一个没有层次的骨骼系统是可能的</span><span> -- </span><span>但那时你不能忽略一个骨架并且预期它工作。你所看到的只是身体上的一个骨架开始了新动画，除非你实现了某种</span><span>&#8216;</span><span>向下传递信息</span><span>&#8217;</span><span>的系统，否则在该骨架下面的其它骨架保持原来的动画。首先由一个层次系统开始，你就自动地获得这些效果。</span><span> <br><br></span><span>　　许多今天的动画系统中正开始出现一些比较新的特征，如动画混合，从一个正在播放的动画转变到另外一个动画需要经过一小段时间，而不是立即从一个动画突然转变到另外一个。举例来说，你有个角色在行走，然后他停了下来。你不是仅仅突然地转变动画，让他的腿和脚停在无效位置，而是一秒钟混合一半，这样脚似乎自然地移到了新的动画。不能够过高的评价这种效果</span><span> -- </span><span>混合是一个微妙的事情</span><span>,</span><span>但如果正确的运用，它真的有些差别。</span><span><br><br><br></span><strong><span>反向运动学</span></strong><span><br></span><span>　　反向运动学</span><span> (IK) </span><span>是被许多人们丢弃的一个专业术语，对它的真实含义没有多少概念。</span><span>IK </span><span>是如今游戏里面一个相对比较新的系统。使用</span><span> IK </span><span>，程序员能够移动一只手，或一条腿</span><span>, </span><span>模型的其余关节自动重新定位，因此模型被正确定向。而且有模型的关节新位置的其馀者他们自己，因此模型正确的被定向。比如，你将会说</span><span>,"</span><span>好，手</span><span> , </span><span>去拾起桌子上的那个杯子</span><span>"</span><span>并指出杯子在世界中的位置。手就会移动到那里，且它后面的身体会调节其自身以便双臂移动，身体适当弯曲，等等。</span><span><br><br></span><span>　　也有和</span><span>IK</span><span>相反的事情，叫做前向运动学</span><span>,</span><span>本质上与</span><span> IK </span><span>工作的次序相反。想像一只手，手附着在手臂上，手臂附着在身体上。现在想像你重重地击中了身体。通常手臂像连迦般抽动，且手臂末梢的手随之振动。</span><span> IK </span><span>能够移动身体，并让其余的四肢自己以真实的方式移动。基本上它需要动画师设定每种工作的大量信息</span><span> -- </span><span>像关节所能通过的运动范围，如果一块骨架前面的骨架移动，那么这块骨架将移动多少百分比，等等。</span><span><br><br></span><span>　　和它现在一样，尽管很好，它是一个很大的处理问题，不用它你可以有不同的动画组合而脱身。值得注意的是，真正的</span><span> IK </span><span>解决办法需要一个层次骨骼系统而不是一个模型空间系统</span><span> -- </span><span>否则它们都耗时太多以致无法恰当地计算每个骨架。</span><span><br><br><br><strong><span>LOD</span></strong></span><strong><span>几何系统</span></strong><span><br></span><span>　　最后，我们应当快速讨论一下与缩放模型几何复杂度相关的细节级别（</span><span>LOD</span><span>）系统</span><span>(</span><span>与讨论</span><span>MIP</span><span>映射时使用的</span><span>LOD</span><span>相对照</span><span>)</span><span>。假定如今绝大多数</span><span>PC</span><span>游戏支持的处理器速度的巨大范围，以及你可能渲染的任何给定可视场景的动态性质</span><span>(</span><span>在屏幕上有一个角色还是</span><span>12</span><span>个？</span><span>)</span><span>，</span><span> </span><span>你通常需要一些系统来处理这样的情况，比如，当系统接近极限试图同时在屏幕上绘制出</span><span>12</span><span>个角色，每个角色有</span><span>3</span><span>，</span><span>000</span><span>个多边形</span><span>,</span><span>并维持现实的幀速率。</span><span> LOD </span><span>被设计来协助这样的情景中。最基本的情况，它是在任何给定时间动态地改变你在屏幕上绘制的角色的多边形数量的能力。面对现实吧，当一个角色走远，也许只有十个屏幕像素高度，你真的不需要</span><span>3000</span><span>个多边形来渲染这个角色</span><span> -- </span><span>或许</span><span>300</span><span>个就够了，而且你很难分辨出差别。</span><span> <br><br></span><span>　　一些</span><span> LOD </span><span>系统将会需要你建立模型的多个版本，而且他们将会依靠模型离观察者的接近程度来改变屏幕上的</span><span>LOD</span><span>级别，</span><span> </span><span>以及多少个多边形正被同时显示。更加复杂的系统实际上将会动态地减少屏幕上的多边形数量，在任何给定时间，任何给定的角色，动态地</span><span> -- Messiah</span><span>和</span><span>Sacrifice</span><span>包括了这种风格的技术，尽管在</span><span>CPU</span><span>方面并不便宜。你必须确信，与首先简单地渲染整个事物相比，你的</span><span> LOD </span><span>系统没有花较多的时间计算出要渲染那些多边形（或不渲染）。</span><span> </span><span>任一方式都将会工作，由于如今我们试图要在屏幕上绘制的多边形数量，这是件非常必要的事情。注意，</span><span> DX9 </span><span>将会支持硬件执行的自适应几何缩放</span><span>(tessellation)</span><span>。</span><span><br><br></span><span>　　归结起来是，得到一个运动流畅，其表现和移动在视觉上可信，屏幕上看起来逼真的模型。流畅的动画时常是通过手工建造动画和运动捕捉动画的组合得到。有时你仅仅手工建立了一个给定的动画</span><span> -- </span><span>当你在为一个模型做一些你在现实生活中不能做到的事情的动画时，</span><span> </span><span>你倾向于这样做</span><span> -- </span><span>举例来说，你确实不能向后弯腰，或像</span><span>Mortal Kombat 4</span><span>中的</span><span>Lui Kang</span><span>那样在行进的脚踏车上踢腿，通常运动捕捉这时候就出局了</span><span>! </span><span>通常运动捕捉动画</span><span> -- </span><span>实际上视频捕捉活生生的演员贯穿于你想在屏幕上所看到的动画</span><span> -- </span><span>是得到逼真的东西的方式。真实感的东西能使一款普通游戏看起来很棒，而且能掩饰许多事情。比如</span><span> NFL Blitz</span><span>，屏幕上的模型大约有</span><span> 200 </span><span>个多边形。它们在静止站立时看起来可怕的斑驳，一旦这些模型跑动起来它们就有快速流畅的动画，模型自身的许多丑陋消失了。眼睛容易看见的是</span><span> '</span><span>逼真的</span><span>' </span><span>动画而不是模型自身的结构。</span><span> </span><span>一个不错的模型设计师能够掩饰大多数模型缺陷。</span><span><br><br></span><span>　　我希望这些带给你对模型和动画问题的洞察力。在第五部份中，我们将会更加深入</span><span>3D</span><span>世界的建造，讨论一些物理，运动和效果系统的东西。</span><span><br><br></span><img src ="http://www.cppblog.com/mzty/aggbug/37770.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2007-12-04 13:18 <a href="http://www.cppblog.com/mzty/archive/2007/12/04/37770.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏引擎基础（三）（内存使用，特效和API）</title><link>http://www.cppblog.com/mzty/archive/2007/12/04/37769.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Tue, 04 Dec 2007 05:17:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2007/12/04/37769.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/37769.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2007/12/04/37769.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/37769.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/37769.html</trackback:ping><description><![CDATA[<span>第</span><span>3</span><span>部份</span><span>: </span><span>内存使用，特效和</span><span>API<br><br><br></span><strong><span>关于内存使用的思考</span></strong><span><br></span><span>　　让我们想一想，在今天实际上是如何使用</span><span>3D </span><span>显卡内存的以及在将来又会如何使用。</span><span> </span><span>如今绝大多数</span><span>3D</span><span>显卡处理</span><span>32</span><span>位像素颜色，</span><span>8</span><span>位红色，</span><span> 8</span><span>位蓝色，</span><span>8 </span><span>位绿色，和</span><span> 8 </span><span>位透明度。这些组合的红，蓝和绿</span><span>256</span><span>个色度，可以组成</span><span> 16</span><span>。</span><span>7 </span><span>百万种颜色</span><span>-- </span><span>那是你我可以在一个监视器上看见的所有颜色。</span><span> <br><br></span><span>　　那么，游戏设计大师</span><span>John Carmack </span><span>为什么要求</span><span> 64 </span><span>位颜色分辨率呢</span><span>? </span><span>如果我们看不出区别，又有什么意义呢</span><span>? </span><span>意义是</span><span>: </span><span>比如说，</span><span> </span><span>有十几个灯光照射模型上的点，颜色颜色各不相同。</span><span> </span><span>我们取模型的最初颜色，然后计算一个灯光的照射，模型颜色值将改变。</span><span> </span><span>然后我们计算另外的一个灯光，</span><span> </span><span>模型颜色值进一步改变。</span><span> </span><span>这里的问题是，因为颜色值只有</span><span>8</span><span>位，在计算了</span><span>4</span><span>个灯光之后，</span><span>8</span><span>位的颜色值将不足以给我们最后的颜色较好的分辨率和表现。分辨率的不足是由量化误差导致的，本质原因是由于位数不足引起的舍入误差。</span><span> <br><br></span><span>　　你能很快地用尽位数，而且同样地，所有的颜色被清掉。每颜色</span><span>16 </span><span>或</span><span> 32 </span><span>位，你有一个更高分辨率，因此你能够反复着色以适当地表现最后的颜色。这样的颜色深度很快就能消耗大量的存储空间。我们也应提到整个显卡内存与纹理内存。这里所要说的是，每个</span><span>3D </span><span>显卡实际只有有限的内存，而这些内存要存储前端和后端缓冲区，</span><span>Z </span><span>缓冲区，还有所有的令人惊奇的纹理。最初的</span><span> Voodoo1 </span><span>显卡只有</span><span>2MB</span><span>显存，后来</span><span> Riva TNT</span><span>提高到</span><span>16MB</span><span>显存。然后</span><span> GeForce </span><span>和</span><span> ATI Rage</span><span>有</span><span>32MB</span><span>显存，</span><span> </span><span>现在一些</span><span> GeForce 2 </span><span>到</span><span> 4</span><span>的显卡和</span><span> Radeons </span><span>带有</span><span> 64MB </span><span>到</span><span>128MB </span><span>的显存。</span><span> </span><span>这为什么重要</span><span>? </span><span>好吧，让我们看一些数字</span><span>&#8230;<br><br></span><span>　　比如你想让你的游戏看起来最好，所以你想要让它以</span><span>32</span><span>位屏幕，</span><span> 1280x1024</span><span>分辨率和</span><span>32</span><span>位</span><span> Z- </span><span>缓冲跑起来。</span><span> </span><span>好，屏幕上每个像素</span><span>4</span><span>个字节，外加每个像素</span><span>4</span><span>字节的</span><span>Z-</span><span>缓冲，因为都是每像素</span><span>32</span><span>位。我们有</span><span>1280x1024 </span><span>个像素</span><span> &#8211; </span><span>也就是</span><span> 1</span><span>，</span><span>310</span><span>，</span><span>720</span><span>个像素。基于前端缓冲区和</span><span>Z-</span><span>缓冲区的字节数，这个数字乘以</span><span>8</span><span>，是</span><span> 10</span><span>，</span><span>485</span><span>，</span><span>760</span><span>字节。包括一个后端缓冲区，这样是</span><span> 1280x1024x12</span><span>，</span><span> </span><span>也就是</span><span> 15</span><span>，</span><span>728</span><span>，</span><span>640 </span><span>字节，</span><span> </span><span>或</span><span> 15MB</span><span>。</span><span> </span><span>在一个</span><span> 16MB </span><span>显存的显卡上，就只给我们剩下</span><span>1MB </span><span>来存储所有的纹理。</span><span> </span><span>现在如果最初的纹理是真</span><span>32 </span><span>位或</span><span> 4</span><span>字节宽，那么我们每幀能在显卡上存储</span><span> 1MB/4</span><span>字节每像素</span><span> = 262</span><span>，</span><span>144</span><span>个像素。这大约是</span><span>4 </span><span>个</span><span> 256x256 </span><span>的纹理页面。</span><span> <br><br></span><span>　　很清楚，上述例子表明，旧的</span><span>16MB </span><span>显卡没有现代游戏表现其绚丽画面所需要的足够内存。很明显，在它绘制画面的时候，我们每幀都必须重新把纹理装载到显卡。实际上，设计</span><span>AGP</span><span>总线的目的就是完成这个任务，不过，</span><span> AGP </span><span>还是要比</span><span> 3D </span><span>掀卡的幀缓冲区慢，所以你会受到性能上的一些损失。很明显，如果纹理由</span><span>32</span><span>位降低到</span><span>16</span><span>位，你就能够通过</span><span>AGP</span><span>以较低的分辨率传送两倍数量的纹理。如果你的游戏以每个像素比较低的色彩分辨率跑，</span><span> </span><span>那么就可以有更多的显示内存用来保存常用的纹理</span><span> (</span><span>称为高速缓存纹理</span><span>) </span><span>。</span><span> </span><span>但实际上你永远不可能预知使用者将如何设置他们的系统。如果他们有一个在高分辨率和颜色深度跑的显卡，那么他们将会更可能那样设定他们的显卡。</span><span><br><br><br></span><strong><span>雾</span></strong><span><br></span><span>　　我们现在开始讲雾</span><span>,</span><span>它是某种视觉上的效果。如今绝大多数的引擎都能处理雾，</span><span> </span><span>因为雾非常方便地让远处的世界淡出视野，所以当模型和场景地理越过观察体后平面进入视觉范围内时，你就不会看见它们突然从远处跳出来了。</span><span> </span><span>也有一种称为体雾的技术。这种雾不是随物体离照相机的距离而定</span><span>,</span><span>它实际上是一个你能看见的真实对象，并且可以穿越它，从另外一侧出去</span><span> -- </span><span>当你在穿越对象的时候，视觉上雾的可见程度随着变化。想象一下穿过云团</span><span> -- </span><span>这是体雾的一个完美例子。体雾的一些好的实现例子是</span><span>Quake III</span><span>一些关卡中的红色雾，或新的</span><span>Rogue Squadron II </span><span>之</span><span> Lucas Arts</span><span>的</span><span> GameCube </span><span>版本。其中有一些是我曾经见过的最好的云</span><span>--</span><span>大约与你能看见的一样真实。</span><span><br><br></span><span>　　在我们讨论雾化的时候</span><span>,</span><span>可能是简短介绍一下</span><span> Alpha </span><span>测试和纹理</span><span>Alpha</span><span>混合的好时机。当渲染器往屏幕上画一个特定像素时，假定它已经通过</span><span> Z- </span><span>缓冲测试</span><span> (</span><span>在下面定义</span><span>)</span><span>，我们可能最后做一些</span><span>Alpha</span><span>测试。我们可能发现为了显示像素后面的某些东西，像素需要透明绘制。这意味着我们必须取得像素的已有值，和我们新的像素值进行混和，并把混合结果的像素值放回原处。这称为读</span><span>-</span><span>修改</span><span>-</span><span>写操作</span><span>,</span><span>远比正常的像素写操作费时。</span><span> <br><br></span><span>　　你可以用不同类型的混合，这些不同的效果被称为混合模式。直接</span><span>Alpha</span><span>混合只是把背景像素的一些百分比值加到新像素的相反百分比值上面。还有加法混合，将旧像素的一些百分比</span><span>,</span><span>和特定数量</span><span>(</span><span>而不是百分比</span><span>)</span><span>的新像素相加。</span><span> </span><span>这样效果会更加鲜明。</span><span> (Kyle's Lightsaber</span><span>在</span><span> Jedi Knight II </span><span>中的效果</span><span>)</span><span>。</span><span><br><br></span><span>　　每当厂商提供新的显卡时，我们可以得到硬件支持的更新更复杂的混合模式，从而制作出更多更眩目的效果。</span><span>GF3+4</span><span>和最近的</span><span>Radeon</span><span>显卡提供的像素操作，已经到了极限。</span><span><br><br><br></span><strong><span>模板阴影与深度测试</span></strong><span><br></span><span>　　用模板产生阴影效果，事情就变得复杂而昂贵了。这里不讨论太多细节（可以写成一篇单独的文章了），其思想是，从光源视角绘制模型视图，然后用这个把多边形纹理形状产生或投射到受影响的物体表面。</span><span> <br><br></span><span>　　实际上你是在视野中投射将会</span><span>&#8220;</span><span>落</span><span>&#8221;</span><span>在其他多边形上面的光体。最后你得到看似真实的光照，甚至带有视角在里面。因为要动态创建纹理，并对同一场景进行多遍绘制，所以这很昂贵。</span><span> <br><br></span><span>　　你能用众多不同方法产生阴影，情形时常是这样一来，渲染质量与产生效果所需要的渲染工作成比例。有所谓的硬阴影或软阴影之分，而后者较好，因为它们更加准确地模仿阴影通常在真实世界的行为。</span><span> </span><span>通常有一些被游戏开发者偏爱的</span><span>&#8220;</span><span>足够好</span><span>&#8221;</span><span>的方法。如要更多的了解阴影，请参考</span><span> <span>Dave Salvator</span></span><span>的</span><span> 3D </span><span>流水线一文。</span><span><br><br><br></span><strong><span>深度测试</span></strong><span><br></span><span>　　现在我们开始讨论深度测试，</span><span> </span><span>深度测试丢弃隐藏的像素，过度绘制开始起作用。过度绘制非常简单</span><span> &#8211; </span><span>在一幀中，你数次绘制一个像素位置。它以</span><span>3D</span><span>场景中</span><span>Z</span><span>（深度）方向上存在的元素数量为基础，也被称为深度复杂度。如果你常常太多的过度绘制，</span><span> -- </span><span>举例来说</span><span>, </span><span>符咒的眩目视觉特效，就象</span><span>Heretic II</span><span>，能让你的幀速率变得很糟糕。当屏幕上的一些人们彼此施放符咒时，</span><span>Heretic II</span><span>设计的一些最初效果造成的情形是，他们在一幀中对屏幕上每个相同的像素画了</span><span>40</span><span>次</span><span>! </span><span>不用说，这必须调整，尤其是软件渲染器，除了将游戏降低到象是滑雪表演外，它根本不能处理这样的负荷。深度测试是一种用来决定在相同的像素位置上哪些对象在其它对象前面的技术，这样我们就能够避免绘制那些隐藏的对象。</span><span> <br><br></span><span>　　看着场景并想想你所看不见的。</span><span> </span><span>换句话说，是什么在其他场景对象前面</span><span>,</span><span>或者隐藏了其他场景对象</span><span>? </span><span>是深度测试作出的这个决定。</span><span> <br><br></span><span>　　我将进一步解释深度深度如何帮助提高幀速率。想像一个很琐细的场景，大量的多边形</span><span> (</span><span>或像素</span><span>)</span><span>位于彼此的后面，在渲染器获得他们之间没有一个快速的方法丢弃他们。对非</span><span>Alpha</span><span>混合的多边形分类排序</span><span>( </span><span>在</span><span>Z- </span><span>方向上</span><span>)</span><span>，首先渲染离你最近的那些多边形，优先使用距离最近的像素填充屏幕。所以当你要渲染它们后面的像素（由</span><span>Z</span><span>或者深度测试决定）时，这些像素很快被丢弃，从而避免了混合步骤并节省了时间。如果你从后到前绘制，所有隐藏的对象将被完全绘制，然后又被其他对象完全重写覆盖。场景越复杂，这种情况就越糟糕，所以深度测试是个好东西。</span><span><br><br><br></span><strong><span>抗锯齿</span></strong><span><br></span><span>　　让我们快速的看一下抗锯齿。当渲染单个多边形时，</span><span>3D </span><span>显卡仔细检查已经渲染的，并对新的多边形的边缘进行柔化，这样你就不会得到明显可见的锯齿形的像素边缘。两种技术方法之一通常被用来处理。</span><span> </span><span>第一种方法是单个多边形层次，需要你从视野后面到前面渲染多边形，这样每个多边形都能和它后面的进行适当的混合。如果不按序进行渲染，最后你会看见各种奇怪的效果。在第二种方法中，使用比实际显示更大的分辩率来渲染整幅幀画面，然后在你缩小图像时，尖锐的锯齿形边缘就混合消失了。这第二种方法的结果不错，但因为显卡需要渲染比实际结果幀更多的像素，所以需要大量的内存资源和很高的内存带宽。</span><span><br><br></span><span>　　多数新的显卡能很好地处理这些，但仍然有多种抗锯齿模式可以供你选择，因此你可以在性能和质量之间作出折衷。对於当今流行的各种不同抗锯齿技术的更详细讨论请参见</span><span>Dave Salvator </span><span>的</span><span>3D </span><span>流水线一文。</span><span><br><br><br></span><strong><span>顶点与像素着色</span></strong><span><br></span><span>　　在结束讨论渲染技术之前，我们快速的说一下顶点和像素着色，最近它们正引起很多关注。顶点着色是一种直接使用显卡硬件特征的方式，不使用</span><span>API</span><span>。举例来说，如果显卡支持硬件</span><span> T &amp; L </span><span>，你可以用</span><span>DirectX</span><span>或</span><span>OpenGL</span><span>编程，并希望你的顶点通过</span><span> T &amp; L </span><span>单元</span><span> (</span><span>因为这完全由驱动程序处理，所以没有办法确信</span><span>)</span><span>，或者你直接利用显卡硬件使用顶点着色。它们允许你根据显卡自身特征进行特别编码，你自己特殊的编码使用</span><span>T &amp; L </span><span>引擎，以及为了发挥你的最大优势，显卡必须提供的其他别的特征。</span><span> </span><span>事实上，现在</span><span>nVidia </span><span>和</span><span>ATI </span><span>在他们大量的显卡上都提供了这个特征。</span><span> <br><br></span><span>　　不幸的是，显卡之间表示顶点着色的方法并不一致。你不能象使用</span><span>DirectX</span><span>或者</span><span>OpenGL </span><span>那样，为顶点着色编写一次代码就可以在任何显卡上运行，这可是个坏消息。然而，因为你直接和显卡硬件交流，它为快速渲染顶点着色可能生成的效果提供最大的承诺。</span><span>( </span><span>如同创造很不错的特效</span><span> -- </span><span>你能够使用顶点着色以</span><span>API</span><span>没有提供的方式影响事物</span><span>)</span><span>。事实上，顶点着色正在真的将</span><span>3D </span><span>图形显示卡带回到游戏机的编码方式，直接存取硬件，最大限度利用系统的必须知识，而不是依靠</span><span>API</span><span>来为你做一切。对一些程序员来说，会对这种编码方式感到吃惊，但这是进步代价。</span><span><br><br></span><span>　　进一步阐述，顶点着色是一些在顶点被送到显卡渲染之前计算和运行顶点效果程序或者例程。你可以在主</span><span>CPU</span><span>上面用软件来做这些事情，或者使用显卡上的顶点着色。</span><span> </span><span>为动画模型变换网格是顶点程序的主选。</span><span><br><br></span><span>　　像素着色是那些你写的例程，当绘制纹理时，这些例程就逐个像素被执行。你有效地用这些新的例程推翻了显卡硬件正常情况做的混合模式运算。这允许你做一些很不错的像素效果，</span><span> </span><span>比如，使远处的纹理模糊，添加炮火烟雾</span><span>, </span><span>产生水中的反射效果等。一旦</span><span> ATI </span><span>和</span><span> nVidia </span><span>能实际上就像素着色版本达成一致</span><span>( DX9's </span><span>新的高级阴影语言将会帮助促进这一目标</span><span>), </span><span>我一点不惊讶</span><span>DirectX </span><span>和</span><span>OpenGL</span><span>采用</span><span>Glide</span><span>的方式</span><span>-- </span><span>有帮助开始</span><span>, </span><span>但最终不是把任何显卡发挥到极限的最好方法。我认为我会有兴趣观望将来。</span><span><br><br><br></span><strong><span>最后（</span></strong><strong><span>In Closing...</span></strong><strong><span>）</span></strong><span><br></span><span>　　最终，渲染器是游戏程序员最受评判的地方。在这个行业，视觉上的华丽非常重要，因此它为知道你正在做的买单。对于渲染器程序员，最坏的因素之一就是</span><span>3D </span><span>显卡工业界变化的速度。一天，你正在尝试使透明图像正确地工作；第二天</span><span> nVidia </span><span>正在做顶点着色编程的展示。而且发展非常快，大致上，四年以前为那个时代的</span><span> 3D </span><span>显卡写的代码现在已经过时了，需要全部重写。</span><span> </span><span>甚至</span><span>John Carmack </span><span>这样描述过，他知道四年以前为充分发挥那个时期显卡的性能所写的不错的代码，如今很平凡</span><span> -- </span><span>因此他产生了为每个新的</span><span>id</span><span>项目完全重写渲染器的欲望。</span><span>Epic </span><span>的</span><span>Tim Sweeney</span><span>赞同</span><span> -- </span><span>这里是去年他给我的评论</span><span>: <br><br></span><span>　　我们已经足足花费了</span><span>9</span><span>个月时间来更换所有的渲染代码。最初的</span><span> Unreal </span><span>被设计为软件渲染和后来扩展为硬件渲染。下一代引擎被设计为</span><span> GeForce </span><span>及更好的图形显示卡，且多边形吞吐量是</span><span>Unreal Tournament</span><span>的</span><span>100</span><span>倍。</span><span> <br><br></span><span>　　这需要全部替换渲染器。很幸运，该引擎模块化程度足够好，我们可以保持引擎的其余部分</span><span>—</span><span>编辑器，物理学，人工智能，网络</span><span>--</span><span>不改动，尽管我们一直在以许多方式改进这些部分。</span><span><br><br></span><span>　　搭配长篇文章的短篇报导（</span><span>Sidebar</span><span>）：</span><span>API -- </span><span>祝福和诅咒</span><span><br></span><span>　　那么什么是</span><span>API? </span><span>它是应用程序编程接口</span><span>,</span><span>将不一致的后端用一致的前端呈现出来。举例来说，很大程度上每种</span><span>3D</span><span>显示卡的</span><span>3D</span><span>实现方式都有所差别。然而，他们全部都呈现一个一致的前端给最终使用者或者程序员，所以他们知道他们为</span><span>X 3D</span><span>显示卡写的代码将会在</span><span>Y 3D</span><span>显示卡上面有相同的结果。好吧，不管怎样理论上是那样。</span><span> </span><span>大约在三年以前这可能是相当真实的陈述，但自那以后，在</span><span>nVidia </span><span>公司的引领下，</span><span>3D</span><span>显卡行业的事情发生了变化。</span><span> <br><br></span><span>　　如今在</span><span>PC</span><span>领域，除非你正计划建造自己的软件光栅引擎，使用</span><span>CPU</span><span>来绘制你所有的精灵，多边形和粒子</span><span> -- </span><span>而且人们仍然在这样做。跟</span><span>Unreal</span><span>一样，</span><span>Age of Empires II: Age of Kings</span><span>有一个优秀的软件渲染器</span><span> &#8211; </span><span>否则你将使用两种可能的图形</span><span>API</span><span>，</span><span>OpenGL</span><span>或者</span><span> DirectX </span><span>之一。</span><span>OpenGL</span><span>是一种真正的跨平台</span><span>API (</span><span>使用这种</span><span>API</span><span>写的软件可以在</span><span>Linux</span><span>，</span><span>Windows</span><span>和</span><span>MacOS</span><span>上运行。</span><span>)</span><span>，</span><span> </span><span>而且有多年的历史了，为人所熟知，但也开始慢慢地显示出它的古老。</span><span> </span><span>大约在四年以前，定义</span><span>OpenGL</span><span>驱动特征集一直是所有显示卡厂商工作的方向。</span><span><br><br></span><span>　　然而，一旦在目标达成以后，没有预先制定特征工作方向的路线图，这时候，所有的显卡开发商开始在特征集上分道扬镳，使用</span><span>OpenGL</span><span>扩展。</span><span><br><br></span><span>　　</span><span>3dfx </span><span>创造了</span><span>T- </span><span>缓冲。</span><span> nVidia </span><span>努力寻求硬件变换和光照计算。</span><span>Matrox</span><span>努力获取凹凸贴图。等等。</span><span> </span><span>我以前说过的一句话，</span><span>"</span><span>过去几年以来，</span><span>3D</span><span>显示卡领域的事情发生了变化。</span><span>"</span><span>委婉地说明了这一切。</span><span> <br><br></span><span>　　无论如何，另一个可以选择的</span><span>API</span><span>是</span><span> DirectX</span><span>。这受</span><span>Microsoft</span><span>公司控制，且在</span><span>PC </span><span>和</span><span> Xbox </span><span>上被完美地支持。由于明显的原因，</span><span>DirectX </span><span>没有</span><span>Apple</span><span>或者</span><span> Linux </span><span>版本。因为</span><span>Microsoft</span><span>控制着</span><span> DirectX</span><span>，大体上它容易更好地集成在</span><span>Windows</span><span>里面。</span><span> <br><br></span><span>　　</span><span>OpenGL</span><span>和</span><span>DirectX</span><span>之间的基本差别是前者由</span><span>&#8216;</span><span>社区</span><span>&#8217;</span><span>拥有，而后者由</span><span>Microsoft</span><span>拥有。如果你想要</span><span> DirectX </span><span>为你的</span><span> 3D </span><span>显示卡支持一个新的特征，那么你需要游说微软，希望采纳你的愿望，并等待新的</span><span> DirectX</span><span>发行版本。对于</span><span>OpenGL</span><span>，由于显示卡制造商为</span><span>3D</span><span>显示卡提供驱动程序，你能够通过</span><span>OpenGL</span><span>扩展立即获得显示卡的新特征。这是好，但作为游戏开发者，当你为游戏编码的时候，你不能指望它们很普遍。它们可能让你的游戏速度提升</span><span>50%</span><span>，但你不能要求别人有一块</span><span>GeForce 3 </span><span>来跑你的游戏。好吧，你可以这么做，但如果你想来年还在这个行业的话，这是个相当愚蠢的主意。</span><span><br><br></span><span>　　这是对这个问题极大的简单化，对我所有描述的也有各种例外情况，但这里一般的思想是很确实的。对于</span><span>DirectX </span><span>，在任何既定时间你容易确切地知道你能从显示卡获得的特征，如果一个特征不能获得，</span><span>DirectX </span><span>将会用软件模拟它</span><span>(</span><span>也不总是一件好事情，因为这样有时侯非常的慢，但那是另外一回事</span><span>)</span><span>。对于</span><span>OpenGL</span><span>，你可以更加贴近显示卡的特征</span><span>,</span><span>但代价是不能确定将会获得的准确特征。</span><span> <br><br></span><img src ="http://www.cppblog.com/mzty/aggbug/37769.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2007-12-04 13:17 <a href="http://www.cppblog.com/mzty/archive/2007/12/04/37769.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏引擎基础（二）（3D环境的光照和纹理）</title><link>http://www.cppblog.com/mzty/archive/2007/12/04/37768.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Tue, 04 Dec 2007 05:16:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2007/12/04/37768.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/37768.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2007/12/04/37768.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/37768.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/37768.html</trackback:ping><description><![CDATA[<span>第</span><span>2</span><span>部份</span><span>: 3D</span><span>环境的光照和纹理</span><span><br><br><br></span><strong><span>世界的灯光</span></strong><span><br></span><span>　　在变换过程中，</span><span> </span><span>通常是在称为观察空间的坐标空间中，</span><span> </span><span>我们遇到了最重要的运算之一</span><span>: </span><span>光照计算。</span><span> </span><span>它是一种这样的事情，</span><span> </span><span>当它工作时，你不关注它，但当它不工作时，</span><span> </span><span>你就非常关注它了。有很多不同的光照方法，从简单的计算多边形对于灯光的朝向，并根据灯光到多边形的方向和距离加上灯光颜色的百分比值，一直到产生边缘平滑的灯光贴图叠加基本纹理。而且一些</span><span> API </span><span>实际上提供预先建造的光照方法。举例来说，</span><span>OpenGL </span><span>提供了每多边形，每顶点，和每像素的光照计算。</span><span> <br><br></span><span>　　在顶点光照中，你要决定一个顶点被多少个多边形共享，并计算出共享该顶点的所有多边形法向量的均值（称为法向量），并将该法向量赋顶点。一个给定多边形的每个顶点会有不同的法向量，所以你需要渐变或插值多边形顶点的光照颜色以便得到平滑的光照效果。</span><span> </span><span>你没有必要用这种光照方式查看每个单独的多边形。</span><span> </span><span>这种方式的优点是时常可以使用硬件转换与光照（</span><span>T &amp; L</span><span>）来帮助快速完成。</span><span> </span><span>不足之处是它不能产生阴影。</span><span> </span><span>举例来说，即使灯光是在模型的右侧，左手臂应该在被身体投影的阴影中，而实际上模型的双臂却以同样的方式被照明了。</span><span><br><br></span><span>　　这些简单的方法使用着色来达到它们的目标。</span><span> </span><span>当用平面光照绘制一个多边形时，</span><span> </span><span>你让渲染（绘制）引擎把整个多边形都着上一种指定的颜色。这叫做平面着色光照。</span><span> (</span><span>该方法中，多边形均对应一个光强度，表面上所有点都用相同的强度值显示，渲染绘制时得到一种平面效果，多边形的边缘不能精确的显示出来</span><span>) </span><span>。</span><span><br><br></span><span>　　对于顶点着色</span><span> ( Gouraud </span><span>着色</span><span>) </span><span>，你让渲染引擎给每个顶点赋予特定的颜色。</span><span> </span><span>在绘制多边形上各点投影所对应的像素时，根据它们与各顶点的距离，对这些顶点的颜色进行插值计算。</span><span> (</span><span>实际上</span><span>Quake III </span><span>模型使用的就是这种方法，</span><span> </span><span>效果好的令人惊奇</span><span>)</span><span>。</span><span> <br><br></span><span>　　还有就是</span><span> Phong </span><span>着色。如同</span><span> Gouraud </span><span>着色，通过纹理工作，但不对每个顶点颜色进行插值决定像素颜色值，</span><span> </span><span>它对每个顶点的法向量进行插值，会为每个顶点投影的像素做相同的工作。对于</span><span> Gouraud </span><span>着色，你需要知道哪些光投射在每个顶点上。对于</span><span> Phong </span><span>着色，你对每个像素也要知道这么多。</span><span> <br><br></span><span>　　一点也不令人惊讶，</span><span> Phong </span><span>着色可以得到更加平滑的效果，因为每个像素都需要进行光照计算，其绘制非常耗费时间。平面光照处理方法很快速，</span><span> </span><span>但比较粗糙。</span><span>Phong </span><span>着色比</span><span> Gouraud </span><span>着色计算更昂贵，但效果最好，可以达到镜面高光效果</span><span>("</span><span>高亮</span><span>")</span><span>。</span><span> </span><span>这些都需要你在游戏开发中折衷权衡。</span><span><br><br><br></span><strong><span>不同的灯光</span></strong><span><br></span><span>　　接着是生成照明映射，你用第二个纹理映射（照明映射）与已有的纹理混合来产生照明效果。这样工作得很好，</span><span> </span><span>但这本质上是在渲染之前预先生成的一种罐装效果。如果你使用动态照明</span><span> (</span><span>即，灯光移动，</span><span> </span><span>或者没有程序的干预而打开和关闭</span><span>)</span><span>，你得必须在每一幀重新生成照明映射，按照动态灯光的运动方式修改这些照明映射。灯光映射能够快速的渲染，但对存储这些灯光纹理所需的内存消耗非常昂贵。你可以使用一些压缩技巧使它们占用较少的的内存空间，或减少其尺寸大小，</span><span> </span><span>甚至使它们是单色的</span><span> (</span><span>这样做就不会有彩色灯光了</span><span>)</span><span>，等等。</span><span> </span><span>如果你确实在场景中有多个动态灯光，</span><span> </span><span>重新生成照明映射将以昂贵的</span><span>CPU</span><span>周期而告终。</span><span> <br><br></span><span>　　许多游戏通常使用某种混合照明方式。</span><span> </span><span>以</span><span>Quake III</span><span>为例，场景使用照明映射，</span><span> </span><span>动画模型使用顶点照明。</span><span> </span><span>预先处理的灯光不会对动画模型产生正确的效果</span><span> -- </span><span>整个多边形模型得到灯光的全部光照值</span><span> -- </span><span>而动态照明将被用来产生正确的效果。</span><span> </span><span>使用混合照明方式是多数的人们没有注意到的一个折衷，它通常让效果看起来</span><span>"</span><span>正确</span><span>"</span><span>。</span><span> </span><span>这就是游戏的全部</span><span> &#8211; </span><span>做一切必要的工作让效果看起来</span><span>"</span><span>正确</span><span>"</span><span>，但不必真的是正确的。</span><span> <br><br></span><span>　　当然，所有这些在新的</span><span>Doom</span><span>引擎里面都不复存在了，但要看到所有的效果，至少需要</span><span> 1GHZ CPU </span><span>和</span><span> GeForce 2 </span><span>显卡。是进步了，但一切都是有代价的。</span><span> <br><br></span><span>　　一旦场景经过转换和照明，</span><span> </span><span>我们就进行裁剪运算。</span><span> </span><span>不进入血淋淋的细节而，剪断运算决定哪些三角形完全在场景</span><span> (</span><span>被称为观察平截头体</span><span>) </span><span>之内或部份地在场景之内。完全在场景之内的三角形被称为细节接受，它们被处理。对于只是部分在场景之内的三角形，</span><span> </span><span>位于平截头体外面的部分将被裁剪掉，余下位于平截头体内部的多边形部分将需要重新闭合，以便其完全位于可见场景之内。</span><span> (</span><span>更多的细节请参考我们的</span><span> 3D </span><span>流水线指导一文</span><span>)</span><span>。</span><span><br><br></span><span>　　场景经过裁剪以后，流水线中的下一个阶段就是三角形生成阶段</span><span>(</span><span>也叫做扫描</span><span> </span><span>线转换</span><span>)</span><span>，场景被映射到</span><span>2D </span><span>屏幕坐标。到这里，就是渲染（绘制）运算了。</span><span><br><br><br></span><strong><span>纹理与</span></strong><strong><span>MIP</span></strong><strong><span>映射</span></strong><span><br></span><span>　　纹理在使</span><span>3D</span><span>场景看起来真实方面异常重要，它们是你应用到场景区域或对象的一些分解成多边形的小图片。多重纹理耗费大量的内存，有不同的技术来帮助管理它们的尺寸大小。纹理压缩是在保持图片信息的情况下，让纹理数据更小的一种方法。纹理压缩占用较少的游戏</span><span>CD</span><span>空间，更重要的是，占用较少内存和</span><span>3D </span><span>显卡存储空间。另外，在你第一次要求显卡显示纹理的时候，压缩的</span><span>(</span><span>较小的</span><span>) </span><span>版本经过</span><span> AGP </span><span>接口从</span><span> PC </span><span>主存送到</span><span>3D </span><span>显卡，</span><span> </span><span>会更快一些。纹理压缩是件好事情。</span><span> </span><span>在下面我们将会更多的讨论纹理压缩。</span><span> <br><br><br><strong><span>MIP </span></strong></span><strong><span>映射（多纹理映射）</span></strong><span><br></span><span>　　游戏引擎用来减少纹理内存和带宽需求的另外一个技术就是</span><span> MIP </span><span>映射。</span><span> MIP </span><span>映射技术通过预先处理纹理，产生它的多个拷贝纹理，每个相继的拷贝是上一个拷贝的一半大小。为什么要这样做</span><span>?</span><span>要回答这个问题，你需要了解</span><span> 3D </span><span>显卡是如何显示纹理的。最坏情况，你选择一个纹理，贴到一个多边形上，然后输出到屏幕。我们说这是一对一的关系，最初纹理映射图的一个纹素</span><span> (</span><span>纹理元素</span><span>) </span><span>对应到纹理映射对象多边形的一个像素。如果你显示的多边形被缩小一半，纹理的纹素就每间隔一个被显示。这样通常没有什么问题</span><span> -- </span><span>但在某些情况下会导致一些视觉上的怪异现象。让我们看看砖块墙壁。</span><span> </span><span>假设最初的纹理是一面砖墙，有许多砖块，砖块之间的泥浆宽度只有一个像素。如果你把多边形缩小一半，</span><span> </span><span>纹素只是每间隔一个被应用，这时候，所有的泥浆会突然消失，因为它们被缩掉了。你只会看到一些奇怪的图像。</span><span> <br><br></span><span>　　使用</span><span> MIP </span><span>映射，你可以在显示卡应用纹理之前，自己缩放图像，因为可以预先处理纹理，你做得更好一些，让泥浆不被缩掉。当</span><span> 3D </span><span>显卡用纹理绘制多边形时，它检测到缩放因子，说，</span><span>"</span><span>你知道，我要使用小一些的纹理，而不是缩小最大的纹理，这样看起来会更好一些。</span><span>" </span><span>在这里，</span><span> MIP </span><span>映射为了一切，一切也为了</span><span> MIP </span><span>映射。</span><span><br><br><br></span><strong><span>多重纹理与凹凸映射</span></strong><span><br></span><span>　　单一纹理映射给整个</span><span>3D </span><span>真实感图形带来很大的不同，</span><span> </span><span>但使用多重纹理甚至可以达到一些更加令人难忘的效果。过去这一直需要多遍渲染（绘制），严重影响了像素填充率。</span><span> </span><span>但许多具有多流水线的</span><span>3D </span><span>加速卡，如</span><span>ATI's Radeon </span><span>和</span><span> nVidia's GeForce 2</span><span>及更高级的显卡，多重纹理可以在一遍渲染（绘制）过程中完成。</span><span> </span><span>产生多重纹理效果时，</span><span> </span><span>你先用一个纹理绘制多边形，然后再用另外一个纹理透明地绘制在多边形上面。这让你可以使纹理看上去在移动，或脉动，</span><span> </span><span>甚至产生阴影效果</span><span> (</span><span>我们在照明一节中描述过</span><span>)</span><span>。绘制第一个纹理映射，然后在上面绘制带透明的全黑纹理，引起一种是所有的织法黑色的但是有一个透明分层堆积过它的顶端</span><span> </span><span>，</span><span> </span><span>这就是</span><span> -- </span><span>即时阴影。</span><span> </span><span>该技术被称为照明映射</span><span> ( </span><span>有时也称为</span><span> </span><span>暗映射</span><span>)</span><span>，直至新的</span><span>Doom </span><span>，一直是</span><span>Id</span><span>引擎里关卡照明的传统方法。</span><span> <br><br></span><span>　　凹凸贴图是最近涌现出来的一种古老技术。几年以前</span><span> Matrox </span><span>第一个在流行的</span><span> 3D </span><span>游戏中发起使用各种不同形式的凹凸贴图。就是生成纹理来表现灯光在表面的投射，表现表面的凹凸或表面的裂缝。</span><span> </span><span>凹凸贴图并不随着灯光一起移动</span><span> -- </span><span>它被设计用来表现一个表面上的细小瑕疵，而不是大的凹凸。</span><span> </span><span>比如说，在飞行模拟器中，你可以使用凹凸贴图来产生像是随机的地表细节，而不是重复地使用相同的纹理，看上去一点趣味也没有。</span><span> <br><br></span><span>　　凹凸贴图产生相当明显的表面细节，尽管是很高明的戏法，但严格意义上讲，凹凸贴图并不随着你的观察角度而变化。比较新的</span><span> ATI </span><span>和</span><span> nVidia </span><span>显卡片能执行每像素运算，这种缺省观察角度的不足就真的不再是有力而快速的法则了。</span><span> </span><span>无论是哪一种方法，</span><span> </span><span>到目前为止，没有游戏开发者太多的使用；</span><span> </span><span>更多的游戏能够且应该使用凹凸贴图。</span><span><br><br><br></span><strong><span>高速缓存抖动</span></strong><strong><span> = </span></strong><strong><span>糟糕的事物</span></strong><span><br></span><span>　　纹理高速缓存的管理游戏引擎的速度至关重要。</span><span> </span><span>和任何高速缓存一样，缓存命中很好，而不命中将很糟糕。如果遇到纹理在图形显示卡内存被频繁地换入换出的情况，这就是纹理高速缓存抖动。发生这种情况时，通常</span><span>API</span><span>将会废弃每个纹理，结果是所有的纹理在下一幀将被重新加载，这非常耗时和浪费。对游戏玩家来说，当</span><span>API</span><span>重新加载纹理高速缓存时，会导致幀速率迟钝。</span><span><br><br></span><span>　　在纹理高速缓存管理中，有各种不同的技术将纹理高速缓存抖动减到最少</span><span> &#8211; </span><span>这是确保任何</span><span> 3D </span><span>游戏引擎速度的一个决定性因素。</span><span> </span><span>纹理管理是件好事情</span><span> &#8211; </span><span>这意味着只要求显卡使用纹理一次，而不是重复使用。这听起来有点自相矛盾，但效果是它意谓着对显卡说，</span><span>"</span><span>看，</span><span> </span><span>所有这些多边形全部使用这一个纹理，我们能够仅仅加载这个纹理一次而不是许多次吗</span><span>?" </span><span>这阻止</span><span>API ( </span><span>或图形驱动软件</span><span>) </span><span>上传多次向显卡加载纹理。象</span><span>OpenGL</span><span>这样的</span><span>API</span><span>实际上通常处理纹理高速缓存管理，意谓着，根据一些规则，比如纹理存取的频率，</span><span>API</span><span>决定哪些纹理储存在显卡上，哪些纹理存储在主存。</span><span> </span><span>真正的问题来了：</span><span>a) </span><span>你时常无法知道</span><span>API</span><span>正在使用的准确规则。</span><span> b)</span><span>你时常要求在一幀中绘制更多的纹理，以致超出了显卡内存空间所能容纳的纹理。</span><span> <br><br></span><span>　　另外一种纹理高速缓存管理技术是我们早先讨论的纹理压缩。很象声音波形文件被压缩成</span><span> MP3 </span><span>文件，尽管无法达到那样的压缩比率，但纹理可以被压缩。</span><span> </span><span>从声音波形文件到</span><span>MP3</span><span>的压缩可以达到</span><span> 11:1</span><span>的压缩比率，而绝大多数硬件支持的纹理压缩运算法则只有</span><span> 4:1 </span><span>的压缩比率，尽管如此，这样能产生很大的差别。</span><span> </span><span>除此之外，在渲染（绘制）过程中，只有在需要时，硬件才动态地对纹理进行解压缩。这一点非常棒，我们仅仅擦除即将可能用到的表面。</span><span><br><br></span><span>　　如上所述，另外一种技术确保渲染器要求显卡对每个纹理只绘制一次。确定你想要渲染（绘制）的使用相同纹理的所有多边形同时送到显卡，而不是一个模型在这里，另一个模型在那里，然后又回到最初的纹理论。仅仅绘制一次，你也就通过</span><span>AGP</span><span>接口传送一次。</span><span>Quake III </span><span>在其阴影系统就是这么做的。处理多边形时，把它们加入到一个内部的阴影列表，一旦所有的多边形处理完毕，渲染器遍历纹理列表，就将纹理及所有使用这些纹理的多边形同时传送出去。</span><span> <br><br></span><span>　　上述过程在使用显卡的硬件</span><span> T &amp; L</span><span>（如果支持的话）时，并不怎么有效。你面临的结局是，满屏幕都是使用相同纹理的大量的多边形小群组，所有多边形都使用不同的变换矩阵。这意谓着更多的时间花在建立显卡的硬件</span><span> T &amp; L </span><span>引擎</span><span> </span><span>，更多的时间被浪费了。</span><span> </span><span>无论如何，因为他们有助于对整个模型使用统一的纹理，所以它对实际屏幕上的模型可以有效地工作。但是因为许多多边形倾向使用相同的墙壁纹理，所以对于世界场景的渲染，它常常就是地狱。通常它没有这么严重，因为大体而言，世界的纹理不会有那么大，这样一来</span><span>API</span><span>的纹理缓存系统将会替你处理这些，并把纹理保留在显卡以备再次使用。</span><span> <br><br></span><span>　　在游戏机上，通常没有纹理高速缓存系统</span><span>(</span><span>除非你写一个</span><span>)</span><span>。在</span><span> PS2 </span><span>上面，你最好是远离</span><span>"</span><span>一次纹理</span><span>" </span><span>的方法。在</span><span> Xbox </span><span>上面，</span><span> </span><span>这是不重要的，因为它本身没有图形内存</span><span>(</span><span>它是</span><span> UMA </span><span>体系结构</span><span>)</span><span>，且所有的纹理无论如何始终保留在主存之中。</span><span> <br><br></span><span>　　事实上，在今天的现代</span><span>PC FPS </span><span>游戏中，试图通过</span><span>AGP</span><span>接口传送大量纹理是第二个最通常的瓶颈。最大的瓶颈是实际几何处理，它要使东西出现在它应该出现的地方。在如今的</span><span>3D FPS </span><span>游戏中，最耗费时间的工作，显然是那些计算模型中每个顶点正确的世界位置的数学运算。如果你不把场景的纹理保持在预算之内，仅居其次的就是通过</span><span>AGP</span><span>接口传送大量的纹理了。然而，你确实有能力影响这些。</span><span> </span><span>通过降低顶层的</span><span> MIP </span><span>级别</span><span>(</span><span>还记得系统在哪里不断地为你细分纹理吗</span><span>?)</span><span>，</span><span> </span><span>你就能够把系统正在尝试送到显卡的纹理大小减少一半。你的视觉质量会有所下降</span><span>-- </span><span>尤其是在引人注目的电影片断中</span><span>--</span><span>但是你的幀速率上升了。这种方式对网络游戏尤其有帮助。实际上，</span><span>Soldier of Fortune II</span><span>和</span><span>Jedi Knight II: Outcast</span><span>这两款游戏在设计时针对的显卡还不是市场上的大众主流显卡。为了以最大大小观看他们的纹理，你的</span><span>3D </span><span>显卡至少需要有</span><span>128MB</span><span>的内存。这两种产品在思想上都是给未来设计的。</span><span> <br><br></span><span>　　上面就是第</span><span> 2 </span><span>部份。在下面章节中，我们将介绍许多主题，包括内存管理，雾效果，深度测试，</span><span> </span><span>抗锯齿，顶点着色，</span><span>API</span><span>等。</span><span> <br><br></span><img src ="http://www.cppblog.com/mzty/aggbug/37768.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2007-12-04 13:16 <a href="http://www.cppblog.com/mzty/archive/2007/12/04/37768.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏引擎基础（一）（渲染和构造3D世界）</title><link>http://www.cppblog.com/mzty/archive/2007/12/04/37767.html</link><dc:creator>梦在天涯</dc:creator><author>梦在天涯</author><pubDate>Tue, 04 Dec 2007 05:14:00 GMT</pubDate><guid>http://www.cppblog.com/mzty/archive/2007/12/04/37767.html</guid><wfw:comment>http://www.cppblog.com/mzty/comments/37767.html</wfw:comment><comments>http://www.cppblog.com/mzty/archive/2007/12/04/37767.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/mzty/comments/commentRss/37767.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/mzty/services/trackbacks/37767.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;本系列转自：http://www.cppblog.com/orlando/archive/2007/12/03/37734.html&nbsp;谢谢作者有这么好的文章与大家共享！代表所有有幸阅读到次书的读者谢谢先！第1部分: 游戏引擎介绍， 渲染和构造3D世界介绍　　自Doom游戏时代以来我们已经走了很远。 DOOM不只是一款伟大的游戏，它同时也开创了一种新的游戏编程模式: 游戏 "引...&nbsp;&nbsp;<a href='http://www.cppblog.com/mzty/archive/2007/12/04/37767.html'>阅读全文</a><img src ="http://www.cppblog.com/mzty/aggbug/37767.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/mzty/" target="_blank">梦在天涯</a> 2007-12-04 13:14 <a href="http://www.cppblog.com/mzty/archive/2007/12/04/37767.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>