How to fix jittering sprites in cocos2d-x

Andreas Löw
How to fix jittering sprites in cocos2d-x

Introduction

When using TexturePacker with Cocos2D-x, users may sometimes encounter wobbling, shaking or jittering sprites. This can be frustrating and reduces the quality of the game. In this tutorial, we will explain the causes of wobbling sprites and provide step-by-step instructions for fixing this issue.

The Role of Shader Precision

A sprite is a two-dimensional image used in games to represent characters, objects, and other elements. To render a sprite on the screen, Cocos2D-x uses the 3D graphics hardware of the device the game is running on.

In Cocos2D-x, shaders are used to calculate the colors of pixels in a sprite for rendering on the screen. Shaders can be used with different precisions - lowp, mediump, or highp. The table below shows the range of values and fractional accuracy for each level of precision:

PrecisionRange of ValuesFractional accuracy
lowp(-2,2)2^(-8)=0.00390625
mediump(-2^(14),2^(14))2^(-10)=0.0009765625
highp(-2^(62), 2^(62))2^(-16)=0.0000152587

As you can see, the lowp precision has the smallest range of values and the least accurate calculations. The highp precision has the largest range of values and the most accurate calculations. The mediump precision falls in between these two levels of precision.

Cocos2D-x's standard shaders use mediump. This can cause problems because the fractional accuracy of this precision can only address single pixels up to a texture size of 1024. With a texture size of 2048, only every 2nd pixel can be addressed precisely.

How to fix jittering sprites in cocos2d-x

To fix this issue in cocos2d-x, you have two options:

  1. Reduce the sprite sheet size to 1024: This is quite surely not the solution you want to use because this size puts hard restrictions on how you use the sprite sheets.

  2. Modify the shaders to use high precision: This option is easy to implement, but the shaders might not work on older devices that do not support high precision.

I was not able to get any statistics how many old devices do not support highp. However, the fact that cocos2d-x still uses the mediump in their shaders leads to the conclusion that there must be at least some...

Modifying the shaders

There are two options for modifying the shaders in cocos2d-x. The first is to modify the shaders directly in cocos2d-x, but this means that you will have to fix the shaders each time you update cocos2d in your project. The advantage of this method is that you don't have to change your source code.

The second option is to set a custom shader on the SpriteBatchNode you are using to render the sprites. This allows you to make changes to the shaders without affecting the cocos2d-x code, but it means that you will have to set them everywhere you use them.

To ensure that the shaders work on as many devices as possible, you can wrap the precision settings with an if-def. This will allow the high precision settings to be used only on devices that support them, while ensuring that the shaders will still work on older devices that do not support high precision. This means that the jittering sprites may still be visible on some devices, but it is a trade-off that you may be willing to accept in order to ensure compatibility with a wider range of devices.

In the vertex shaders (found under cocos/2d/renderer/shaders) change

varying mediump vec2 v_texCoord;

to

#ifdef GL_FRAGMENT_PRECISION_HIGH
varying highp vec2 v_texCoord;
#else
varying mediump vec2 v_texCoord;
#endif

In positionTextureColor.vert which is used by the SpriteBatchNode this would look like this:

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

uniform highp mat4 u_MVPMatrix;

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

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

Conclusion

In conclusion, jittering sprites in Cocos2D-x can be fixed by modifying the shaders to use high precision. This can be done by modifying the shaders directly in Cocos2D-x, or by setting a custom shader on the SpriteBatchNode being used to render the sprites.

It is important to note that using high precision shaders may not work on all devices, but the esimated number of devices it does not work on should be quite small. By following the steps outlined in this tutorial, you can fix jittering sprites and improve the quality of your games.