编译着色器
//创建着色器
//type有 GL_VERTEX_SHADER - 顶点着色器 GL_FRAGMENT_SHADER - 片段着色器
shaderId = glCreateShader(type);
if (!glIsShader(shaderId)) {
//检查是否创建成功
return false;
}
//shaderSrc就是上面着色器代码的字符串
glShaderSource(shaderId, 1, &shaderSrc, NULL);
//开始编译
glCompileShader(shaderId);
//检查是否编译成功
GLint compiled = 0;
glGetShaderiv(shaderId, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
GLint infoLen = 0;
glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1)
{
//获取编译失败的信息
infoLog = new char[infoLen]();
glGetShaderInfoLog(shaderId, infoLen, NULL, infoLog);
printf("Error compiling shader:
%s
", infoLog);
delete[] infoLog;
}
glDeleteShader(shaderId);
return false;
}
//编译成功,得到shaderId
4.2 创建Program
m_programId = glCreateProgram();
if (m_programId == 0) {
close();
return false;
}
//连接上面编译好的两个着色器
glAttachShader(m_programId, m_vShaderId);
glAttachShader(m_programId, m_fShaderId);
glLinkProgram(m_programId);
//检查一下连接是否成功
GLint linked = 0, infoLen = 0;
glGetProgramiv(m_programId, GL_LINK_STATUS, &linked);
if (!linked) {
glGetProgramiv(m_programId, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1)
{
//连接失败原因
char* infoLog = new char[sizeof(char) * infoLen]();
glGetProgramInfoLog(m_programId, infoLen, NULL, infoLog);
printf("Error linking program:
%s
", infoLog);
delete[] infoLog;
}
return false;
}
//开始使用
glUseProgram(m_programId);
//一般会在绘制前先刷一下底色
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
4.3 创建纹理
纹理是绘制片段着色器时使用的贴图,示例中绘制的是YUV数据,所以我们分布对Y U V创建三个纹理。
for (int i = 0; i < 3; i++) {
glGenTextures(1, &m_textures[i]);
glBindTexture(GL_TEXTURE_2D, m_textures[i]);
// 为当前绑定的纹理对象设置环绕、过滤方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
4.4 绘制
4.4.1 切换上下文
//切换上下文
eglMakeCurrent(m_display, m_surface, m_surface, m_context);
glUseProgram(m_programId);
glViewport(x, y, cx, cy);
4.4.2 构建顶点数据
//index=0 对应顶点着色器代码中的vPosition变量
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), vVertices);
glEnableVertexAttribArray(0);
//index=1 对应顶点着色器代码中的aTexCoord变量
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), vVertices + 3);
glEnableVertexAttribArray(1);
顶点数据
static const GLfloat vertices[] =
{
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, //左上 这里是 一个顶点坐标+一个纹理坐标
1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, //右上
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, //左下
1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f //右下
};
顶点数据包含了顶点坐标和纹理坐标,顶点坐标用来确定物体绘制形状的边界,纹理坐标用来给物体刷漆时框定的边界,但是他们具有不同的坐标系:
顶点坐标的坐标系

纹理坐标的坐标系

当按照这个标准把YUV图形渲染上去的时候你会惊奇地发现图像是倒着的,具体原因我没去详细了解过,应该是跟图片的读取有关,最简单的解决办法就是在顶点数组里调整一下纹理坐标,纹理倒着刷,图像不就变正了么,千万别自己去把YUV数据倒过来,这样太耗性能了。
glVertexAttribPointer