现在的位置: 首页 > 综合 > 正文

高级粒子系统[译]

2012年07月13日 ⁄ 综合 ⁄ 共 7210字 ⁄ 字号 评论关闭

高级粒子系统

我们学习怎样制作友好的编辑器后,我们的粒子系统,我们进行最后的学习。你可以处理好的GUI代码吗?好的-现在扔掉它们吧,我们的窗口!(现在是回去喘气的时候了,所以每个人围绕着你想你是读一些包含秘密的扭曲的戏剧艺术.)

我们将花大约一章的讲Ch19p1_AdvancedPartSys,高级demo在CD上,所以前进简单的程序发怒了。这第一次不再围绕。取代的是,我们大的编辑3D使徒(看图19.1)

大的编辑框在我们可以输入粒子系统的脚本。停止播放和围绕新的基于脚本的编辑器-你可以加载一些简单的脚本来测试它。

制作高级粒子系统

本章主要的焦点是创建我们调用脚本的粒子系统。我们打算最后两样东西通过存在的粒子系统的代码。最初,我们打算提高它在我们的粒子和粒子系统扩展新的属性,第二,我们打算看到不同的,不同的意见,更多灵活的粒子系统的示范,-脚本。

添加灵活的当前系统

We want the most bang for out buck.翻译上下文,这意味着我们想里要灵活性,但是仍然保持清晰。使用基于脚本的代码,我们放弃我们自己复杂的GuI-GUI将需要许多复杂的对话框。

原因是复杂的数组。获取,粒子,粒子颜色属性。最后我们指定开始颜色和结束颜色。不好,但是不灵活-如果我们创建火回,我们想开始是白色的,渐变为黄色,然后橘黄色,然后红色,然后黑色?同样的,如果我们想粒子速度的改变呢?

现在,我们将解决这些增加的基本情况。改变成员的颜色从但个变量到一个STL 容器颜色将用一些代码,但是不需要很努力。It is the same thing with the particle size and the velocity.

所以现在,取代的是简单的核心属性集,我们现在更多的智能粒子将改变时间。举例,我们也许从这段代码:class CParticle{ protected: D3DXCOLOR m_StartColor; D3DXCOLOR m_EndColor; };

加入这样的代码: class CColorChange{ public: float m_fTime; D3DXCOLOR m_NewColor; };

class CParticle{ protected: std::vector m_ColorChanges; };

另外,我们家但的开始和结束颜色(m_StartColor 和 m_EndColor)支持任意颜色值的改变,每个在粒子时间内作用。更多灵活的方法。

现在,想象如果我们做类似的粒子属性。最初也许我们漂亮的解决,但是靠近我们真正要现实的会一团糟因为所有的代码容器里排列和复制每个属性。我们不得不循环的每帧处理颜色,看任何改变。然后,我们不得不同样的大小,速度。不好-我们的代码复制到所有的地方。

事件 Events

有更好的方式完成灵活性,但是它需要不同的想法模式。取代容器的个别的属性,让粒子放在大的容器里,包含所有的改变-颜色改变,大小改变,等等。

多形的将来到我们面前。想象抽象的基类,CEvent,定义纯粹的虚拟函数"应用"事件的粒子:

