在上一節(jié)中有介紹道OpenGL ES管線階段,在這一節(jié)主要介紹一下vertex shader和fragment shader。
簡單來說,在頂點處理階段會對傳入渲染管線的每個頂點執(zhí)行頂點著色器中的內(nèi)容,在光柵化過程中會對未被裁剪的頂點執(zhí)行片元著色器中的內(nèi)容(可以通過對紋理進行取樣或者使用其他技術來確定像素的顏色)。
著色器程序的創(chuàng)建與C/C++程序的創(chuàng)建相似。首先需要編寫著色器程序文本,其次將Shader源程序逐個編譯成Shader對象,之后將編譯好的Shader對象鏈接到一個單獨的程序對象中并將其載入到 GPU。
我們在項目中創(chuàng)建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中聲明以下幾個方法:
// 根據(jù)路徑讀取文件內(nèi)容
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;
}
// 根據(jù)代碼編譯著色器
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;
}
// 根據(jù)編譯好的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,執(zhí)行gpuProgram=CreateGPUProgram(LoadAssetContent("shader.vsh"),LoadAssetContent("shader.fsh"));,如果gpuProgram不等于0,意味著程序創(chuàng)建成功。
注:頂點著色器和片元著色器包含自建變量,如gl_Position(輸出頂點位置的剪裁坐標)和gl_PointSize(點精靈尺寸)。想要具體了解著色器自建變量可查閱OpenGL ES 3.0編程指南8.1和10.2。