如何在Cocos2d-x中集成LiquidFun(二)

来源:互联网 发布:声音模拟的软件 编辑:程序博客网 时间:2024/06/06 12:22

本文翻译自《Integrating LiquidFun with Cocos2d-x: Part II


第一部分中,介绍了如何在Cocos2d-x中集成LiquidFun。本文(第二部分)将介绍如何使用一个基本的水效果来渲染粒子效果。

1406857775443454.png

第一部分中,使用glDrawArrays(GL_POINTS, 0, total);来绘制粒子系统。这个函数可用于绘制粒子,但是不能绘制“水”。


绘制“水”需要更复杂的渲染算法,就如这个例子中使用的算法。本文将介绍一个类似的算法。


算法功能

1.选择一个白色的圆圈,并使其模糊化

  • 你可以在运行时使这个圆圈模糊化

  • 你也可以在离线时使其模糊化

2.创建一个新的帧缓存(例如,一个用于渲染的off-screen缓冲区)

3.在新创建的帧缓冲区,使用上述模糊化的圆圈渲染例子效果

4.在主颜色缓冲区使用一个阈值渲染帧缓存。阈值可以是这样的:

  • 如果pixel.r < 0.1, 去掉像素(不绘制这个像素)

  • 如果pixel.r < 0.2, 绘制蓝色像素(作为边界)

  • 其他,绘制白色像素(作为水的内部)


如何使用Cocos2d-x和LiquidFun实现

对第一部分中的LFParticleSystemNode进行扩展:


首先在LFParticleSystemNode类中添加“off-screen”帧缓冲。Cocos2d-x中在RenderTexture类中创建这个“off-screen”缓冲区。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bool LFParticleSystemNode::init(b2ParticleSystem* particleSystem, float ratio)
{
    // create an off-screen frame-buffer with the size of the screen
    auto s = Director::getInstance()->getWinSize();
    _renderTexture = cocos2d::RenderTexture::create(s.width, s.height, Texture2D::PixelFormat::RGBA8888);
    this->addChild(_renderTexture);
    _renderTexture->setAnchorPoint(Point::ANCHOR_MIDDLE);
    _renderTexture->setPosition(Point(s.width/2, s.height/2));
 
    // Change the default shader. Use a the threshold shader
    auto program = GLProgram::createWithByteArrays(_renderTextureShaderVert, _renderTextureShaderFrag);
    auto programState = GLProgramState::getOrCreateWithGLProgram(program);
    programState->setUniformFloat("u_threshold_discard", 0.15);
    programState->setUniformFloat("u_threshold_border", 0.3);
}


另外,正如之前提到的,RenderTexture(off-screen帧缓冲)需要一个着色器阈值。定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
uniform float u_threshold_discard;
uniform float u_threshold_border;
 
void main()
{
    vec4 color = v_fragmentColor * texture2D(CC_Texture0, v_texCoord);
    if( color.r < u_threshold_discard)
    // black or discard
    color = vec4(0,0,0,0);
    else if( color.r < u_threshold_border)
    // blue for the border
    color = vec4(0.2,0.2,0.9,1);
    else
    // white for the center
    color = vec4(1,1,1,1);
    gl_FragColor = color;
}


在运行时定义uthresholddiscard和uthresholdborder的值。这个例子中,值分别为0.15和0.3。


其次,在RenderTexture类中渲染粒子

1
2
3
4
5
6
7
8
9
10
11
12
void LFParticleSystemNode::draw(Renderer *renderer, const Mat4 &transform, uint32_t transformFlags)
{
    // tell RenderTexture to "capture" the particles
    _renderTexture->beginWithClear(0,0,0,0);
 
    _customCommand.init(_globalZOrder);
    _customCommand.func = CC_CALLBACK_0(LFParticleSystemNode::onDraw, this, transform, transformFlags);
    renderer->addCommand(&_customCommand);
 
    // tell RenderTexture to stop "capturing" the particles
    _renderTexture->end();
}


运行结果:

1406858005877902.jpg

进一步改善

以上所描述的是渲染水的简单算法。但是,更高级和渲染效果更好的算法可以通过同样的原则实现:

  • 在off-screen缓冲区渲染模糊(或其他效果)的粒子。

  • 使用特殊的着色器渲染off-screen缓冲区。


Google提供的官方例子“LiquidFun–EyeCandy”使用了更复杂的着色器,包括照明、折射以及背景扭曲。


在Cocos2d-x 3.1及以上版本中自定义着色器

Cocos2d-x 3.1提供了一个自定义着色器的新方法。与3.0版本中的GLProgram类似,但是如果你想要添加自定义属性或者外观,不需要使用GLProgram类,你可以使用GLProgramState类定义。


GLProgram类仍可用,但是推荐使用GLProgramState类,如下:

1
2
3
4
5
6
7
8
// you create a GLProgram like in v3.0
GLProgram* glprogram = GLProgram::createWithByteArrays(_particleShaderVert, _particleShaderFrag);
 
// and then you create a GLProgramState with it
GLProgramState* glprogramstate = GLProgramState::getOrCreateWithGLProgram(glprogram);
 
// attach the ProgramState to a Node
sprite->setGLProgramState( glprogramstate );


接下来就是使用GLProgramState API来添加自定义外观或者属性。


添加自定义外观

1
2
3
4
5
6
7
8
9
10
// setting a float
glprogramstate->setUniformFloat("u_name_1", 0.15f);
 
// setting a vec2
glprogramstate->setUniformVec2("u_name_2", Vec2(0.2, 0.3));
 
// setting a callback
glprogramstate->setUniformCallback("uniform_name_2", [](GLProgram* program, Uniform* uniform){
  glUniform4fv( uniform->location, 10, _buffer);
});


添加自定义属性

1
2
3
4
5
6
7
// setting an attribute pointer
glprogramstate->setVertexAttribPointer("a_position", 2, GL_FLOAT, GL_FALSE, 0, _particleSystem->GetPositionBuffer());
 
// setting a callback
glprogramstate->setVertexAttribCallback("a_color", [](VertexAttrib* vertexAttrib) {
  glVertexAttrib4f(vertexAttrib->index, 0.2, 0.8, 0.7, 1.0);
});


下载并运行例子

复制 Cocos2d-x Samples 仓库,并按照其向导进行。然后运行“LiquidFun – EyeCandy” demo。

1
$ git clone https://github.com/cocos2d/cocos2d-x-samples.git


按照此网站说明,然后运行:

1
2
$ cd samples/LiquidFun-EyeCandy/proj.ios_mac
$ open LiquidFun-EyeCandy.xcodeproj


PS:以上为全文翻译,有不够准确的地方,敬请勘误。

0 0