zoukankan      html  css  js  c++  java
  • 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();
    }
  • 相关阅读:
    第一次结对编程作业
    第一次个人编程作业
    获取file中字段,写入到TXT文件中
    通过file中的字段查询MySQL内容
    MySQL常用语句
    MySQL乱码问题
    脚本数据编码格式转换
    mysql 常用命令操作
    thinkphp项目 Class 'finfo' not found
    POJ3255--次短路
  • 原文地址:https://www.cnblogs.com/lx-hhxxttxs/p/5965162.html
Copyright © 2011-2022 走看看