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);
这样,一条通讯信道就算创建起来了。