【问题标题】:how to set different texture to sprites sharing one shader in cocos2d如何在 cocos2d 中为共享一个着色器的精灵设置不同的纹理
【发布时间】:2014-09-09 11:12:54
【问题描述】:

我正在制作具有 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是如何管理不同精灵的shader的状态和制服的,可能直接继承CCSprite,覆盖“draw”,自己管理纹理可以解决问题,但有点复杂。

有更好的想法吗?

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

更新:

我发现我可以使用 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有关系吗?

【问题讨论】:

  • TEXTURE1TEXTURE2 纹理单元可能会被稍后的另一个 GL 操作覆盖(它们经常使用)。您可能必须在 GL 绘制之前设置 TEXTURE1TEXTURE2 单位。我有一个类似的问题。我的解决方案是简单地将纹理单元设置为TEXTURE3TEXTURE4,因为我不知道 API 的其他部分没有设置这些纹理单元,而且在绘制之前我无法访问 GL 状态。
  • @PeqNP 你是对的,我的解决方案是为不同的雨滴重新创建相同的着色器。幸运的是,我只有 4 种不同的雨滴纹理,这意味着我只需使用不同的纹理创建 4 次相同的着色器,并且所有使用相同纹理的雨滴都可以使用相同的着色器。但是如果每个雨滴都有不同的纹理,我不知道如何处理。

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


【解决方案1】:

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


我所做的是:

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。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-30
    • 1970-01-01
    • 2014-11-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多