OpenGLES2之Android&iOS跨平台开发教程(三)绘制三角形

前言


前面介绍完了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);
}

代码中的注释已经写得比较清晰了,大致过程就是:
1. 初始化顶点坐标及顶点颜色数据;
2. 创建着色器;
3. 给着色器传递数据;
4. 绘制;

怎么样,是不是很简单?ヽ(゜▽゜ )-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画矩形,并加载本地图片作为纹理显示。

猜你喜欢

转载自blog.csdn.net/suwk1009/article/details/80777058