前言
前面介绍完了OpenGL ES在Android&iOS端的构建,这一篇我们用OpenGL ES画个三角形,得益于前面的工作,现在我们只要写C++代码就可以能跨平台运行了。
步骤
1.着色器
Shader.hpp ↓
#ifndef OPENGLES_SHADER_HPP
#define OPENGLES_SHADER_HPP
#include "Platform.h"
// 获取OpenGL属性的状态
static void printGLString(const char *name, GLenum s) {
const char *v = (const char *) glGetString(s);
ESLog("GL %s = %s\n", name, v);
}
// 检测OpenGL状态是否错误
static void checkGlError(const char* op) {
for (GLint error = glGetError(); error; error = glGetError()) {
ESLog("after %s() glError (0x%x)\n", op, error);
}
}
// 创建着色器
static GLuint createShader(GLenum shaderType, const char* src) {
GLuint shader = glCreateShader(shaderType);
if (!shader) {
checkGlError("glCreateShader");
return 0;
}
glShaderSource(shader, 1, &src, NULL);
GLint compiled = GL_FALSE;
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
GLint infoLogLen = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLen);
if (infoLogLen > 0) {
//GLchar* infoLog = (GLchar*)malloc(infoLogLen);
GLchar *infoLog = new GLchar[infoLogLen];
if (infoLog) {
glGetShaderInfoLog(shader, infoLogLen, NULL, infoLog);
ESLog("Could not compile %s shader:\n%s\n",
shaderType == GL_VERTEX_SHADER ? "vertex" : "fragment",
infoLog);
//free(infoLog);
delete[] infoLog;
}
}
glDeleteShader(shader);
return 0;
}
return shader;
}
// 创建着色器程序
static GLuint createProgram(const char* vtxSrc, const char* fragSrc) {
GLuint vtxShader = 0;
GLuint fragShader = 0;
GLuint program = 0;
GLint linked = GL_FALSE;
vtxShader = createShader(GL_VERTEX_SHADER, vtxSrc);
if (!vtxShader)
goto exit;
fragShader = createShader(GL_FRAGMENT_SHADER, fragSrc);
if (!fragShader)
goto exit;
program = glCreateProgram();
if (!program) {
checkGlError("glCreateProgram");
goto exit;
}
glAttachShader(program, vtxShader);
glAttachShader(program, fragShader);
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &linked);
if (!linked) {
ESLog("Could not link program");
GLint infoLogLen = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLen);
if (infoLogLen) {
GLchar* infoLog = new GLchar[infoLogLen];
if (infoLog) {
glGetProgramInfoLog(program, infoLogLen, NULL, infoLog);
ESLog("Could not link program:\n%s\n", infoLog);
delete[] infoLog;
}
}
glDeleteProgram(program);
program = 0;
}
exit:
glDeleteShader(vtxShader);
glDeleteShader(fragShader);
return program;
}
#endif //OPENGLES_SHADER_HPP
着色器的编译、链接过程比较固定,这里已经封装成函数供后续使用,着色器的知识也不是一句两句能讲清楚的,网上也已经有了很多相关文章,比如这里,需要的同学可以去看看。
顶点着色器代码:
attribute vec3 aPosition; // 顶点位置
void main() {
gl_Position = aPosition;
}
片元着色器代码:
precision mediump float;
uniform vec4 uColor; // 顶点颜色
void main() {
gl_FragColor = uColor;
}
着色器代码类似C语言,在程序中使用的话把它当成字符串处理就好了,当然有的人做法是把它们保存成文件,然后读取文件的内容。
2.三角形
Triangle.h ↓
#ifndef OPENGLES_TRIANGLE_H
#define OPENGLES_TRIANGLE_H
#include "Platform.h"
#include "Shader.hpp"
class Triangle {
public:
GLuint program; // 着色器程序引用
GLuint aPosition; // 顶点位置引用
GLuint uColor; // 顶点颜色引用
int vertexCount = 0; // 顶点数量
float* vertices = NULL;
float* color = NULL;
Triangle(); // 构造函数
~Triangle();
void init();
void draw();
};
#endif //OPENGLES_TRIANGLE_H
将绘制三角形的代码封装成了类,主要为两个方法:init 和 draw。
Triangle.cpp ↓
//
// Created by sxh on 2018/6/22.
//
#include "Triangle.h"
Triangle::Triangle()
{
init();
}
Triangle::~Triangle()
{
delete [] vertices;
delete [] color;
}
void Triangle::init()
{
vertexCount = 3;
// 顶点坐标
vertices = new float[vertexCount * 3]
{
0, 0.5, 0,
-0.5, -0.5, 0,
0.5, -0.5, 0
};
// 顶点颜色
color = new float[4]
{
0, 1, 0, 1
};
char vsh[] = "attribute vec4 aPosition; // 顶点位置\n"
"\n"
"void main() {\n"
" gl_Position = aPosition;\n"
"}";
char fsh[] = "precision mediump float;\n"
"uniform vec4 uColor; // 顶点颜色\n"
"\n"
"void main() {\n"
" gl_FragColor = uColor;\n"
"}";
// 创建着色器程序
program = createProgram(vsh, fsh);
// 获取着色器中的属性引用
aPosition = glGetAttribLocation(program, "aPosition");
uColor = glGetUniformLocation(program, "uColor");
// 使用着色器程序
glUseProgram(program);
// 给着色器传递顶点数据
glVertexAttribPointer(aPosition, 3, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(aPosition);
// 给着色器传递颜色数据
glUniform4fv(uColor, 1, color);
}
void Triangle::draw()
{
// 绘制三角形
glDrawArrays(GL_TRIANGLES, 0, vertexCount);
}
代码中的注释已经写得比较清晰了,大致过程就是:
- 初始化顶点坐标及顶点颜色数据;
- 创建着色器;
- 给着色器传递数据;
- 绘制;
怎么样,是不是很简单?ヽ(゜▽゜ )-C<(/;◇;)/~
3.渲染
最后只要在Renderer中调用Triangle就好了
Renderer.cpp ↓
#include "Renderer.h"
#include "Platform.h"
#include "Triangle.h"
Triangle *triangle;
void surfaceCreated() {
// 指定刷新颜色缓冲区的颜色
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
triangle = new Triangle();
}
void surfaceChanged(int w, int h) {
ESLog("viewport: %d, %d", w, h);
// 设置视口
glViewport(0, 0, w, h);
}
void drawFrame() {
// 清除颜色缓冲区
glClear(GL_COLOR_BUFFER_BIT);
triangle->draw();
}
运行结果(左iOS,右Android):

后记
下一篇介绍OpenGL ES画矩形,并加载本地图片作为纹理显示。
网友评论