zoukankan      html  css  js  c++  java
  • Cocos2dx中的opengl使用(一)简单介绍

      引擎提供了CCGLProgram类来处理着色器相关操作,对当前绘图程序进行了封装,其中使用频率最高的应该是获取着色器程序的接口:const GLuint getProgram();

    该接口返回了当前着色器程序的标识符。后面将会看到,在操作OpenGL的时候,我们常常需要针对不同的着色器程序作设置。注意,这里返回的是一个无符号整型的标识符,而不是一个指针或结构引用,这是OpenGL接口的一个风格。对象(纹理、着色器程序或其他非标准类型)都是使用整型标识符来表示的。

    CCGLProgram提供了两个函数导入着色器程序,支持直接从内存的字符串流载入或是从文件中读取。这两个函数的第一个参数均指定了顶点着色器,后一个参数则指定了像素着色器:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. /** Initializes the CCGLProgram with a vertex and fragment with bytes array */  
    2. bool initWithVertexShaderByteArray(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray);  
    3. /** Initializes the CCGLProgram with a vertex and fragment with contents of filenames */  
    4. bool initWithVertexShaderFilename(const char* vShaderFilename, const char* fShaderFilename);  

    仅仅加载肯定是不够的,我们还需要给着色器传递运行时必要的输入数据。在着色器中存在两种输入数据,分别被标识为attribute和uniform。

    attribute变量是应用程序直接传递给顶点着色器的变量,在段着色器中不能访问。它描述的是每个顶点的属性,如位置、法线等,被限制为向量或标量这样的简单结构。必须为每个顶点指定对应的值,这类似于C中的函数参数。

    uniform变量是全局性的,可以同时在顶点着色器和段着色器中访问。在整个渲染流水线中,每个uniform变量都是唯一的,不存在每个像素或顶点需要单独定义的问题,这一点是和C的全局变量类似的。uniform变量的可定义类型会更丰富一些,还可以包括纹理矩阵和纹理,甚至可以通过uniform block自定义复杂的数据类型。

    uniform变量是全局性的,可以同时在顶点着色器和段着色器中访问。在整个渲染流水线中,每个uniform变量都是唯一的,不存在每个像素或顶点需要单独定义的问题,这一点是和C的全局变量类似的。uniform变量的可定义类型会更丰富一些,还可以包括纹理矩阵和纹理,甚至可以通过uniform block自定义复杂的数据类型。

    int glGetUniformLocation(GLuint program, const GLchar* name);

    对uniform变量的设置存在着一系列以"glUniform"为前缀的函数,这些函数的第一个参数为需要设置的参数标识,后面跟若干参数值.

     shader配置文件 .vsh  和 .fsh  

    initWithVertexShaderFilename(const char* vShaderFilename, const char* fShaderFilename)     这里我们可以用到shader配置文件 .vsh  和 .fsh  

    可以参考quick-lua3.3 quicklibquick-srcextrafiltersshader目录下的部分例子,如

    example_MultiTexture.vsh:

    attribute vec4 a_position;
    attribute vec2 a_texCoord;
    attribute vec4 a_color;
    
    #ifdef GL_ES
    varying lowp vec4 v_fragmentColor;
    varying mediump vec2 v_texCoord;
    #else
    varying vec4 v_fragmentColor;
    varying vec2 v_texCoord;
    #endif
    
    void main()
    {
        gl_Position = CC_PMatrix * a_position;
        v_fragmentColor = a_color;
        v_texCoord = a_texCoord;
    }

    example_MultiTexture.fsh:

    #ifdef GL_ES
    precision mediump float;
    #endif
    
    varying vec4 v_fragmentColor;
    varying vec2 v_texCoord;
    
    uniform sampler2D u_texture1;
    uniform float u_interpolate;
    
    void main() {
        vec4 color1 = texture2D(CC_Texture0, v_texCoord);
        vec4 color2 = texture2D(u_texture1, v_texCoord);
        gl_FragColor = v_fragmentColor * mix( color1, color2, u_interpolate);
    }

    OpenGL的渲染管线主要包括:

    1. 准备顶点数据(通过VBO、VAO和Vertex attribute来传递数据给OpenGL)

    2. 顶点处理(这里主要由Vertex Shader来完成,从上图中可以看出,它还包括可选的Tessellation和Geometry shader阶段)

    3. 顶点后处理(主要包括Clipping,顶点坐标归一化和viewport变换)

    4. Primitive组装(比如3点组装成一个3角形)

    5. 光栅化成一个个像素

    6. 使用Fragment shader来处理这些像素

    7. 采样处理(主要包括Scissor Test, Depth Test, Blending, Stencil Test等)。

    OpenGL Shader Language,简称GLSL,它是一种类似于C语言的专门为GPU设计的语言,它可以放在GPU里面被并行运行。
     
    opengl es的着色器有.fsh和.vsh两个文件。这两个文件在被编译和链接后就可以产生可执行程序与GPU交互。
    .vsh 是 vertex shader,用与顶点计算,可以理解控制顶点的位置,在这个文件中我们通常会传入当前顶点的位置,和纹理的坐标。
    例如:
    复制代码
     1 attribute vec4 position; 
     2 attribute vec4 inputTextureCoordinate;
     3 
     4 varying vec2 textureCoordinate;
     5 
     6 precision mediump float;
     7 uniform float overTurn;
     8 
     9 void main()
    10 {
    11 gl_Position = position;
    12     if (overTurn>0.0) {
    13         textureCoordinate = vec2(inputTextureCoordinate.x,overTurn-inputTextureCoordinate.y);
    14     }
    15     else
    16         textureCoordinate = vec2(inputTextureCoordinate.x,inputTextureCoordinate.y);
    17 }
    复制代码

    首先,每一个Shader程序都有一个main函数,这一点和c语言是一样的。

    这里面有两种类型的变量,一种是attribute,另一种是varying.

    attribute是从外部传进来的,每一个顶点都会有这两个属性,所以它也叫做vertex attribute(顶点属性)。

    而varying类型的变量是在vertex shader和fragment shader之间传递数据用的。

    这里的变量命名规则保持跟c一样就行了,注意gl_开头的变量名是系统内置的变量,所以大家在定义自己的变量名时,请不要以gl_开头。

    而CC_MVPMatrix是一个mat4类型的变量,它是在cocos2d-x内部设置进来的。

    即:

    attribute:外部传入vsh文件的变量 每帧的渲染的可变参数 变化率高 用于定义每个点。

    varying:用于 vsh和fsh之间相互传递的参数。

    precision mediump float 定义中等精度的浮点数。

    uniform 外部传入vsh文件的变量 变化率较低 对于可能在整个渲染过程没有改变 只是个常量。

    在main()当overTurn大于0的时候,函数里面做的事情就是将纹理y轴反转。

    vertex shader是作用于每一个顶点的,如果vertex有三个点,那么vertex shader会被执行三次。

    .fsh 是片段shader。在这里面我可以对于每一个像素点进行重新计算。

    复制代码
     1 varying highp vec2 textureCoordinate;
     2 precision mediump float;
     3 uniform sampler2D videoFrame;
     4 
     5 vec4 memoryRender(vec4 color)
     6 {
     7     float gray;
     8     gray = color.r*0.3+color.g*0.59+color.b*0.11;
     9     color.r = gray;
    10     color.g = gray;
    11     color.b = gray;
    12     
    13     color.r += color.r*1.5;
    14     color.g = color.g*2.0;
    15     
    16     if(color.r > 255.0)
    17     color.r = 255.0;
    18     if(color.g > 255.0)
    19     color.g = 255.0;
    20     
    21     return color;
    22 }
    23 
    24 void main()
    25 {
    26     vec4 pixelColor;
    27 
    28     pixelColor = texture2D(videoFrame, textureCoordinate);
    29     
    30     gl_FragColor = memoryRender(pixelColor);
    31 }
    复制代码

    varying highp vec2 textureCoordinate 就是从vsh中传过来了纹理坐标。

    uniform sampler2D videoFrame 是我们真正的纹理贴图。

    texture2D(videoFrame, textureCoordinate) 将纹理中的每个像素点颜色取出到pixelColor。

    可以用memoryRender(pixelColor)将取到像素点重新加工。

    fragment shader中也有一个main函数,同时我们看到这里也声明了一个与vertex shader相同的变量textureCoordinate。前面我们讲过,这个变量是用来在vertex shader和fragment shader之间传递数据用的。所以,它们的参数类型必须完全相同。如果一个是vec3,一个是vec4,shader编译的时候是会报错的。

    而gl_FragColor我们知道它肯定是一个系统内置变量了,它的作用是定义最终画在屏幕上面的像素点的颜色。

    总结:

    对于着色器的编程并不是很困难,完全是C的语法。但是debug比较麻烦,对于类型的约束也很严格,必须是相同类型的才能进行算术运算。我们理解了这两个文件之后,就可以发挥我们的想象对纹理图片做出各种的处理。

    另有人总结:

    vsh 负责搞定像素位置 ,填写  gl_Posizion 变量,偶尔搞定一下点大小的问题,填写 gl_PixelSize。

    fsh 负责搞定像素外观,填写 gl_FragColor ,偶尔配套填写另外一组变量。

    他们都是一个像素运行一次的,也可能运行多次。为了“这一像素”而努力计算。

     程序的版本是cocos2dx 3.0.vs 2012.

    代码如下:

    复制代码
     1 #ifndef  __GLTesting_H_
     2 #define  __GLTesting_H_
     3 
     4 #include "cocos2d.h"
     5 
     6 USING_NS_CC;
     7 
     8 class GLTestingLayer : public cocos2d::Layer
     9 {
    10 public:
    11     static cocos2d::Scene* createScene();
    12     virtual bool init();  
    13     void menuCloseCallback(cocos2d::Ref* pSender);
    14     CREATE_FUNC(GLTestingLayer);
    15     void graySprite(Sprite * sprite);
    16     virtual void visit( Renderer* renderer, const kmMat4 &parentTransform, bool parentTransformUpdated ) override;
    17     void onDraw();
    18 private:
    19     CustomCommand _command;
    20 };
    21 #endif // ! __GLTesting_H_
    复制代码
    复制代码
     1 #include "GLTestingLayer.h"
     2 
     3 cocos2d::Scene* GLTestingLayer::createScene()
     4 {
     5     auto scene = Scene::create();
     6     auto layer = GLTestingLayer::create();
     7     scene->addChild(layer);
     8     return scene;
     9 }
    10 
    11 bool GLTestingLayer::init()
    12 {
    13     if ( !Layer::init() )  
    14     {  
    15         return false;  
    16     }  
    17 
    18     this->setPosition(0,0);
    19     Size visibleSize = Director::getInstance()->getVisibleSize();  
    20     auto sprite = Sprite::create("HelloWorld.png");  
    21     sprite->setAnchorPoint(Point(0.5, 0.5));  
    22     sprite->setPosition(Point(visibleSize.width / 2, visibleSize.height / 2));  
    23     this->addChild(sprite);  
    24     graySprite(sprite);  
    25 
    26     this->setShaderProgram( ShaderCache::getInstance()->getProgram(GLProgram::SHADER_NAME_POSITION_COLOR));
    27 
    28     return true;  
    29 }
    30 
    31 void GLTestingLayer::menuCloseCallback( cocos2d::Ref* pSender )
    32 {
    33 
    34 }
    35 
    36 void GLTestingLayer::graySprite( Sprite * sprite )
    37 {
    38     if(sprite)  
    39     {   
    40         GLProgram * p = new GLProgram();  
    41         p->initWithFilenames("gray.vsh", "gray.fsh");  
    42         p->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);  
    43         p->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR);  
    44         p->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORDS);  
    45         p->link();  
    46         p->updateUniforms();  
    47         sprite->setShaderProgram(p);  
    48     }  
    49 
    50 }
    51 
    52 void GLTestingLayer::visit( Renderer* renderer, const kmMat4 &parentTransform, bool parentTransformUpdated )
    53 {
    54     Layer::visit( renderer, parentTransform, parentTransformUpdated );
    55     _command.init(_globalZOrder);
    56     _command.func = CC_CALLBACK_0(GLTestingLayer::onDraw,this);
    57     Director::getInstance()->getRenderer()->addCommand(&_command);
    58 }
    59 
    60 void GLTestingLayer::onDraw()
    61 {
    62     auto glProgram = this->getShaderProgram();
    63     glProgram->use();
    64     glProgram->setUniformsForBuiltins();
    65     glPointSize( 10.0f);
    66     glColor4f( 0.0f,1.0f,0.0f,1.0f);
    67     auto size = Director::getInstance()->getWinSize();
    68 
    69     float vertercies[] = { 100,100,
    70                             200, 200,
    71                             300, 100 };
    72     float color[] = { 1,0,0,1,
    73                       0,1,0,1,
    74                       0,0,1,1 };
    75     GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POSITION | GL::VERTEX_ATTRIB_FLAG_COLOR );
    76     glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertercies );
    77     glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_FLOAT,GL_TRUE, 0, color);
    78     // 绘制三角形  
    79     glDrawArrays(GL_TRIANGLES, 0 ,3 );
    80     //通知cocos2d-x 的renderer,让它在合适的时候调用这些OpenGL命令  
    81     CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,3);
    82     CHECK_GL_ERROR_DEBUG();
    83 
    84 }
    复制代码

    内有利用shader使得sprite变灰的代码。

    下面是变灰所用到的vsh和fsh文件。

    复制代码
     1 attribute vec4 a_position;
     2 attribute vec2 a_texCoord;
     3 attribute vec4 a_color;
     4                     
     5 
     6 varying vec4 v_fragmentColor;
     7 varying vec2 v_texCoord;
     8                                 
     9 void main()    
    10 {                            
    11     gl_Position = CC_PMatrix * a_position;
    12     v_fragmentColor = a_color;
    13     v_texCoord = a_texCoord;
    14 }
    复制代码
    复制代码
     1 varying vec4 v_fragmentColor;    
     2 varying vec2 v_texCoord;    
     3 uniform sampler2D CC_Texture0;    
     4         
     5 void main()            
     6 {
     7     vec4 v_orColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord);
     8     float gray = dot(v_orColor.rgb, vec3(0.299, 0.587, 0.114));
     9     gl_FragColor = vec4(gray, gray, gray, v_orColor.a);
    10 }                
    复制代码

    http://www.58player.com/blog-2534-93050.html

    使用例子:http://www.cnblogs.com/U-tansuo/p/quick2-25_shader.html

    http://4gamers.cn/blog/categories/opengl-es/

  • 相关阅读:
    【二分】Pair of Topics
    【Windows】制作登录界面
    【Windows】制作文本框
    【windows】制作幸运“Tiger”机
    【python】函数
    SPOJ 3267 DQUERY
    CF 570D Tree Requests
    UVa 11809 Floating-Point Numbers
    Luogu P5098 Cave Cows 3
    GHOJ 428 未出现的子串
  • 原文地址:https://www.cnblogs.com/zhangfeitao/p/4537726.html
Copyright © 2011-2022 走看看