在上一節(jié)中有介紹道OpenGL ES管線階段淋肾,在這一節(jié)主要介紹一下vertex shader和fragment shader骡显。
簡單來說合搅,在頂點(diǎn)處理階段會(huì)對(duì)傳入渲染管線的每個(gè)頂點(diǎn)執(zhí)行頂點(diǎn)著色器中的內(nèi)容殊霞,在光柵化過程中會(huì)對(duì)未被裁剪的頂點(diǎn)執(zhí)行片元著色器中的內(nèi)容(可以通過對(duì)紋理進(jìn)行取樣或者使用其他技術(shù)來確定像素的顏色)蒋歌。
著色器程序的創(chuàng)建與C/C++程序的創(chuàng)建相似帅掘。首先需要編寫著色器程序文本,其次將Shader源程序逐個(gè)編譯成Shader對(duì)象堂油,之后將編譯好的Shader對(duì)象鏈接到一個(gè)單獨(dú)的程序?qū)ο笾胁⑵漭d入到 GPU修档。
我們?cè)陧?xiàng)目中創(chuàng)建Shader.vsh和Shader.fsh兩個(gè)文件,分別添加如下代碼:
#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中聲明以下幾個(gè)方法:
// 根據(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;
}
聲明一個(gè)GLuint gpuProgram
府框,執(zhí)行gpuProgram=CreateGPUProgram(LoadAssetContent("shader.vsh"),LoadAssetContent("shader.fsh"));
,如果gpuProgram不等于0吱窝,意味著程序創(chuàng)建成功。
注:頂點(diǎn)著色器和片元著色器包含自建變量迫靖,如gl_Position(輸出頂點(diǎn)位置的剪裁坐標(biāo))和gl_PointSize(點(diǎn)精靈尺寸)院峡。想要具體了解著色器自建變量可查閱OpenGL ES 3.0編程指南8.1和10.2。