class CEvent{ public: virtual void DoItToIt(CParticle &part) = 0; protected: float m_fTime; // time the event occurs };

每个CEvent派生将继承DoItToIt不同-DoItToIt方法使用CColorChangeEvent将应用新的颜色到粒子上,将其他甚至派生的也许弄乱了使用粒子大小或颜色。自从所有的事件需要和某个时间的粒子生存期发生关系,我们将添加CEvent基类。

With this design in place,东西改变容易的管理。粒子维持容器的CEvent派生。

事件次序 Event Sequences

或者不是?容易看到怎样改变给我们的粒子系统在更灵活,但是我们不用停止。假象我们想扩展我们的火焰粒子系统到有事件的顺序-它们的颜色从白色,到黄色,到橙色,到红色。但是烟粒子将有不同的事件顺序也许开始外面深色,但是慢慢的黑色和变的透明。

处理这等级的灵活,我们将需要我们的粒子系统有一系列的不同的事件容器。无论何时粒子出生,系统决定它的使用次序。我们将设置另外的属性在我们的系统中。例如,我们将粒子的25%变成灰,75%变成烟。

你看到整个体系,我们关于一些激烈的粒子系统。

我们添加事件的概念。每个事件是本质粒子属性改变在一个范围内改变。下次,我们添加事件顺序的概念,容器时间告诉粒子不得不运转经过。最后,我们打算创建容器事件顺序,写代码使粒子系统随机的分配每个创建的粒子事件的特殊时间顺序。执行这些增加将创建粒子有能力处理许多非常不同类型的效果。

Goodbye,GUI 再见吧,GUI

现在我们决定更多灵活的设计,我们需要想意味着我们的用户接口。我花了一些时间排除周围的想法,但是最后得到的结论是最后排除GUI。如果我们留着GUI,我们将需要为每个事件做个对话框,加上更多的对话框处理,添加,编辑和删除事件顺序。另外,我们将每次添加对话框我们想添加新的粒子属性。

这些GUI工作,while it's certainly doable,我不想花大量时间在in this book working throuhg it.取代的是,我选择信任非常简单那的GUI,基于文本的脚本 "语言" 代替。我设置单词语言在提出因为我将创建不是真正的语言-它没有变量的概念。循环,条件等。事实上,在本章最后,我们将结束结束一些真正复杂的属性文件(像.x文件格式)比真的脚本语言。然而,foundation will be in place.如果你决定take what's presented here and enhance it,添加支持语言特性,你将非常好结束真正的语言。

再者,有一对边缘利益的东西。写代码读和解析小的关于怎样处理着色编译。你也可以结束好的运行库,你将需要创建其他复杂的,测试基于文件属性格式。

The Birthe of a Simple Scripting Language 简单脚本语言诞生

我开始运行记事本输入东西设计属性文件格式。立刻,我认识到最初商业上创建层次的时间和事件顺序。I decided that the top level of this hierarchy should be the particle system iteself,包含的粒子系统将有事件顺序,和包含事件。所以,让我们来吧。

The Property Shuffle

我们在最后一章结束后的粒子系统将包含众多的属性。现在我们有新的想法,事件和事件顺序,我们需要take another peek at all of those properties and 决定where它们在哪里适合?Are they a property of a given event sequence? 或者,are they a property of all event sequences,这样,粒子系统自己?

灵活的粒子直接依赖于这些属性。例如,引力,当前粒子系统。我们将选择设置三类重力。

Event Level事件级 - 在这个级上,每个粒子保持它自己的引力。引力是粒子自己的属性.

Sequence Level顺序级 - 这这个登记上,引力是事件顺序的属性。这意味着所有同一事件顺序共享引力。

System Level系统级 - 这级上,引力整个粒子系统的属性。所有的粒子共享引力值,不管是否属于事件属性。

The Element of Randomness随机元素

Sheesh!更多设计!可容忍的,我们几乎在那!we're almost there!

现在我们有成群的属性,我们需要思考最后的东西-随机。我们的属性文件里,我们的属性文件里没有每个粒子有个大小,我们需要说所有粒子在一个大小范围内,让粒子引擎去随机决定

Property Shuffle

Property Level

Particle System Position - Particle System

Emit Rate - Event Sequence

Source Blending Mode - Event Sequence

Destination Blending Mode - Event Sequence

Lifetime - Event Sequence

Texture - Event Sequence

Emission Radius - Event Sequence

Gravity - Event Sequence

Spawn Direction - Event Sequence

Color - Event

EventTimer - Event

Size - Event

Velocity - Event

Position - Event

随机值当时间到来时。To accommadate randomness,然后,所有我们需要从属性文件的角度确定存储属性的范围,取代刚刚的值。例如,代替刚刚说的属性大小,我们说两个ints- 一个最小值和一个最大值。粒子系统代码在这个范围内挑出一个值。

计划外:BNF语法

现在我们有任何我们需要开始绘制所有这些属性的规则定义我们的属性文件。这样,我们要借用编译器的设计,叫做BNF语法。BNF stands for Backus Naur Form.A BNF grammar,公共的使用创建编译器,is a way of writing down rule specifying what's legal syntax and what isn't.我发现真的容易写复杂的属性文件分解代码if you have a grammar in front of (and conversely,it's really hard without one),所以我们打算花些时间up front for design(总是好想法),and write a grammar.

开始简单的-什么是一个数?

所以,让我们简单的开始。我们的语法有一行,指定一个RealNumber,和一个数是:

RealNumber ::= --< float datatype >-- Number ::= | Random(.)

这第一行是说一个实型数是float。我们用特定的语法(不是标准BNF语法)来表示C++ 的原始类型。我可以写实际的定义float和其他类型,但是没有值-一旦我们知道float,我们知道足够的解析和有效的加载数据项。例如,没有原因指定值float是一个或多个值,随意的十进制,然后更多的值,当realistically像C API函数atof is going to handle all those detials for me anyway.

Vectors是Just Numbers

你可以看I'm doing here?I'm essentially designing in the ability for the user to write "Random(min,max)" anywhere I'm expecting a number in my properties file.更明显的说明这些,我们看vector的定义

Vector ::= XYZ(,,)

这里,你可以看到,一个向量是XYZ字符串,followed by an open parenthesis, 但是然后获取有趣的。我们指定下三个数,用逗号分开。这里幽雅的部分:因为我们已经定义了RealNumber(float),或者这个Random 东西,我们有属性文件能力指定随机范围they would like.这意味这所有下面的向量是有效的:

XYZ(0,1,0)

XYZ(0,Random(-1,1),0)

XYZ(Random(-1,1),1,0)

XYZ(Random(-1,1),Random(-1,1),Random(-1,1))

其他的原始类型

向前移动,这里更多的语法定义数据将类型将使用属性文件:

Name ::=*{--< char >--}"

AlphaBlendMode ::=D3DBLEND_ZERO | D3DBLEND_ONE|D3DBLEND_SRCCOLOR|D3DBLEND_ INVSRCCOLOR|D3DBLEND_SRCALPHA|D3DBLEND_INVSRCALPHA|D3DBLEND_DESTALPHA|D3DBLEND_ INVDESTALPHA|D3DBLEND_DESTCOLOR|D3DBLEND_INVDESTCOLOR|D3DBLEND_SRCALPHASAT

Color ::=RGBA(,,,)

VersionNumber ::=

自顶向下语法,Down

所以,这些我们的原始类型。我们指定小东西,我们创建构造模快我们可而已创建更多复杂的语句。现在,让我们移动透视看非常的语法树。

事件 Events

围绕所有这些其他的stuff构造特殊时间的粒子生存核心任务是事件,所以它对我们处理大部分的灵活方式是重要的。特殊情况下,我们需要语法以当每个时间发生的时候容易阅读。这里我设计解决问题的大纲的描述。

处理渐变 Dealing with Fades

设置fun的属性,但是没有非常有用。粒子系统在这以前的给我们从开始到结束逐渐变化的能力。我想扩展这章,给我们章粒子系统能力在任意两个属性的指定时间内的变化。

The Final Keyword最后关键字

怎样指定结束的话题用渐变。现在关注下我们的语法属性文件创建灵活性的同时当设置粒子的生存期内。谢谢我们的Number定义,作者可以说LifeTime = 5,或者说LifeTime = Random(5,10).

基本循环:The EventTimer Property

创建一个随机的粒子生存期也扔出猴子wrench into另一特性。基于我们现在,我们可以创造粒子改变颜色在时间式样-例如,开始为红色,然后变为绿色,再变为蓝色等。

第一步写文件属性加载器

所以,我们对漂亮很满意。我们供给完成我们的语法文件,我们说了怎样我们打算维持所有的简单粒子系统的功能。我们也添加了附加的事件和语法常量让我们最后制作更有灵活性。

处理白色空间和内容

最初的话题我们需要处理白色空间。不知何故我们需要忽视白色空间和拣选出我们需要的-文本串,打开和关闭,等。那不足以盲目移除空格符,因为我们有时需要空格嵌在字符串里(那样,如果有人名字叫粒子系统"My Cool System",我们不想改变为"MyCoolSystem"不另人注意。

创建标记

处理文本转换到向量是实际漂亮简单的,因为我们使用非常简单的机器状态来工作。这些新奇的机器状态,认为交通亮度。它可以in one of three states-红,黄,或绿。它可以定义它的规则行为-例如,有个规则规定,不可以从红色过度到黄色,或者从黄色过度到绿色-它必须从红色到绿色,工绿色到黄色,黄色到红色,再回到绿色。

确定符号类型

当符号最后amssses字符串的时候that constitute a token,它需要计算出为token it has found.它调用了DetermineTokenType,简单的函数执行简单的系列字符串搜索token to determine its type.例如,它最初试着如果token starts with a number.或者否定符号。If it does,the tokenizer知道不got a RealNumber.类似的,如果token包含"Random" 或 "XYZ"那么知道它获得随机符号或者关键向量符号。

开始实际的加载代码

现在我们写了转换文本流到向量或符号的解析器,我们可以从加载实际代码开始了。看 Ch19pl-_AdvancedPartSys程序-特定的,编译CParticleEmitter方法,包含在Ch19pl_ParticleSystem.cpp这是主要的方法,可靠的转化文本串到事件顺序,事件和属性。

处理错误

我们开始写实际编译代码前,我们需要确定怎样处理错误。如果我们期待插入但是看到字符取代?如果看关键字是料想到的 What happeds if we see a number where a keyword is supposed to be?

开始

编译函数开始是纯洁的。我们清晰的调用InvalidateDeviceObjects,然后调用Init. 后来我们toke 我们的字符串到CParticleEmitterTokenizer对象然后调用它的Tokenize方法。飞快移动!我们的tokenizer跟随流程图容易许多次结实到解析我们输入文件;Tokenize函数给我们的token流,然后我们准备开始解释成一致的语法。

处理粒子系统块

在保证第一tokens是好的后,调用子程序命名为ProcessParticleSystemBlock.不是令人惊讶的,这个方法负责解释粒子系统块,开始打开支持(注意我们没有解释在调用前解释迭代子)然后技术关闭粒子块的支持。

我们的基于更新函数的新事件

最后一章学到小片的代码-这里我们的新的更新函数:

void CParticleEmitter::Update(float fElapsedTime,float fTimeDelta){ for(std::vector::iterator i=m_Sequences.begin();i!= m_Sequences.end();i++){ (*i)->Update(fElapsedTime,fTimeDelta,m_vPos); } }

我们新的时间基础渲染函数

我们中途的-现在让学习关于新渲染函数机制。同顶端开始,CParticleSystem's渲染方法像这样:

脚本粒子系统封装

WOW!没有完成,但是现在我感到一点想象之后我不喜欢Amazon雨林和emergeed into an open field.我们走到丛林,看到许多有趣的东西,然后到达另一端,之后是光线。

我写了这章给你怎样处理基本的粒子系统和增强它需要合适的游戏。也许基于事件适合你的工作,或者也许不是-另一种方式,你可以学习共享核心的方式,从游戏到游戏变化了但是很高级的特性。

使用脚本的粒子系统

抱歉!评论已关闭.