【cocos2d-x 源码解析】shader 实现

本文详细解析了cocos2d-x中与shader相关的源码,包括GLProgramCache、GLProgram、GLProgramState和GLProgramStateCache的实现。GLProgramCache作为着色器程序的缓冲区,负责加载和管理默认及自定义的着色器。GLProgram是着色器程序的核心,通过initWithByteArrays进行编译和链接。GLProgramState是对GLProgram的封装,用于节点与着色器的绑定,通过GLProgramStateCache进行管理,确保多节点共享同一着色器时的效率和一致性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文件结构

cocos2d-x 与 shader 相关的代码在 renderer 目录下

|-cocos
    |-renderer
        |-CCGLProgram.h
        |-CCGLProgram.cpp
        |-CCGLProgramCache.h
        |-CCGLProgramCache.cpp
        |-CCGLProgramState.h
        |-CCGLProgramState.cpp
        |-CCGLProgramStateCache.h
        |-CCGLProgramStateCache.cpp
        |-...
        |-ccShader_PositionColor.vert
        |-ccShaer_PositionColor.frag
        |-ccShader_UI_Gray.frag
        |-...

其中比较重要的几个类是 GLProgram,GLProgramCache,GLProgramState 和 GLProgramStateCache;除此之外还定义一些默认的着色器程序,.vert 后缀的文件是顶点着色器程序,.frag 后缀的文件是片段着色器程序。下面通过解析这几个主要类了解着色器的创建过程和使用方法

GLProgramCache

首先从 GLProgramCache 这个类入手,这个类是着色器 Program 的一个缓冲区,也就是说这个类保存了创建好的着色器程序,使用的时候直接从这缓冲中取 Program 即可。和其它缓冲类一样,GLProgramCache 也是单例模式

GLProgramCache* GLProgramCache::getInstance()
{
    if (!_sharedGLProgramCache) {
        _sharedGLProgramCache = new (std::nothrow) GLProgramCache();
        if (!_sharedGLProgramCache->init())
        {
            CC_SAFE_DELETE(_sharedGLProgramCache);
        }
    }
    return _sharedGLProgramCache;
}

第一次调用 getInstance 方法会先创建一个 GLProgramCache 实例,然后调用 init 方法进行初始化

bool GLProgramCache::init()
{
    loadDefaultGLPrograms();

    auto listener = EventListenerCustom::create(Configuration::CONFIG_FILE_LOADED, [this](EventCustom* event){
        reloadDefaultGLProgramsRelativeToLights();
    });

    Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(listener, -1);

    return true;
}

init 方法一个很重要的功能就是调用 loadDefaultGLPrograms 方法,这个方法创建所有默认的着色器程序

void GLProgramCache::loadDefaultGLPrograms()
{
    // Position Texture Color shader
    GLProgram *p = new (std::nothrow) GLProgram();
    loadDefaultGLProgram(p, kShaderType_PositionTextureColor);
    _programs.insert( std::make_pair( GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR, p ) );

    // Position Texture Color without MVP shader
    p = new (std::nothrow) GLProgram();
    loadDefaultGLProgram(p, kShaderType_PositionTextureColor_noMVP);
    _programs.insert( std::make_pair( GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP, p ) );

    //...
}

loadDefaultGLPrograms 创建 cocos 自带的所有着色器程序,首先创建一个 GLProgram,然后调用 loadDefaultGLProgram 进行内容填充,再插入到 _programs 字典中去

void GLProgramCache::loadDefaultGLProgram(GLProgram *p, int type)
{
    switch (type) {
        case kShaderType_PositionTextureColor:
            p->initWithByteArrays(ccPositionTextureColor_vert, ccPositionTextureColor_frag);
            break;
        case kShaderType_PositionTextureColor_noMVP:
            //...
        //...
        default:
            CCLOG("cocos2d: %s:%d, error shader type", __FUNCTION__, __LINE__);
            return;
    }
    p->link();
    p->updateUniforms();

    CHECK_GL_ERROR_DEBUG();
}

loadDefaultGLProgram 用于创建单个着色器程序,它接收两个参数,一个是事先创建出来的 GLProgram,一个是着色器类型;然后调用 GLProgram 的 initWithByteArrays 进行内容填充,根据不同的 type 传递不同的着色器源文件,ccPositionTextureColor_vert 这些变量在着色器源文件中定义,即上面说到的 .vert 和 .frag 文件中定义,它们的值是一个字符串,也就是着色器的源代码。这里为什么可以直接使用 ccPositionTextureColor_vert 这些变量呢?这是因为这些变量都是全局变量,而且在 ccShaders.cpp 中添加了所有的引用,ccShaders.cpp 的内容如下

#include "renderer/ccShaders.h"

#d
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值