Cocos2d-x shader is using invalid offset on texturepacker imported spriteframe

321 Views Asked by At

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));
2

There are 2 best solutions below

0
On BEST ANSWER

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;
}
2
On

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.