在上一节中有介绍道OpenGL ES管线阶段,在这一节主要介绍一下vertex shader和fragment shader。
简单来说,在顶点处理阶段会对传入渲染管线的每个顶点执行顶点着色器中的内容,在光栅化过程中会对未被裁剪的顶点执行片元着色器中的内容(可以通过对纹理进行取样或者使用其他技术来确定像素的颜色)。
着色器程序的创建与C/C++程序的创建相似。首先需要编写着色器程序文本,其次将Shader源程序逐个编译成Shader对象,之后将编译好的Shader对象链接到一个单独的程序对象中并将其载入到 GPU。
我们在项目中创建Shader.vsh和Shader.fsh两个文件,分别添加如下代码:
#version 300 es // 指定版本
in vec4 position;
void main()
{
gl_Position = position;
}
··
#version 300 es
precision mediump float; // 指定精度
out vec4 fragColor;
void main()
{
fragColor = vec4(1.0,1.0,1.0,1.0); // 输出白色
}
并在ViewController.mm中声明以下几个方法:
// 根据路径读取文件内容
char* LoadAssetContent(const char*path)
{
char*assetContent=nullptr;
NSString*nsPath=[[NSBundle mainBundle] pathForResource:[NSString stringWithUTF8String:path] ofType:nil];
NSData *data=[NSData dataWithContentsOfFile:nsPath];
assetContent=new char[[data length]+1];
memcpy(assetContent, [data bytes], [data length]);
assetContent[[data length]]='\0';
return assetContent;
}
// 根据代码编译着色器
GLuint CompileShader(GLenum shaderType,const char*code)
{
//create shader object in gpu
GLuint shader=glCreateShader(shaderType);
//transform src to gpu & asign to the shader object
glShaderSource(shader, 1, &code, NULL);
glCompileShader(shader);
GLint compileStatus=GL_TRUE;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
if(compileStatus==GL_FALSE)
{
printf("compile shader error,shader code is : %s\n",code);
char szBuffer[1024]={0};
GLsizei logLen=0;
glGetShaderInfoLog(shader, 1024, &logLen, szBuffer);
printf("error log : %s\n",szBuffer);
glDeleteShader(shader);
return 0;
}
return shader;
}
// 根据编译好的Shader链接程序
GLuint CreateGPUProgram(const char*vsCode,const char*fscode)
{
GLuint program;
//compile source code
//.cpp .mm .m -> .o
GLuint vsShader=CompileShader(GL_VERTEX_SHADER, vsCode);
GLuint fsShader=CompileShader(GL_FRAGMENT_SHADER, fscode);
//link .o -> executable file
program=glCreateProgram();
glAttachShader(program, vsShader);
glAttachShader(program, fsShader);
glLinkProgram(program);
GLint programStatus=GL_TRUE;
glGetProgramiv(program, GL_LINK_STATUS, &programStatus);
if(GL_FALSE==programStatus)
{
printf("link program error!");
char szBuffer[1024]={0};
GLsizei logLen=0;
glGetProgramInfoLog(program, 1024, &logLen, szBuffer);
printf("link error : %s\n",szBuffer);
glDeleteProgram(program);
return 0;
}
return program;
}
声明一个GLuint gpuProgram
,执行gpuProgram=CreateGPUProgram(LoadAssetContent("shader.vsh"),LoadAssetContent("shader.fsh"));
,如果gpuProgram不等于0,意味着程序创建成功。
注:顶点着色器和片元着色器包含自建变量,如gl_Position(输出顶点位置的剪裁坐标)和gl_PointSize(点精灵尺寸)。想要具体了解着色器自建变量可查阅OpenGL ES 3.0编程指南8.1和10.2。