0

I'm trying to implement a shader for grass in cocos2d-x. The shader works OK on texture loaded with Sprite::create() and it looks like this:

https://i.stack.imgur.com/Rv4rd.png

The problem is that if I'm using Sprite::createWithSpriteFrameName() and applying the same shader it looks like the offsets are wrong when calculating height also because it is moving at a larger degree, like it is using the height of the full texture from plist file:

https://i.stack.imgur.com/of6Ku.png

Here is the shader code:

VSH

attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;

#ifdef GL_ES
varying lowp vec4 v_fragmentColor;
varying mediump vec2 v_texCoord;
#else
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
#endif

void main()
{
    gl_Position = CC_PMatrix * a_position;
    v_fragmentColor = a_color;
    v_texCoord = a_texCoord;
}

FSH

#ifdef GL_ES
precision mediump float;
#endif

varying vec2 v_texCoord;

uniform float speed;
uniform float bendFactor;

void main()
{
    float height = 1.0 - v_texCoord.y;
    float offset = pow(height, 2.5);

    offset *= (sin(CC_Time[1] * speed) * bendFactor);

    gl_FragColor = texture2D(CC_Texture0, fract(vec2(v_texCoord.x + offset, v_texCoord.y))).rgba;
}

If what is happening is not clear I can provide some videos. Thank you.

EDIT

Here is the code used to generate the grass sprite:

// Smaller grass
auto grass2 = Sprite::createWithSpriteFrameName("grass2.png");
grass2->setAnchorPoint(Vec2(0.5f, 0));
grass2->setPosition(Vec2(230, footer1->getContentSize().height * 0.25f));
// Apply "grass" shader
grass2->setGLProgramState(mat->getTechniqueByName("grass")->getPassByIndex(0)->getGLProgramState()->clone());
grass2->getGLProgramState()->setUniformFloat("speed", RandomHelper::random_real(0.5f, 3.0f));
grass2->getGLProgramState()->setUniformFloat("bendFactor", RandomHelper::random_real(0.1f, 0.2f));
Daniel Gorgan
  • 83
  • 2
  • 5

2 Answers2

0

It's hard to tell what's happening without seeing more of your code...

If I should guess I would say that the problem is related to trimming in TexturePacker.

If you set TrimMode=Trim the sprite is stripped from transparency. This makes the sprite smaller. Cocos2d-x also only renders the smaller portion of the sprite, compensating the difference between the original sprite and the trimmed sprite with an offset vector.

I propose that you either try not to trim the sprite or try polygon trimming.

Andreas Löw
  • 1,002
  • 8
  • 15
  • Yes indeed that was a part of the problem. With no trimming it looks ok. But there also is another problem. Because grass swing effect is based on texture height and because in the generated texture one is below the other, the texture that is below is having a less swinging effect. So I'm guessing the height in the fragment shader is calculated wrong, by using the entire texture height from texturepacker. Is there a way to avoid this? – Daniel Gorgan Feb 23 '16 at 22:04
  • You could try passing the real sizes to the shader. They are available from grass2->getSpriteFrame(). With this you should be able to compensate for the trimmed pixels. – Andreas Löw Feb 25 '16 at 06:51
0

The problem was with TexturePacker trimming but also with offsets in v_texCoord.

The solution was to calculate offsets in cocos2d-x and pass them to shader.

I calculated offsets using following code:

Rect grass2Offset(
    grass2->getTextureRect().origin.x / grass2->getTexture()->getContentSize().width,
    grass2->getTextureRect().origin.y / grass2->getTexture()->getContentSize().height,
    grass2->getTextureRect().size.width / grass2->getTexture()->getContentSize().width,
    grass2->getTextureRect().size.height / grass2->getTexture()->getContentSize().height
);

Next I pass the height offset and scale to shader as uniforms using:

grass2->getGLProgramState()->setUniformFloat("heightOffset", grass2Offset.origin.y);
grass2->getGLProgramState()->setUniformFloat("heightScale", 1 / grass2Offset.size.height);

Last, the shader is using the offset like this:

#ifdef GL_ES
precision mediump float;
#endif

varying vec2 v_texCoord;

uniform float speed;
uniform float bendFactor;
uniform float heightOffset;
uniform float heightScale;

void main()
{
    float height = 1.0 - (v_texCoord.y - heightOffset) * heightScale;
    float offset = pow(height, 2.5);

    offset *= (sin(CC_Time[1] * speed) * bendFactor);

    gl_FragColor = texture2D(CC_Texture0, fract(vec2(v_texCoord.x + offset, v_texCoord.y))).rgba;
}
Daniel Gorgan
  • 83
  • 2
  • 5