#应用步骤
- 着色器和程序对象的概述
- 创建和编译着色器
- 创建和链接程序 【本文至此】
- 获取和设置统一变量
- 获取和设置属性
- 着色器编译器和程序二进制代码
#着色器与程序
-
需要创建
两种基本对象才能用着色器进行渲染:着色器对象和程序对象; -
要理解着色器与程序之间的关系的话, 可以把它们比作
C语言的编译器和链接程序; -
C编译器为一段源代码生成目标代码(如.obj或者.o文件); 创建目标文件之后,C链接程序将对象文件链接为最后的程序;
OpenGL ES在着色器的表现上 使用类似的方式—— 着色器对象 是 包含单个着色器的对象, 【shader = GLES30.glCreateShader ( type );】
源代码提供给着色器对象, 【GLES30.glShaderSource ( shader, shaderSrc );】
然后把着色器对象编译为一个目标形式(类似与.obj文件); 【GLES30.glCompileShader ( shader );】
编译之后,着色器对象便可以连接到 一个程序对象;程序对象可以连接多个 着色器对象;
//向程序中加入顶点着色器 片元着色器
GLES30.glAttachShader ( programObject, vertexShader );
GLES30.glAttachShader ( programObject, fragmentShader );
- 在OpenGL ES中, 每个程序对象必须连接一个顶点着色器和一个片段着色器, 程序对象 被链接为 用于渲染的最后“可执行程序”;
// 基于顶点着色器与片段着色器创建程序
programObject = GLES30.glCreateProgram();
//创建失败,就拜拜
if ( programObject == 0 )
{
return;
}
//向程序中加入顶点着色器 片元着色器
GLES30.glAttachShader...
// Bind vPosition to attribute 0
GLES30.glBindAttribLocation ( programObject, 0, "vPosition" );
// 链接程序
GLES30.glLinkProgram ( programObject );
// 把链接成功的 渲染管线程序id 存入数组linked
GLES30.glGetProgramiv ( programObject, GLES30.GL_LINK_STATUS, linked, 0 );
//若链接失败则报错 并 删除程序
if ( linked[0] == 0 )
{
...
}
// 保存 链接成功的 渲染管线程序id 到 全局变量
mProgramObject = programObject;
####即获得链接后的着色器对象 的 一般步骤如下:
- 创建一个顶点着色器对象和一个片段着色器对象;
- 将 每一套 着色器源代码 连接到 对应的 着色器对象;
- 编译着色器对象;
- 创建一个程序对象;
- 将编译后的着色器对象连接到程序对象;
- 链接程序对象;
#####创建和编译一个 着色器对象 (相关API)
-
Create
-
Delete
-
glShaderSource 加载 着色器代码
Android API中 只有
shader和string两个参数; -
compileShader 编译
-
glGetShaderiv 查看 着色器的 编译结果状态或其他的各种信息
【通过pname控制】注意第三个参数是存放结果的
int类型数组,对应params: -
glGetShaderInfoLog
Android API只需要提供一个shader实例即可:【API返回结果即Log信息】
private int LoadShader ( int type, String shaderSrc )
{
int shader;
int[] compiled = new int[1];
// Create the shader object
shader = GLES30.glCreateShader ( type );
if ( shader == 0 )
{
return 0;
}
// Load the shader source
// 加载 着色器代码
GLES30.glShaderSource ( shader, shaderSrc );
// Compile the shader
// 编译 着色器代码
GLES30.glCompileShader ( shader );
// Check the compile status
// 查看 着色器编译结果状态
GLES30.glGetShaderiv (shader, GLES30.GL_COMPILE_STATUS, compiled, 0 );
//编译失败,则 报错 并 删除着色器实例
if ( compiled[0] == 0 )
{
Log.e ( TAG, GLES30.glGetShaderInfoLog ( shader ) );
GLES30.glDeleteShader ( shader );
return 0;
}
//编译成功,则返回 着色器id
return shader;
}
#####创建和链接管线程序 (相关API)  - Create
-
delete
-
Attach【着色器实例 连接 管线程序实例】
-
Detach【断开 着色器实例 与 管线程序实例 的连接】
-
链接(程序对象 成功链接之后,就可使用 程序对象 进行渲染了!)
-
glGetProgramiv 查看 管线程序实例的 编译结果状态或其他的各种信息 【通过
pname 标签控制想要查询的内容,params返回存储结果的int类型数组 (类似glGetShaderiv)】 -
glGetProgramInfoLog
Android API只需要提供一个 管线程序实例 即可【API返回结果即Log信息】:
-
glValidateProgram:
用于检查, 一般不使用;
-
glUseProgram:
///
// Initialize the shader and program object
// 初始化 着色器 和 渲染管线程序
//
public void onSurfaceCreated ( GL10 glUnused, EGLConfig config )
{
String vShaderStr =
"#version 300 es \n"
+ "in vec4 vPosition; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_Position = vPosition; \n"
+ "} \n";
String fShaderStr =
"#version 300 es \n"
+ "precision mediump float; \n"
+ "out vec4 fragColor; \n"
+ "void main() \n"
+ "{ \n"
+ " fragColor = vec4 ( 0.0, 0.8, 1.0, 1.0 ); \n"
+ "} \n";
int vertexShader;//加载好的 顶点着色器实例
int fragmentShader;//加载好的 片段着色器实例
int programObject;//自定义的渲染管线程序id
int[] linked = new int[1];//存放链接成功 渲染管线程序id 的数组
// Load the vertex/fragment shaders
// 【调用 LoadShader() 】加载着色器实例
vertexShader = LoadShader ( GLES30.GL_VERTEX_SHADER, vShaderStr );
fragmentShader = LoadShader ( GLES30.GL_FRAGMENT_SHADER, fShaderStr );
// Create the program object
// 基于顶点着色器与片段着色器创建程序
programObject = GLES30.glCreateProgram();
//创建失败,就拜拜
if ( programObject == 0 )
{
return;
}
//向程序中加入顶点着色器 片元着色器
GLES30.glAttachShader ( programObject, vertexShader );
GLES30.glAttachShader ( programObject, fragmentShader );
// Bind vPosition to attribute 0
GLES30.glBindAttribLocation ( programObject, 0, "vPosition" );
// Link the program
// 链接程序
GLES30.glLinkProgram ( programObject );
// Check the link status
// 把链接成功的 渲染管线程序id 存入数组linked
GLES30.glGetProgramiv ( programObject, GLES30.GL_LINK_STATUS, linked, 0 );
//若链接失败则报错 并 删除程序
if ( linked[0] == 0 )
{
Log.e ( TAG, "Error linking program:" );
Log.e ( TAG, GLES30.glGetProgramInfoLog ( programObject ) );
GLES30.glDeleteProgram ( programObject );
return;
}
// Store the program object
// 保存 链接成功的 渲染管线程序id 到 全局变量
mProgramObject = programObject;
//指定清除屏幕用的颜色
GLES30.glClearColor ( 1.0f, 1.0f, 1.0f, 0.0f );
}
// /
// Draw a triangle using the shader pair created in onSurfaceCreated()
// 使用onSurfaceCreated()中创建好的 着色器对(一对顶点、片段着色器) 画一个三角形
//
public void onDrawFrame ( GL10 glUnused )
{
// Set the viewport
// viewport【窗口】
GLES30.glViewport ( 0, 0, mWidth/2, mHeight/2 );
// Clear the color buffer
GLES30.glClear ( GLES30.GL_COLOR_BUFFER_BIT );
// Use the program object
// 指定使用某套shader程序
GLES30.glUseProgram ( mProgramObject );
// Load the vertex data
// vertex【顶点】
// 将顶点位置数据【mVertices】传送进 渲染管线
GLES30.glVertexAttribPointer ( 0, 3, GLES30.GL_FLOAT, false, 0, mVertices );
//启用顶点位置数据
GLES30.glEnableVertexAttribArray ( 0 );
// GLES30.glDrawArrays ( GLES30.GL_TRIANGLES, 0, 3 );
// 绘制
GLES30.glDrawArrays ( GLES30.GL_TRIANGLE_STRIP, 0, 3 );
}
参考自:
- 《OPENGL ES 3.0编程指南(第2版)》