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

opengl之vsh、fsh简易介绍+cocos2dx 3.0 shader 变灰

发布时间:2020-12-14 20:09:51 所属栏目:百科 来源:网络整理
导读:认识着色器 理解OpenGL渲染管线,对于学习OpenGL非常重要。下面是OpenGL渲染管线的示意图:(图中淡蓝色区域是可以编程的阶段) 此图是从wiki中拿过来的,OpenGL的渲染管线主要包括: 准备顶点数据(通过VBO、VAO和Vertex attribute来传递数据给OpenGL) 顶
认识着色器

理解OpenGL渲染管线,对于学习OpenGL非常重要。下面是OpenGL渲染管线的示意图:(图中淡蓝色区域是可以编程的阶段)

此图是从wiki中拿过来的,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之间相互传递的参数。

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

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

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

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

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

1 varying highp vec2 textureCoordinate; 2 precision mediump 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 > 19 color.g = 20 21 return color; 22 } 23 24 25 { 26 vec4 pixelColor; 27 28 pixelColor = texture2D(videoFrame,textureCoordinate); 29 30 gl_FragColor = memoryRender(pixelColor); 31 }

varyinghighpvec2textureCoordinate就是从vsh中传过来了纹理坐标。

uniformsampler2DvideoFrame是我们真正的纹理贴图。

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_
 4 #include "cocos2d.h"
 6 USING_NS_CC;
 7 
 8 class GLTestingLayer : public cocos2d::Layer
 9 {
10 public:
11     static cocos2d::Scene* createScene();
virtual bool init();  
13     void menuCloseCallback(cocos2d::Ref* pSender);
14     CREATE_FUNC(GLTestingLayer);
void graySprite(Sprite * sprite);
void visit( Renderer* renderer,const kmMat4 &parentTransform,255); line-height:1.5!important">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 { if ( !Layer::init() ) 14 { 15 return false; 16 } 17 this->setPosition(0,0); 19 Size visibleSize = Director::getInstance()->getVisibleSize(); 20 auto sprite = Sprite::create(HelloWorld.png"); 21 sprite->setAnchorPoint(Point(0.5,128); line-height:1.5!important">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)); 28 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",0); line-height:1.5!important">gray.fsh42 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,255); line-height:1.5!important">bool parentTransformUpdated ) 53 { 54 Layer::visit( renderer,parentTransform,parentTransformUpdated ); 55 _command.init(_globalZOrder); 56 _command.func = CC_CALLBACK_0(GLTestingLayer::onDraw,255); line-height:1.5!important">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,128); line-height:1.5!important">1.0f,128); line-height:1.5!important">1.0f); 67 auto size = Director::getInstance()->getWinSize(); 68 69 float vertercies[] = { 100,128); line-height:1.5!important">100,70 200,128); line-height:1.5!important">200,128); line-height:1.5!important">71 300,128); line-height:1.5!important">100 }; 72 float color[] = { 1,128); line-height:1.5!important">1,128); line-height:1.5!important">73 74 1 }; 75 GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POSITION | GL::VERTEX_ATTRIB_FLAG_COLOR ); 76 glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION,GL_FLOAT,GL_FALSE,128); line-height:1.5!important">0,vertercies ); 77 glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR,128); line-height:1.5!important">4,GL_TRUE,color); 78 绘制三角形 79 glDrawArrays(GL_TRIANGLES,128); line-height:1.5!important">3 ); 80 通知cocos2d-x 的renderer,让它在合适的时候调用这些OpenGL命令 81 CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(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 6 varying vec4 v_fragmentColor; 7 varying vec2 v_texCoord; 8 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() 7 vec4 v_orColor = v_fragmentColor * texture2D(CC_Texture0,v_texCoord); float gray = dot(v_orColor.rgb,vec3(0.299,128); line-height:1.5!important">0.587,128); line-height:1.5!important">0.114)); 9 gl_FragColor = vec4(gray,gray,v_orColor.a); 10 }

(编辑:李大同)

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

    推荐文章
      热点阅读