上一篇我們介紹了cocos2d-x繪製基本圖形的基本流程,我們還留下了一個着色器的部分沒有講,本篇內容將從openGL的渲染流程講起,介紹cocos2d-x中的着色器,openGL的渲染流程如圖所示:
openGL的繪製通常就是將頂點數據傳輸到openGL服務端。我們可以將一個頂點視爲一個需要統一處理的數據包,這個包中的數據可以是我們需要的任何數據,通常其中幾乎始終會包含位置數據。其他數據可能用來決定一個像素的最終顏色。
頂點着色器:一個複雜的應用程序可能包含許多個頂點着色器,但是在同一時刻只能有一個頂點着色器起作用,它用來進行頂點的變換,可能會非常簡單,簡單到傳遞着色器,也可能包含大量的計算。
幾何着色器:對幾何圖元做處理,可以創建新的圖元,這個階段是可選的
細分着色器:頂點着色器存在一些限制,一個就是它們在執行的過程中無法創建額外的幾何圖形,它們僅僅更新與它們當前所處理的頂點相關數據,無法訪問當前圖元中其他頂點數據,它包含細分控制着色器和細分計算着色器。
像素着色器(片元着色器):通過編程控制在屏幕上顯示顏色的階段,在這個階段中,我們使用着色器來計算片元的最終顏色和它的深度值。片元着色器非常強大,在這裏我們會使用紋理映射的方式,對頂點處理階段進行補充。可能還會丟棄不需要處理的片元
簡而言之,頂點着色器決定一個圖元應該位於屏幕什麼位置,而片元着色器使用這些信息來決定摸個片元的顏色是什麼。這兩個着色器是必選的。另外因爲頂點着色器階段處理的頂點比較少,而在像素着色階段處理的像素會很多,所以有時會在頂點階段處理顏色和光照,其餘的像素進行插值處理,爲了節約效率,當然效果要差些了。
下面來看cocos2d-x的着色器流程,回到上一篇講的DrawNode的init函數中
//設置着色器
setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_LENGTH_TEXTURE_COLOR));
這句話調用setGLProgramState設置着色器狀態,setGLProgramState函數代碼如下:void Node::setGLProgramState(cocos2d::GLProgramState* glProgramState)
{
if (glProgramState != _glProgramState)
{
CC_SAFE_RELEASE(_glProgramState);
_glProgramState = glProgramState;
CC_SAFE_RETAIN(_glProgramState);
if (_glProgramState)
_glProgramState->setNodeBinding(this);
}
}
這段代碼判斷設置的着色器是否與之前設置的相同,不同就重新設置,在onDraw函數中,會使用設置的着色器auto glProgram = getGLProgram();
glProgram->use();
glProgram->setUniformsForBuiltins(transform);
其中getGLProgram函數就是獲得着色器,代碼如下:GLProgram * Node::getGLProgram() const
{
return _glProgramState ? _glProgramState->getGLProgram() : nullptr;
}
或者乾脆直接在使用時傳遞使用哪個着色器auto glProgram = GLProgramCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_LENGTH_TEXTURE_COLOR);
glProgram->use();
glProgram->setUniformsForBuiltins(transform);
無論哪種方式,我們這裏都使用的是cocos2d-x的內置的着色器代碼,它們在“cocos目錄/cocos/renderer”目錄中 具體的詳細加載可以看GLProgramCache類的loadDefaultGLProgram函數,這是一個單例類,在初始化的時候就會加載所有的內置着色器,然後這些着色器的代碼文本以鍵值對的方式存儲程序中,當使用的時候就通過getGLProgram調用,我們看一下這裏使用的GLProgram::SHADER_NAME_POSITION_LENGTH_TEXTURE_COLOR:
頂點着色器:ccShader_PositionColorLengthTexture.vert
像素着色器:ccShader_PositionColorLengthTexture.frag
const char* ccPositionColorLengthTexture_vert = STRINGIFY(
\n#ifdef GL_ES\n
attribute mediump vec4 a_position;
attribute mediump vec2 a_texcoord;
attribute mediump vec4 a_color;
varying mediump vec4 v_color;
varying mediump vec2 v_texcoord;
\n#else\n
attribute vec4 a_position;
attribute vec2 a_texcoord;
attribute vec4 a_color;
varying vec4 v_color;
varying vec2 v_texcoord;
\n#endif\n
void main()
{
v_color = vec4(a_color.rgb * a_color.a, a_color.a);
v_texcoord = a_texcoord;
gl_Position = CC_MVPMatrix * a_position;
}
);
cocos2d-x的內置着色器採用字符串的方式存儲,可讀性上會差一些,忽略掉“\n”之類的應該還好,着色器使用GLSL,在下一篇中會詳細介紹,它類似於C語言,main函數是入口,這裏處理了輸入進來的顏色,貼圖和位置信息,並做相應處理,位置進行了MVP的轉換。
下一篇會介紹GLSL
能力不足,水平有限,如有錯誤,歡迎指出。