cocos2dx(3.X)中使用shader


 
 
 

原文鏈接:http://blog.csdn.net/xufeng0991/article/details/47256583

一 shader的基本概念

1 什么是shader

shader即着色器,就是專門用來渲染3D圖形的一種技術。 
通過shader,可以自己編寫顯卡渲染畫面的算法,使畫面更漂亮、更逼真。

2 shader分類

shader又分兩種,一種是頂點shader(3D圖形是由三角形組成的,頂點shader就是計算頂點位置,並為后期像素渲染做准備的), 
另一種是像素shader,就是以像素為單位,計算光照、顏色的一系列算法。

3 shader語言

幾個不同的圖形API有各自的shader語言: 
在DirectX中,頂點shader叫做vertex shader,像素shader叫做pixel shader; 
在OpenGL中,頂點shader也叫做vertex shader,但像素shader叫做fragment shader。 
此外顯卡芯片廠商NVIDIA還推出CG顯卡編程語言,也支持shader。

二 shader開發流程

這里寫圖片描述

  1. 編寫vertex Shader和fragment shader源碼。
  2. 創建兩個shader 實例:GLuint glCreateShader(GLenum type); [gl.createShader]
  3. 給Shader實例指定源碼。 glShaderSource [gl.shaderSource]
  4. 編譯shaer源碼 void glCompileShader(GLuint shader) [gl.compileShader]
  5. 創建shader program – GLuint glCreateProgram(void) [gl.createProgram]
  6. 綁定shader到program 。 void glAttachShader(GLuint program, GLuint shader)。每個program必須綁定一個vertex shader 和一個fragment shader。 [gl.attachShader]
  7. 鏈接program 。 void glLinkProgram(GLuint program) [gl.linkProgram]
  8. 使用porgram 。 void glUseProgram(GLuint program) [gl.useProgram]

對於使用獨立shader編譯器編譯的二進制shader代碼,可使用glShaderBinary來加載到一個shader實例中。

三 shader程序

1 語言glsl

glsl即OpenGL Shading Language(OpenGL着色語言),是用來在OpenGL中着色編程的語言。

2 頂點着色器

// vert.vsh // 頂點着色器,VBO/VAO提供的每個頂點都執行一遍頂點着色器,輸出一個varying和gl_Position等 // 變量修飾: // attribute: 只讀,隨不同頂點變化的全局變量,應用程序傳入,只能用在頂點着色器中 // uniform: 只讀,隨不同圖元變化的全局變量,應用程序傳入, // varying: 在頂點shader中可寫,在片斷shader中只讀,用於在頂點着色器和片段着色器之間傳遞數據 // 輸入: attribute, 輸出:varying+gl_positon + gl_Position + gl_PointSize attribute vec4 a_position; attribute vec4 a_color; varying vec4 v_fragmentColor; // 每一個Shader程序都有一個main函數 void main() { // gl開頭的變量名是系統內置的變量 gl_Position = CC_MVPMatrix * a_position;// 每個點固有的Varying,表示點的空間位置。 v_fragmentColor = a_color; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

3 片段着色器

// frag.fsh // 片元着色器,光柵化輸出的每個片元都執行一遍片段着色器,生成一個或多個(多重渲染)顏色值作為輸出 // 輸入: varying, 輸出: gl_FragColor + gl_FragDepth //用於在頂點着色器和片段着色器之間傳遞數據,因此類型必須完全一直 varying vec4 v_fragmentColor; // 每一個Shader程序都有一個main函數 void main() { // gl開頭的變量名是系統內置的變量 gl_FragColor = v_fragmentColor;// gl_FragColor 定義最終畫在屏幕上面的像素點的顏色 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

三 程序調用

新建cocos工程,將上面兩個文件放到Resource/shaders文件夾下,修改代碼如下:

// .h #ifndef __HELLOWORLD_SCENE_H__ #define __HELLOWORLD_SCENE_H__ #include "cocos2d.h" USING_NS_CC; class HelloWorld : public cocos2d::Layer { public: static cocos2d::Scene* createScene(); virtual bool init(); CREATE_FUNC(HelloWorld); virtual void visit(Renderer *renderer, const Mat4& parentTransform, uint32_t parentFlags); void onDraw(); private: CustomCommand _customCommand; GLuint _vao; GLuint _vertVBO; GLuint _colorVBO; }; #endif // __HELLOWORLD_SCENE_H__
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
// .cpp #include "HelloWorldScene.h" USING_NS_CC; Scene* HelloWorld::createScene() { // 'scene' is an autorelease object auto scene = Scene::create(); // 'layer' is an autorelease object auto layer = HelloWorld::create(); // add layer as a child to scene scene->addChild(layer); // return the scene return scene; } // on "init" you need to initialize your instance bool HelloWorld::init() { ////////////////////////////// // 1. super init first if ( !Layer::init() ) { return false; } /* 在OpenGL中,GLSL的shader使用的流程與C語言相似,每個shader類似一個C模塊,首先需要單獨編譯(compile), 然后一組編譯好的shader連接(link)成一個完整程序。 */ auto program = CCGLProgram::createWithFilenames("shader/vert.vsh", "shader/frag.fsh"); program->link(); program->updateUniforms(); this->setGLProgram(program); /* 使用VBO和VAO的步驟都差不多,步驟如下: 1 glGenXXX 2 glBindXXX */ // 創建和綁定vao glGenVertexArrays(1, &_vao); glBindVertexArray(_vao); // 創建和綁定vbo glGenBuffers(1, &_vertVBO);// 生成VBO glBindBuffer(GL_ARRAY_BUFFER, _vertVBO); // 關聯到當前的VAO auto size = Director::getInstance()->getVisibleSize(); float vertercies[] = {// 三角形頂點位置 0, 0, // 第1個點坐標 size.width, 0, // 第2個點坐標 size.width / 2, size.height // 第3個點坐標 }; // 給VBO設置數據 glBufferData(GL_ARRAY_BUFFER, sizeof(vertercies), vertercies, GL_STATIC_DRAW); // 獲得變量a_position在內存中的位置 GLuint positionLocation = glGetAttribLocation(program->getProgram(), "a_position"); glEnableVertexAttribArray(positionLocation); // 提交包含數據的數組指針 glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // 設置顏色 float color[] = {// 三角形頂點顏色RGBA 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1 }; glGenBuffers(1, &_colorVBO); glBindBuffer(GL_ARRAY_BUFFER, _colorVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(color), color, GL_STATIC_DRAW); // 獲得變量a_color在內存中的位置 GLuint colorLocation = glGetAttribLocation(program->getProgram(), "a_color"); glEnableVertexAttribArray(colorLocation); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); return true; } void HelloWorld::visit(cocos2d::Renderer *renderer, const Mat4 &transform, uint32_t parentFlags) { Layer::draw(renderer, transform, parentFlags); _customCommand.init(_globalZOrder); _customCommand.func = CC_CALLBACK_0(HelloWorld::onDraw, this); renderer->addCommand(&_customCommand); } void HelloWorld::onDraw() { auto glProgram = getGLProgram(); glProgram->use(); glProgram->setUniformsForBuiltins(); /* VAO里的VBOs都設置好了以后,在繪制的地方只需要設置當前綁定的VAO是哪個, 就能按照初始化的VAO來繪制,即調用glDrawArrays */ // 設置當前綁定的VAO glBindVertexArray(_vao); // 繪制三角形 glDrawArrays(GL_TRIANGLES, 0, 3); // 解綁當前VAO,但並不釋放 glBindVertexArray(0); CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, 3); CHECK_GL_ERROR_DEBUG(); }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM