OpenGL ES shading language 3.0 也被稱做 GLSL,是個 C風格的編程語言。編程
Opengl ES 3.0內部有兩種可編程處理單元,即Vertex processor和Fragment processor,分別用來處理Vertex shader executable和Fragment shader executable。注意,Opengl ES 3.0不支持Geometry Shader。上圖中,紫色部分就是可執行體了,即 executable .服務器
先來一段Vertex shader代碼編程語言
#version 300 es //版本號 in vec4 VertexPosition; //應用層輸入逐頂點位置座標數據 in vec4 VertexColor; //應用層輸入逐頂點顏色數據 uniform float RadianAngle; //應用層輸入數據 out vec4 TriangleColor;
mat2 rotation = mat2(cos(RadianAngle),sin(RadianAngle), -sin(RadianAngle),cos(RadianAngle));
void main()
{
gl_Position = mat4(rotation)*VertexPosition;//給內置數據賦值
TriangleColor = VertexColor;
}
再來一段Fragment shader代碼ui
#version 300 es precision mediump float;//配置精度 in vec4 TriangleColor; out vec4 FragColor; void main() { FragColor = TriangleColor; };
上面這兩段代碼,只是文本數據,上述的兩種processor可沒辦法直接執行,這就須要一個叫作編譯和連接的步驟,來將這個文本數據變成executable的數據。能夠經過下圖來了解這個建立executable的過程:spa
須要在應用層加載和編譯shader,使用以下代碼進一步說明:code
GLuint loadAndCompileShader(GLenum shaderType, const char* sourceCode)
{ // Create the shader GLuint shader = glCreateShader(shaderType); if ( shader )
{ // Pass the shader source code glShaderSource(shader, 1, &sourceCode, NULL); // Compile the shader source code glCompileShader(shader); // Check the status of compilation GLint compiled = 0; glGetShaderiv(shader,GL_COMPILE_STATUS,&compiled); if (!compiled)
{ // Get the info log for compilation failure GLint infoLen = 0; glGetShaderiv(shader,GL_INFO_LOG_LENGTH, &infoLen); if (infoLen)
{ char* buf = (char*) malloc(infoLen); if (buf)
{ glGetShaderInfoLog(shader, infoLen, NULL, buf); printf("Could not compile shader %s:" buf); free(buf); } // Delete the shader program glDeleteShader(shader); shader = 0; } } } return shader; }
使用以下代碼來執行連接過程:orm
GLuint linkShader(GLuint vertShaderID,GLuint fragShaderID){ if (!vertShaderID || !fragShaderID){ // Fails! return return 0; } // Create an empty program object GLuint program = glCreateProgram(); if (program) { // Attach vertex and fragment shader to it glAttachShader(program, vertShaderID); glAttachShader(program, fragShaderID); // Link the program glLinkProgram(program); GLint linkStatus = GL_FALSE; glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); if (linkStatus != GL_TRUE) { GLint bufLength = 0; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); if (bufLength) { char* buf = (char*) malloc(bufLength); if(buf) { glGetProgramInfoLog(program,bufLength,NULL,buf); printf("Could not link program:\n%s\n", buf);
free(buf);
}
}
glDeleteProgram(program);
program = 0;
}
}
return program;
}blog
前文一直提到的executable就是這個返回的句柄變量 program。這個program將會在流水線的Processor上執行。ci
回過頭再來分析vertex shader代碼和fragment shader代碼。it
in vec4 VertexPosition; in vec4 VertexColor;
shader代碼裏聲明的這兩個變量的值是從哪裏獲取的呢,這就涉及了一個重要的環節,就是應用層和shader層的數據通訊問題。爲了方便理解,根據執行的位置不一樣,能夠把應用層看作CPU,把shader層看作GPU。便可抽象爲CPU與GPU通訊,進一步抽象爲客戶端C和服務端S之間的通訊。下面來解釋這個通訊的流程,從通訊上來講,必然是要先讓客戶端找到服務器端的一個通訊端口,而後客戶端創建與這個通訊端口的鏈接,最後只要往這個鏈接上扔數據,這樣服務端就能收到數據了。
首先實現尋找到服務端通訊端口的功能,如下代碼就幫助CPU端找到GPU端的數據通訊端口
GLuint positionAttribHandle; GLuint colorAttribHandle; positionAttribHandle = glGetAttribLocation(programID, "VertexPosition"); colorAttribHandle = glGetAttribLocation(programID, "VertexColor");
如下代碼,實現了往通訊通道上扔數據的功能:
// Send data to shader using queried attrib location glVertexAttribPointer(positionAttribHandle, 2, GL_FLOAT,GL_FALSE, 0, gTriangleVertices); glVertexAttribPointer(colorAttribHandle, 3, GL_FLOAT,GL_FALSE, 0, gTriangleColors);
GPU端,默認全部這些頂點屬性端口都是關閉的,所以須要打開這些通訊端口:
// Enable vertex position attribute glEnableVertexAttribArray(positionAttribHandle); glEnableVertexAttribArray(colorAttribHandle);
這樣,一條通訊信道就算創建起來了。