如何在Cocos2d-x 3.0 中整合LiquidFun PART1

[size=3]如何在Cocos2d-x 中整合LiquidFun (带有流体物理性质的粒子)。 [/size]

这篇教程的话,原版是来源于Ricardo Quesada的文章,英文好的童鞋可以直接点击 http://towp8.com/2014/04/23/integrating-liquidfun-with-cocos2d-x-part-i/ 学习。

背景介绍:

LiquidFun 是谷歌基于原本的Box2D改造的,可以生成带有流体物理性质粒子的一个扩展库。Ricardo 利用这个LiquidFun,将它整合到了Cocos2d-x 3.0 中,做成了2个Demo,使我们可以直接生成带有流体物理性质的粒子。

LiquidFun 整合Cocos2d-x 3.0 Demo github 仓库地址:https://github.com/cocos2d/cocos2d-x-samples

LiquidFun 官方文档: http://google.github.io/liquidfun/

[attachment=68777]
LiquidFun Testbed + Cocos2d-x

以下是全文翻译,有不够准确的地方,希望大家指出

分割线******************

下面这段话摘自LiquidFun的官网地址:

[backcolor=#ffff66]通过基于Box2D的功能,LiquidFun 实现了一个可以模拟流体的粒子特效。游戏开发者可以在他们的游戏中通过使用它来实现游戏中的力学,或者逼真的物理特效。游戏设计者则可以通过这些库来设计出精彩的流体互动的游戏体验。[/backcolor]

通过上面这段话可以看出,本质上 LiquidFun 是一个在Box2D之上追加的一个扩展,它通过使用粒子系统来实现模拟流体粒子的效果。你可以通过下载安装安卓上的LiquidFun-TestbedLiquidFun-EyeCandy 来测试它。

Cocos2d-x 已经整合了Box2D,  为了整合LiquidFun, 我们需要先把一个新的类整合进来:b2ParticleSystem

[size=3]LiquidFun中的 b2ParticleSystem[/size][size=3]
[/size]
我并不打算在这里介绍如何使用LiquidFun(你可以通过阅读它的开发向导来学习。)不过,我会讲解如何将 [font=courier new, courier, monospace]b2ParticleSysytem [/font]整合进Cocos2d-x。(这个方法在别的游戏引擎中也同样适用。)

为了合并整合,我们需要一个能够懂得如何渲染 [font=courier new]b2ParticleSysytem的[/font][font=arial, helvetica, sans-serif] [/font][font=courier new]Cocos2d-x Node[/font][font=arial, helvetica, sans-serif]。[/font][font=courier new]b2ParticleSysytem [/font][font=arial, helvetica, sans-serif]提供以下4个有用的方法:

<pre class="brush:cpp; toolbar: true; auto-links: false;">class b2ParticleSystem {
  …
  // 获得粒子的数量
  int32 GetParticleCount() const;

  // 获得粒子的半径
  float32 GetRadius() const;

  // 获得每个粒子在Box2D坐标系统中的位置
  // 数组长度可以通过GetParticleCount()获得
  b2Vec2* GetPositionBuffer();

  // 获得每个粒子RGBA Uint8格式下的颜色
  b2ParticleColor* GetColorBuffer();
};
</pre>[/font]

[font=arial, helvetica, sans-serif]理想情况下我们本应该通过重用[/font][font=courier new] cocos2d::ParticleSystemQuad [/font][font=arial, helvetica, sans-serif]来做上面提到的渲染,但是因为以下几个原因这样做是行不通的:[/font]
[list][li][font=courier new]cocos2d::ParticleSystemQuad 不支持改变它的吸引子(这是一个设计上的缺陷,之后我们会修复它。)这种情况下应该用一个空的吸引子。[/font][/li][li][font=courier new]ParticleSystemQuad[/font][font=arial, helvetica, sans-serif] [/font][font=arial, helvetica, sans-serif]是通过[font=courier new]Quads[/font]来实现的,而不是[/font][font=courier new]Points。尽管Cocos2d-x是支持[/font][font=courier new][font=arial, helvetica, sans-serif] [/font]Points的(如 Cocos2d-x v1.0[/font],它依旧没有办法正常工作[font=courier new][font=arial]因为[/font]Points和colors应该在一个交错的数组中。[/font][/li][li][font=courier new]另一个问题便是Box2D和Cocos2d-x之前的坐标系转换问题,不过这个问题可以很容易解决[/font][/li][/list][size=3]Points vs .Quads[/size]
[size=3]
[/size]使用[font=courier new]Points[/font]的主要缺点在于,你没有办法旋转一个[font=courier new]Points[/font],这也正是我们在Cocos2d-x上不使用它的原因。

但是[font=courier new]Points[/font]也有很多优势,它跟[font=courier new]Quads[/font]比起来只需要更少的内存,这意味着它可以运行的更快。下面举一些使用[font=courier new]Point的与[/font][font=courier new]Quads不同的情况[/font]:
[list][li][font=courier new]Point[/font] 的坐标只需要一个点 ([font=courier new]Quads需要4个[/font])[/li][li][font=courier new]Point[/font] 只需要1种颜色([font=courier new]Quads需要4个[/font])[/li][li][font=courier new]Point[/font] 不需要使用 UV 坐标 ([font=courier new]Quads需要[/font])[/li][li][font=courier new]Point[/font] 如果你需要使用不同的大小的时候,你可能要传一个浮点型的数组。([font=courier new]Quads不需要[/font])[/li][li][font=courier new]Point[/font] 在做碰撞检测的时候会消耗比[font=courier new]Quads[/font]更少的资源。[/li][/list]值得注意的是LiquidFun的目的在于模拟流体。因此在流体的情况下,你是不需要去考虑粒子的旋转的, 所以 LiquidFun在这里选择了内存消耗更小的[font=courier new]Points[/font]

[size=3]通过GL_POINTS绘图[/size]

在OpenGL/OpenGL ES 中可以通过[font=courier new]GL_POINTS[/font]来绘制[font=courier new]Points,不过[/font]它有以下几个确定的限制:
[list][li]它没有办法旋转(就像上面说的那样)[/li][li]如果你通过[font=courier new]gl_PointSize[/font]放大或者缩小粒子,你没有办法单独放大或缩小X轴和Y轴的大小,它们只能同时被放大或缩小。[/li][li][font=courier new]Points[/font]也可以使用纹理,但是你没有办法改变他的 U-V坐标,无论你用的是一整张纹理还是什么都不使用。[/li][/list]
如果你以前从没使用过[font=courier new]GL_POINTS,你可以通过下面的代码来看看它什么样的:[/font]

<pre class="brush:cpp; toolbar: true; auto-links: false;">

// 创建一个Box2D下的坐标的数组
// 这些坐标等会会转换成Cocos2d-x中的坐标系统的坐标
void *positions = _particleSystem->GetPositionBuffer();
glVertexAttribPointer(position_index, 2, GL_FLOAT, GL_FALSE, 0, positions);
glEnableVertexAttribArray(position_index);

// 颜色的数组. 它的参数格式: R,G,B,A unsigned bytes
void *colors= _particleSystem->GetColorBuffer();
glVertexAttribPointer(color_index, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors);
glEnableVertexAttribArray(color_index);

// 尺寸大小的数组。particlesize_index指的是一个浮点数的数组(上面提到过的),用户必须创建这个数组
// 这是一个额外的功能,当用户想要使用不一样大小的Points的时候可以用到它
glVertexAttribPointer(particlesize_index, 1, GL_FLOAT, GL_FALSE, 0, particle_size);
glEnableVertexAttribArray(particlesize_index);

// 绘制Points
glDrawArrays(GL_POINTS, 0, _particleSystem->GetParticleCount());
</pre>

[size=3]将Box2d坐标转换成Cocos2d-x坐标系[/size][size=3]
[/size]
Cocos2d-x v3.0 需要将ModelView模型传递给[font=courier new]draw()[/font]方法。我们所要做的便是将它转换成Box2D坐标系统中能用的坐标。下面的代码便是我们所需要做的:[size=3][size=1]
[/size][/size]
<pre class="brush:cpp; toolbar: true; auto-links: false;">
class LFParticleSystemNode : public cocos2d::Node {
  …
  // 为缩放转换用的变量
  kmMat4 _ratioTransform;
}

bool LFParticleSystemNode::init(b2ParticleSystem* particleSystem, float ratio)
{
  …
  // 像素转换为米的比例:相当于将Box2d转换为Cocos2d
  kmMat4Scaling(&_ratioTransform, ratio, ratio, 1);
  …
}

void LFParticleSystemNode::onDraw(const kmMat4 &modelViewTransform, bool transformUpdated)
{
    // 这里需要新建一个新的modelview,它可以让我们在Cocos2d-x坐标系中渲染粒子想·想·
    // newMV = modelViewTransform * _ratioTransform
    kmMat4 newMV;
    kmMat4Multiply(&newMV, &modelViewTransform, &_ratioTransform);
    _shaderProgram->use();
    _shaderProgram->setUniformsForBuiltins(newMV);
   …
}

</pre>

[size=3]通过gl_PointSize来转换大小[/size]

我们要做的另一件事便是上面所没有讲到的,如何根据“世界”大小来放大缩小[font=courier new]Points[/font]。下面的代码将会展示:

<pre class="brush:cpp; toolbar: true; auto-links: false;">// Vertex 着色器
attribute vec4 a_position;
attribute vec4 a_color;
attribute float a_size;

void main()
{
    // CC_PMatrix = Projection Matrix
    // CC_MVMatrix = ModelView Matrix
    gl_Position = CC_PMatrix * CC_MVMatrix * a_position;

    // 下面正是如何放大所辖Points的方法:
    // 这里的ModelView 模型的X轴缩放为[0][0] Y轴缩放为[1][1]
    //不幸的是我们只能ScaleX或者ScaleY,而不能同时使用它们
    gl_PointSize = CC_MVMatrix[0][0] * a_size;
    v_fragmentColor = a_color;
}
</pre>

[size=3]通过gl_PointCoord来生成纹理坐标[/size]

最后要做的事情,就是给粒子附上纹理,否则我们将没法看到任何东西。上面提到过,你不能直接把UV坐标传递给[font=courier new]Points。因此,这里[/font]我们将使用一个叫做[font=courier new]gl_POINTS的[/font]预定义变量。如下:

<pre class="brush:cpp; toolbar: true; auto-links: false;">
// Fragment 着色器
uniform sampler2D CC_Texture0;

varying vec4 v_fragmentColor;
void main()
{
    // gl_PointCoord 在fragment中应该是已经转换成像素了
    // 它必须使用一张完整的纹理,而不是一张纹理中截取的部分。
    gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, gl_PointCoord);
}

</pre>

以上!便是所有的过程!

[font=courier new]你可以在这里找到完整的LFParticleSystemNode:[/font][list][li][font=courier new]LFParticleSystemNode[/font][/li][/list]
完整的示例demo可以在这里下载:[list][li][font=courier new]cocos2d-x-samples: 你可以尝试LiquidFun-EyeCandy和LiquidFun-Tested两个粒子。[/font][/li][/list]
[font=courier new]在第二部分,我会介绍如何将LiquidFun整合到Cocos2d-x在Win32和Visual Studio的环境中。待会我会介绍如何使用更漂亮的"metaball/blob"来渲染模拟水的特效。[/font]

翻译版比较难以理解原本精髓,建议大家读原版。

如果有不理解,需要使用的地方,请私信我,我将帮忙大家解答~~~:2::2::2:

好东西。加油哦。我先去试试。

有可能集合到SpriteKit里吗

我就随便问一下,别打脸

apple会不会做这个工作呢?期待wwdc:14:

请问源码下载后怎样在VS里面编译运行?

好东西……

这个是XCODE的工程,Riq他最后提到之后会给出vs环境的,到时候再发一篇