LoginSignup
18
17

More than 5 years have passed since last update.

cocos2d-x Glowエフェクト

Last updated at Posted at 2015-12-23

cocos2d-x Advent Calendar21日目の記事です。

はじめに

今回はアウトラインを色付けるサンプルを元に、Glowエフェクトっぽいモノを作っていきます。

Glowエフェクトとは、その名の通り光る演出です。

フラグメントシェーダーの用意

早速ですが、サンプルのフラグメントシェーダーを元にGlowエフェクトっぽく書いたのが下記になります。

glow.fsh
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;

uniform float u_ctime;
uniform float u_threshold;
uniform float u_radius;
uniform vec4  u_outlineColor;

void main() {
    float radius = u_radius;

    vec4 accum  = vec4(0.0);
    vec4 normal = vec4(0.0);

    normal = texture2D(CC_Texture0, v_texCoord);

    for(float i = 1.0; i <= radius; i += 1.0) {
        accum += texture2D(CC_Texture0, vec2(v_texCoord.x - 0.01 * i, v_texCoord.y - 0.01 * i));
        accum += texture2D(CC_Texture0, vec2(v_texCoord.x + 0.01 * i, v_texCoord.y - 0.01 * i));
        accum += texture2D(CC_Texture0, vec2(v_texCoord.x + 0.01 * i, v_texCoord.y + 0.01 * i));
        accum += texture2D(CC_Texture0, vec2(v_texCoord.x - 0.01 * i, v_texCoord.y + 0.01 * i));
    }

    accum.rgb =  u_outlineColor.rgb * u_outlineColor.a * accum.a * 0.95;
    float opacity = ((1.0 - normal.a) / radius) * (u_ctime / u_threshold);

    normal = (accum * opacity) + (normal * normal.a);

    gl_FragColor = v_fragmentColor * normal;
}

このフラグメントシェーダーをSpriteに適用させてみます。
バーテックスシェーダーにはccPositionTextureColor_noMVP_vertを使用します。

HelloWorldScene.cpp

bool HelloWorld::init()
{

    // ... 省略

    auto sprite = Sprite::create("HelloWorld.png");
    sprite->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));

    Vec4 color(0.5f, 0.5f, 0.5f, 1.0f);
    m_ctime = 0.01f;  // メンバ変数
    GLfloat gtime = 1.0f;
    GLfloat radius = 5.0f;

    auto fileUtiles = FileUtils::getInstance();
    auto fragmentFullPath = fileUtiles->fullPathForFilename("shaders/glow.fsh");
    auto fragSource = fileUtiles->getStringFromFile(fragmentFullPath);

    auto glprogram = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource.c_str());
    auto glProgramState = GLProgramState::getOrCreateWithGLProgram(glprogram);

    glProgramState->setUniformVec4("u_outlineColor", color);
    glProgramState->setUniformFloat("u_ctime", m_ctime);
    glProgramState->setUniformFloat("u_threshold", gtime);
    glProgramState->setUniformFloat("u_radius", radius);

    sprite->setGLProgramState(glProgramState);

    glProgramState->setUniformCallback("u_ctime", CC_CALLBACK_2(HelloWorld::callbackColor, this));

    this->addChild(sprite, 1);

    return true;
}

void HelloWorld::callbackCTime(GLProgram* glProgram, Uniform* uniform)
{
    m_ctime += 0.05f;
    glProgram->setUniformLocationWith1f(uniform->location, (sin(m_ctime) + 1)/2);
}

完成イメージ

setUniformCallback が非常に便利ですね。

色を変化させオーラ感を出す

同じフラグメントシェーダーを利用します。

HelloWorldScene.cpp
bool HelloWorld::init()
{

    // ... 省略

    auto sprite = Sprite::create("HelloWorld.png");
    sprite->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));

    Vec4 color(0.5f, 0.5f, 0.5f, 1.0f);
    GLfloat ctime = 1.0f;
    GLfloat gtime = 1.0f;
    GLfloat radius = 5.0f;

    auto fileUtiles = FileUtils::getInstance();
    auto fragmentFullPath = fileUtiles->fullPathForFilename("shaders/glow.fsh");
    auto fragSource = fileUtiles->getStringFromFile(fragmentFullPath);

    auto glprogram = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource.c_str());
    auto glProgramState = GLProgramState::getOrCreateWithGLProgram(glprogram);

    glProgramState->setUniformVec4("u_outlineColor", color);
    glProgramState->setUniformFloat("u_ctime", ctime);
    glProgramState->setUniformFloat("u_threshold", gtime);
    glProgramState->setUniformFloat("u_radius", radius);

    sprite->setGLProgramState(glProgramState);

    glProgramState->setUniformCallback("u_outlineColor", CC_CALLBACK_2(HelloWorld::callbackColor, this));

    this->addChild(sprite, 1);

    return true;
}

void HelloWorld::callbackColor(GLProgram* glProgram, Uniform* uniform)
{
    float r = CCRANDOM_0_1();
    float g = CCRANDOM_0_1();
    float b = CCRANDOM_0_1();
    float a = 1.0f;

    glProgram->setUniformLocationWith4f(uniform->location, r, g, b, a);
}

完成イメージ

以上になりますが、それっぽくなったでしょうか?
GLSLを勉強するなら、最近だとWebGLから入るのが環境に左右されず本質を勉強出来そうで良さそうですね。

ps.

Advent Calendar大遅刻組です...、申し訳ありませんん。
cocos2d-x Advent Calendar 過疎り気味なので開いている日にでも投稿します。。

18
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
17