理解OpenGL渲染管線,對於學習OpenGL很是重要。下面是OpenGL渲染管線的示意圖:(圖中淡藍色區域是能夠編程的階段)編程
此圖是從wiki中拿過來的,OpenGL的渲染管線主要包括:ide
準備頂點數據(經過VBO、VAO和Vertex attribute來傳遞數據給OpenGL)函數
頂點處理(這裏主要由Vertex Shader來完成,從上圖中能夠看出,它還包括可選的Tessellation和Geometry shader階段)學習
頂點後處理(主要包括Clipping,頂點座標歸一化和viewport變換)ui
Primitive組裝(好比3點組裝成一個3角形)this
光柵化成一個個像素spa
使用Fragment shader來處理這些像素debug
採樣處理(主要包括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語言是同樣的。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_
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 }