cocos2dx(3.X)中使用shader

Posted 空幻无灵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cocos2dx(3.X)中使用shader相关的知识,希望对你有一定的参考价值。

 
 
 

原文链接:http://blog.csdn.net/xufeng0991/article/details/47256583

一 shader的基本概念

1 什么是shader

shader即着色器,就是专门用来渲染3D图形的一种技术。 
通过shader,可以自己编写显卡渲染画面的算法,使画面更漂亮、更逼真。

2 shader分类

shader又分两种,一种是顶点shader(3D图形是由三角形组成的,顶点shader就是计算顶点位置,并为后期像素渲染做准备的), 
另一种是像素shader,就是以像素为单位,计算光照、颜色的一系列算法。

3 shader语言

几个不同的图形API有各自的shader语言: 
在DirectX中,顶点shader叫做vertex shader,像素shader叫做pixel shader; 
在OpenGL中,顶点shader也叫做vertex shader,但像素shader叫做fragment shader。 
此外显卡芯片厂商NVIDIA还推出CG显卡编程语言,也支持shader。

二 shader开发流程

技术分享

  1. 编写vertex Shader和fragment shader源码。
  2. 创建两个shader 实例:GLuint glCreateShader(GLenum type); [gl.createShader]
  3. 给Shader实例指定源码。 glShaderSource [gl.shaderSource]
  4. 编译shaer源码 void glCompileShader(GLuint shader) [gl.compileShader]
  5. 创建shader program – GLuint glCreateProgram(void) [gl.createProgram]
  6. 绑定shader到program 。 void glAttachShader(GLuint program, GLuint shader)。每个program必须绑定一个vertex shader 和一个fragment shader。 [gl.attachShader]
  7. 链接program 。 void glLinkProgram(GLuint program) [gl.linkProgram]
  8. 使用porgram 。 void glUseProgram(GLuint program) [gl.useProgram]

对于使用独立shader编译器编译的二进制shader代码,可使用glShaderBinary来加载到一个shader实例中。

三 shader程序

1 语言glsl

glsl即OpenGL Shading Language(OpenGL着色语言),是用来在OpenGL中着色编程的语言。

2 顶点着色器

// vert.vsh
// 顶点着色器,VBO/VAO提供的每个顶点都执行一遍顶点着色器,输出一个varying和gl_Position等

// 变量修饰:
// attribute: 只读,随不同顶点变化的全局变量,应用程序传入,只能用在顶点着色器中
// uniform: 只读,随不同图元变化的全局变量,应用程序传入,
// varying: 在顶点shader中可写,在片断shader中只读,用于在顶点着色器和片段着色器之间传递数据

// 输入: attribute, 输出:varying+gl_positon + gl_Position + gl_PointSize

attribute vec4 a_position;
attribute vec4 a_color;

varying vec4 v_fragmentColor;

