opengl之vsh、fsh簡易介紹+cocos2dx 3.0 shader 變灰

認識着色器
 

理解OpenGL渲染管線,對於學習OpenGL很是重要。下面是OpenGL渲染管線的示意圖:(圖中淡藍色區域是能夠編程的階段)編程

1408089665637131.png

此圖是從wiki中拿過來的,OpenGL的渲染管線主要包括:ide

  1. 準備頂點數據(經過VBO、VAO和Vertex attribute來傳遞數據給OpenGL)函數

  2. 頂點處理(這裏主要由Vertex Shader來完成,從上圖中能夠看出,它還包括可選的Tessellation和Geometry shader階段)學習

  3. 頂點後處理(主要包括Clipping,頂點座標歸一化和viewport變換)ui

  4. Primitive組裝(好比3點組裝成一個3角形)this

  5. 光柵化成一個個像素spa

  6. 使用Fragment shader來處理這些像素debug

  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語言是同樣的。code

這裏面有兩種類型的變量,一種是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_
GLTestingLayer
 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 }
GLTestingLayer.cpp

內有利用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 }
gray.vsh
 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 }                
gray.fsh
相關文章
相關標籤/搜索