Cocos2dx中的opengl使用(一)简单介绍
引擎提供了CCGLProgram类来处理着色器相关操作,对当前绘图程序进行了封装,其中使用频率最高的应该是获取着色器程序的接口:const GLuint getProgram();
该接口返回了当前着色器程序的标识符。后面将会看到,在操作OpenGL的时候,我们常常需要针对不同的着色器程序作设置。注意,这里返回的是一个无符号整型的标识符,而不是一个指针或结构引用,这是OpenGL接口的一个风格。对象(纹理、着色器程序或其他非标准类型)都是使用整型标识符来表示的。
CCGLProgram提供了两个函数导入着色器程序,支持直接从内存的字符串流载入或是从文件中读取。这两个函数的第一个参数均指定了顶点着色器,后一个参数则指定了像素着色器:
- /** Initializes the CCGLProgram with a vertex and fragment with bytes array */
- bool initWithVertexShaderByteArray(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray);
- /** Initializes the CCGLProgram with a vertex and fragment with contents of filenames */
- 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 quick\lib\quick-src\extra\filters\shader目录下的部分例子,如
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的渲染管线主要包括:
准备顶点数据(通过VBO、VAO和Vertex attribute来传递数据给OpenGL)
顶点处理(这里主要由Vertex Shader来完成,从上图中可以看出,它还包括可选的Tessellation和Geometry shader阶段)
顶点后处理(主要包括Clipping,顶点坐标归一化和viewport变换)
Primitive组装(比如3点组装成一个3角形)
光栅化成一个个像素
使用Fragment shader来处理这些像素
采样处理(主要包括Scissor Test, Depth Test, Blending, Stencil Test等)。

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/
Cocos2dx中的opengl使用(一)简单介绍的更多相关文章
- Python中的yield生成器的简单介绍
Python yield 使用浅析(整理自:廖 雪峰, 软件工程师, HP 2012 年 11 月 22 日 ) 初学 Python 的开发者经常会发现很多 Python 函数中用到了 yield 关 ...
- UE4中的AI行为树简单介绍
UE4引擎中可以实现简单AI的方式有很多,行为树是其中比较常用也很实用的AI控制方式,在官网的学习文档中也有最简单的目标跟踪AI操作教程,笔者在这里只作简单介绍. AIController->和 ...
- mysql中set和enum使用(简单介绍)
简单介绍 SET类型 在创建表时,就指定SET类型的取值范围. 属性名 SET('值1','值2','值3'...,'值n') 其中,“属性名”参数指字段的名称:“值n”参数表示列表中的第n个值,这些 ...
- Java中Synchronized的用法(简单介绍)
简单介绍 synchronized是Java中的关键字,是一种同步锁.它修饰的对象有以下几种: 1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调 ...
- java中equals以及==的用法(简单介绍)
简单介绍 equals方法是java.lang.Object类的方法 有两种用法说明: 一.对于字符串变量来说,使用“==”和“equals()”方法比较字符串时,其比较方法不同. 1.“==”比较两 ...
- NDK中android.mk文件的简单介绍和第三方库的调用
先贴一个样例,然后解释一下: LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := mydjvuapi SRC_FILE_ ...
- 网络测量中基于Sketch方法的简单介绍
Sketch介绍 为什么要用Sketch 网络流主要根据五元组.主机地址.包的大小来分类.在网络中存在各种各样的包,如果按照上述分类方法,对每一种包都分配一个计数器来储存,虽然测量准确,那么存放计数器 ...
- Cocos2d-x中使用OpenGL ES2.0编写shader
这几天在看子龙山人的关于OpenGL的文章,先依葫芦画瓢,能看到些东西,才能慢慢深入了解,当入门文章不错,但是其中遇到的一些问题,折腾了一些时间,为了方便和我一样的小白们,在这篇文章中进行写补充. O ...
- Cocos2d-x中Vector<T>容器以及实例介绍
Vector<T> 是Cocos2d-x 3.x推出的列表容器,因此它所能容纳的是Ref及子类所创建的对象指针,其中的T是模板,表示能够放入到容器中的类型,在Cocos2d-x 3.x中T ...
随机推荐
- C#线程系列讲座(2):Thread类的应用
一.Thread类的基本用法 通过System.Threading.Thread类可以开始新的线程,并在线程堆栈中运行静态或实例方法.可以通过Thread类的的构造方法传递一个无参数,并且不返回值(返 ...
- ARC Rules
To write and compile source code for ARC, you have to take care of a few things. Just by following t ...
- pyOpenSSL0.13安装失败
/usr/lib64/python2.4/distutils/dist.py:236: UserWarning: Unknown distribution option: 'zip_safe' war ...
- 布置theano(Ubuntu14.04 LTS)
引言 由于研究生阶段将会从事自然语言处理方向的研究,目前要用到机器学习和深度学习相关的框架,那应老师的要求,将要使用theano,由于theano官方文档中关于ubuntu下配置的问题并没有给出很好的 ...
- Fusioncharts使用说明
背景 最近由于工作需要,再次接触到了Fusioncharts,但也有不足之处,现在官网上似乎是不支持flash的版本了,只能看到html5相关的javascript版本,无奈再次从网上搜索到了一些别人 ...
- Java 多线程 并发编程
一.多线程 1.操作系统有两个容易混淆的概念,进程和线程. 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进程的地址空间是互相隔离的:进程拥有各种 ...
- As3 Anchored Container 代码设置锚点旋转
原文地址:http://jamesvango.co.uk/blog/?p=136
- Codeforce Round #213 Div2
哎,弄了半天这次的C还是没出,真是捉急!,还TM的以为前几次只是运气不好!太逗了!
- Android 5.0新特性了解(一)----TabLayout
1.在2015年的google大会上,google发布了新的Android Support Material Design库,里面包含了几个新的控件,其中就有一个TabLayout,它就可以完成Tab ...
- 如何将扩展名为.backup的文件导入postgresql中 求步骤 新手 谢谢.
1.到www.postgresql.org下载pgadmin这个工具,安装好2.在菜单-文件-新增服务器 名称:TEST-PGSQL(名称自己编) 主机:填上你postgresql数据库的服务器ip地 ...