// 每一个Shader程序都有一个main函数
void main()
{
    // gl开头的变量名是系统内置的变量
    gl_Position = CC_MVPMatrix * a_position;// 每个点固有的Varying,表示点的空间位置。
    v_fragmentColor = a_color;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

3 片段着色器

// frag.fsh
// 片元着色器,光栅化输出的每个片元都执行一遍片段着色器,生成一个或多个(多重渲染)颜色值作为输出
// 输入: varying, 输出: gl_FragColor + gl_FragDepth

//用于在顶点着色器和片段着色器之间传递数据,因此类型必须完全一直
varying vec4 v_fragmentColor;

// 每一个Shader程序都有一个main函数
void main()
{
    // gl开头的变量名是系统内置的变量
    gl_FragColor = v_fragmentColor;// gl_FragColor 定义最终画在屏幕上面的像素点的颜色
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

三 程序调用

新建cocos工程,将上面两个文件放到Resource/shaders文件夹下,修改代码如下:

// .h
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"

USING_NS_CC;

class HelloWorld : public cocos2d::Layer
{
public:
    static cocos2d::Scene* createScene();

    virtual bool init();

    CREATE_FUNC(HelloWorld);

    virtual void visit(Renderer *renderer, const Mat4& parentTransform, uint32_t parentFlags);
    void onDraw();

private:
    CustomCommand _customCommand;

    GLuint _vao;
    GLuint _vertVBO;
    GLuint _colorVBO;
};

#endif // __HELLOWORLD_SCENE_H__
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
// .cpp
#include "HelloWorldScene.h"

USING_NS_CC;

Scene* HelloWorld::createScene()
{
    // ‘scene‘ is an autorelease object
    auto scene = Scene::create();

    // ‘layer‘ is an autorelease object
    auto layer = HelloWorld::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if ( !Layer::init() )
    {
        return false;
    }

    /*
    在OpenGL中,GLSL的shader使用的流程与C语言相似,每个shader类似一个C模块,首先需要单独编译(compile),
    然后一组编译好的shader连接(link)成一个完整程序。
    */
    auto program = CCGLProgram::createWithFilenames("shader/vert.vsh", "shader/frag.fsh");
    program->link();
    program->updateUniforms();
    this->setGLProgram(program);

    /*
    使用VBO和VAO的步骤都差不多,步骤如下:
    1 glGenXXX
    2 glBindXXX
    */

    // 创建和绑定vao
    glGenVertexArrays(1, &_vao); 
    glBindVertexArray(_vao);

    // 创建和绑定vbo
    glGenBuffers(1, &_vertVBO);// 生成VBO
    glBindBuffer(GL_ARRAY_BUFFER, _vertVBO); // 关联到当前的VAO

    auto size = Director::getInstance()->getVisibleSize();
    float vertercies[] = {// 三角形顶点位置
        0, 0, // 第1个点坐标
        size.width, 0, // 第2个点坐标
        size.width / 2, size.height // 第3个点坐标
    };

    // 给VBO设置数据
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertercies), vertercies, GL_STATIC_DRAW);

    // 获得变量a_position在内存中的位置
    GLuint positionLocation = glGetAttribLocation(program->getProgram(), "a_position");
    glEnableVertexAttribArray(positionLocation);
    // 提交包含数据的数组指针
    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);

    // 设置颜色
    float color[] = {// 三角形顶点颜色RGBA
        0, 1, 0, 1,
        1, 0, 0, 1,
        0, 0, 1, 1
    };
    glGenBuffers(1, &_colorVBO);
    glBindBuffer(GL_ARRAY_BUFFER, _colorVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(color), color, GL_STATIC_DRAW);

    // 获得变量a_color在内存中的位置
    GLuint colorLocation = glGetAttribLocation(program->getProgram(), "a_color");
    glEnableVertexAttribArray(colorLocation);
    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);

    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    return true;
}

void HelloWorld::visit(cocos2d::Renderer *renderer, const Mat4 &transform, uint32_t parentFlags)
{
    Layer::draw(renderer, transform, parentFlags);

    _customCommand.init(_globalZOrder);
    _customCommand.func = CC_CALLBACK_0(HelloWorld::onDraw, this);
    renderer->addCommand(&_customCommand);
}

void HelloWorld::onDraw()
{
    auto glProgram = getGLProgram();
    glProgram->use();
    glProgram->setUniformsForBuiltins();

    /*
    VAO里的VBOs都设置好了以后,在绘制的地方只需要设置当前绑定的VAO是哪个,
    就能按照初始化的VAO来绘制,即调用glDrawArrays
    */

    // 设置当前绑定的VAO
    glBindVertexArray(_vao);

    // 绘制三角形
    glDrawArrays(GL_TRIANGLES, 0, 3);

    // 解绑当前VAO,但并不释放
    glBindVertexArray(0);

    CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, 3);
    CHECK_GL_ERROR_DEBUG();
}





以上是关于cocos2dx(3.X)中使用shader的主要内容,如果未能解决你的问题,请参考以下文章

转 自动Shader优化器glsl_optimizer的编译与在cocos2dx中使用

cocos2dx 编写shader 遇到 溢出问题

cocos2dx creator canvas 怎么使用shader

cocos2dx中用shader实现折射效果

Cocos2dx-3.x 中CCCamera相机类详解及源码分析

关于cocos2dx 3.x版本移植 dragonbones 4.5版本的解决方案