如何在cocos2d中为sprite共享一个着色器设置不同的纹理

时间:2014-09-09 11:12:54

标签: opengl opengl-es lua cocos2d-x shader

我制作了具有4种不同雨滴纹理的雨景,每个雨滴精灵在创建并添加到屏幕时随机选择雨滴纹理。所有雨滴精灵共享一个相同的着色器。

问题是,当我在屏幕上添加一个新的雨滴时,所有添加到场景中的前雨滴都会改变其纹理,使其与新的雨滴相同。

我的代码如下:

local function addOneRainDrop()
    local rainStyleNumber = math.random(1,4)
    local rainDrop = cc.Sprite:create("rainDrop"..tostring(rainStyleNumber)..".png")
    rainShader:use()
    rainShader:updateUniforms()
    rainShader:setUniformsForBuiltins()
    gl.activeTexture(GL_TEXTURE1)    -- here may be the reason
    gl.bindTexture(GL_TEXTURE_2D, rainDrop:getTexture():getName())
    gl.activeTexture(GL_TEXTURE2)
    gl.bindTexture(GL_TEXTURE_2D, rainNormal[rainStyleNumber]:getName())
    gl.activeTexture(GL_TEXTURE0)

    rainDrop:setGLProgram(rainShader)
    rainDropLayer:addChild(rainDrop)
end

在我的着色器中,我只是采样CC_Texture0,CC_Texture1,CC_Texture2和输出颜色。我认为这不是着色器的问题。我不知道Cocos2d如何管理它的着色器状态和不同精灵的制服,可能直接从CCSprite继承,覆盖"绘制"并通过我自己管理纹理可以解决问题,但它有点复杂。

有更好的想法吗?

=============================================== ==============================

更新:

我发现我可以使用GLProgramState为每个精灵存储制服。引自cocos2d的网站

  

GLProgram可以被数千个节点使用,但是如果要使用不同的统一值,那么每个节点都需要自己的GLProgramState

所以我将代码更改为以下内容:

local function addOneRainDrop()
    local rainStyleNumber = math.random(1,4)
    local rainDrop = cc.Sprite:create("rainDrop"..tostring(rainStyleNumber)..".png")
    local glprogramstate = cc.GLProgramState:getOrCreateWithGLProgram(rainShader);
    glprogramstate:setUniformTexture("rainDrop", rainDrop:getTexture():getName());
    glprogramstate:setUniformTexture("textureBackground", bg:getTexture():getName());
    glprogramstate:setUniformTexture("rainDropNormals", rainNormal[rainStyleNumber]:getName());
    rainDrop:setGLProgramState(glprogramstate);
    rainDropLayer:addChild(rainDrop)
end

不幸的是,所有的精灵仍然使用相同的纹理。这与batchedNode有关吗?

1 个答案:

答案 0 :(得分:0)

您的问题在于使用 getOrCreateWithGLProgram(),它总是返回相同的 GLProgramState ,因为它使用 rainShader 作为密钥进行缓存。 / p>


我所做的是:

1)创建一个创建或返回着色器程序的方法

    static GLProgram* getOrCreateShader(std::string name, const GLchar* vert, const GLchar* frag)
    {
        auto cache = GLProgramCache::getInstance();
        auto prog = cache->getGLProgram(name);
        if(prog == nullptr)
        {
            prog = GLProgram::createWithByteArrays(vert, frag);
            cache->addGLProgram(prog, name);
        }
        return prog;
    }

我的方法从GLchar缓冲区创建一个程序,但您可以创建一个使用磁盘文件的新程序。

2)对于每个精灵,您可以从GLProgram创建一个新的GLProgramState

        auto program = getOrCreateShader("rainShaderName", vertexProgram, fragmentProgram);
        auto programState = GLProgramState::create(program);

        Sprite* sprite = Sprite::create("yourSpriteImage.png");
        programState->setUniformTxeture("u_texture", sprite->getTexture());
        sprite->setGLProgramState(programState);

这样,着色器程序只会创建一次,每个精灵都有一个唯一的GLProgramState。