加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Cocos2D-X shader(一) 渲染机制

发布时间:2020-12-14 16:47:16 所属栏目:百科 来源:网络整理
导读:Cocos2D-X渲染机制 Cocos2D-X 从3.0开始引入了一种新的渲染机制,所有的OpenGL渲染代码不再放到每一个node的draw函数里面,而是通过各种RenderCommand封装起来,然后添加到一个渲染队列里面去,最后在每一帧结束时把所有的这些命令都渲染出来。过程如下图所

Cocos2D-X渲染机制

Cocos2D-X 从3.0开始引入了一种新的渲染机制,所有的OpenGL渲染代码不再放到每一个node的draw函数里面,而是通过各种RenderCommand封装起来,然后添加到一个渲染队列里面去,最后在每一帧结束时把所有的这些命令都渲染出来。过程如下图所示:


引擎不再使用主线程,而是开辟新的线程对队列中的任务统一进行渲染,这有助于并行性,利用多核处理器提升渲染的效率。每个渲染任务都有个Key值,渲染队列依据Key值排序,依据优先级进行渲染。

具体Key值的定义,可以阅读这里。

Cocos2D-X渲染代码实现

了解Cocos2D-X的渲染机制后,用代码实现自己想要渲染的图形就变得容易了。首先是上节提到的RenderCommand,他的作用是将渲染函数封装到渲染队列中去。Cocos提供了 CustomCommand类(继承自 RenderCommand)来实现用户自定义调用openGL命令。通过CustomCommand,我们就能绑定自己写的OpenGL代码函数了。但是,封装之后,渲染指令并不会执行,这是因为我们还没有向RenderQueue发送渲染指令。
Cocos2D-X中Node类定义了虚函数 virtual void visit(Renderer *renderer,const Mat4& parentTransform,uint32_t parentFlags);遍历所有子节点,并且循环递归得发送它们的渲染指令。Layer继承自Node,因此我们可以重载visit函数,使用CustomCommand来发送自定义的渲染指令。
接下来就是定义自己的渲染函数(onDraw),使用OpenGL ES 2.0来实现自己的图形。
新建一个测试工程,具体代码如下:
头文件
#include "cocos2d.h"
USING_NS_CC;

class HelloWorld : public cocos2d::Layer
{
public:
        //其他默认函数省略

	//重载visit函数
	virtual void visit(Renderer* renderer,uint32_t parentFlags) override;
	//自定义渲染函数
	void onDraw();

private:
	//渲染命令封装类
	CustomCommand _command;
};
源文件:
bool HelloWorld::init()
{
    if ( !Layer::init() )
    {
        return false;
    }

	//<span style="color:#ff0000;">从Cocos2D-X的shader缓存中取出一个带有position和color顶点属性的shader,然后传给HelloWorld这个Layer!!!</span>
	this->setGLProgram(GLProgramCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_COLOR));
    
    return true;
}

void HelloWorld::visit(Renderer* renderer,uint32_t parentFlags)
{
	//<span style="color:#ff0000;">如果不调用父类的visit函数,那么当你往HelloWorldScene里面添加节点的时候,它们是不会被渲染出来的!!!</span>
	Layer::visit(renderer,parentTransform,parentFlags);
	_command.init(_globalZOrder);
	_command.func = CC_CALLBACK_0(HelloWorld::onDraw,this);
	Director::getInstance()->getRenderer()->addCommand(&_command);
}

void HelloWorld::onDraw()
{
   //获得当前HelloWorld的shader
    auto glProgram = getGLProgram();
   //使用此shader
    glProgram->use();
   //设置该shader的一些内置uniform,主要是MVP,即model-view-project矩阵
    glProgram->setUniformsForBuiltins();

    auto size = Director::getInstance()->getWinSize();
    //指定将要绘制的三角形的三个顶点,分别位到屏幕左下角,右下角和正中间的顶端
    float vertercies[] = { 0,//第一个点的坐标
                            size.width,//第二个点的坐标
                           size.width / 2,size.height};  //第三个点的坐标
    //指定每一个顶点的颜色,颜色值是RGBA格式的,取值范围是0-1
    float color[] = { 0,1,//第一个点的颜色,绿色
                        1,//第二个点的颜色,红色
                         0,1};  //第三个点的颜色, 蓝色
    //激活名字为position和color的vertex attribute
    GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POSITION | GL::VERTEX_ATTRIB_FLAG_COLOR);
    //分别给position和color指定数据源
    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION,2,GL_FLOAT,GL_FALSE,vertercies);
    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR,4,color);
    //绘制三角形,所谓的draw call就是指这个函数调用
    glDrawArrays(GL_TRIANGLES,3);
    //通知cocos2d-x 的renderer,让它在合适的时候调用这些OpenGL命令
    CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,3);
    //如果出错了,可以使用这个函数来获取出错信息
    CHECK_GL_ERROR_DEBUG();
}
运行结果:

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读