I'm trying to mask a sprite so I wrote a simple fragment shader that renders only the pixels that are not hidden under another texture (the mask). The problem is that it seems my texture has its y-coordinate offset after passing through the shader.

This is the init method of the sprite (GroundZone) I want to mask:

bool GroundZone::initWithSize(Size size) {

    // [...]

    // Setup the mask of the sprite
    m_mask = RenderTexture::create(textureWidth, textureHeight);

    Texture2D *maskTexture = m_mask->getSprite()->getTexture();
    maskTexture->setAliasTexParameters(); // Disable linear interpolation on the mask

    // Load the custom frag shader with a default vert shader as the sprite’s program
    FileUtils *fileUtils = FileUtils::getInstance();
    string vertexSource = ccPositionTextureA8Color_vert;
    string fragmentSource = fileUtils->getStringFromFile(

    GLProgram *shader = new GLProgram;
    shader->initWithByteArrays(vertexSource.c_str(), fragmentSource.c_str());

    shader->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
    shader->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORDS);

    int maskTexUniformLoc = shader->getUniformLocationForName("u_alphaMaskTexture");
    shader->setUniformLocationWith1i(maskTexUniformLoc, 1);


    // [...]

These are the custom drawing methods for actually drawing the mask over the sprite:
You need to know that m_mask is modified externally by another class, the onDraw() method only render it.

void GroundZone::draw(Renderer *renderer, const kmMat4 &transform, bool transformUpdated) {

    m_renderCommand.func = CC_CALLBACK_0(GroundZone::onDraw, this, transform, transformUpdated);

    Sprite::draw(renderer, transform, transformUpdated);

void GroundZone::onDraw(const kmMat4 &transform, bool transformUpdated) {

    GLProgram *shader = this->getShaderProgram();

    glBindTexture(GL_TEXTURE_2D, m_mask->getSprite()->getTexture()->getName());

Below is the method (located in another class, GroundLayer) that modify the mask by drawing a line from point start to point end. Both points are in Cocos2d coordinates (Point (0,0) is down-left).

void GroundLayer::drawTunnel(Point start, Point end) {

    // To dig a line, we need first to get the texture of the zone we will be digging into. Then we get the
    // relative position of the start and end point in the zone's node space. Finally we use the custom shader to
    // draw a mask over the existing texture.
    for (auto it = _children.begin(); it != _children.end(); it++) {

        GroundZone *zone = static_cast<GroundZone *>(*it);

        Point nodeStart = zone->convertToNodeSpace(start);
        Point nodeEnd = zone->convertToNodeSpace(end);

        // Now that we have our two points converted to node space, it's easy to draw a mask that contains a line
        // going from the start point to the end point and that is then applied over the current texture.
        Size groundZoneSize = zone->getContentSize();
        RenderTexture *rt = zone->getMask();
        rt->begin(); {

            // Draw a line going from start and going to end in the texture, the line will act as a mask over the
            // existing texture
            DrawNode *line = DrawNode::create();
            line->drawSegment(nodeStart, nodeEnd, 20, Color4F::RED);

        } rt->end();

Finally, here's the custom shader I wrote.

#ifdef GL_ES
precision mediump float;

varying vec2 v_texCoord;
uniform sampler2D u_texture;
uniform sampler2D u_alphaMaskTexture;

void main() {

    float maskAlpha = texture2D(u_alphaMaskTexture, v_texCoord).a;
    float texAlpha = texture2D(u_texture, v_texCoord).a;
    float blendAlpha = (1.0 - maskAlpha) * texAlpha; // Show only where mask is invisible

    vec3 texColor = texture2D(u_texture, v_texCoord).rgb;

    gl_FragColor = vec4(texColor, blendAlpha);


I got a problem with the y coordinates. Indeed, it seems that once it has passed through my custom shader, the sprite's texture is not at the right place:

Without custom shader (the sprite is the brown thing):

Without custom shader

With custom shader:

With custom shader

What's going on here? Thanks :)


It looks like after passing through the shader when I set the position of the sprite I set it in points, with (0,0) being in the top-right. Indeed, when I do sprite->setPosition(320, 480), the sprite is perfectly placed at the top of the screen.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.