OpenGL ES(OpenGL for Embedded Systems)和 OpenGL 是两个紧密相关但用途和设计目标不同的图形API。下面帮你详细梳理它们的区别:


OpenGL ES 与 OpenGL 的区别

方面OpenGLOpenGL ES
定位主要面向桌面和工作站平台专为嵌入式系统和移动设备设计
目标设备PC、工作站、笔记本手机、平板、游戏机、车载系统等
功能集功能丰富,支持多种高级特性精简版本,去掉部分复杂功能以适应性能和资源限制
版本号最新是 OpenGL 4.xOpenGL ES 有 1.0、2.0、3.x 等版本,功能逐步增强
编程模型支持固定功能管线和可编程管线1.x版本支持固定管线,2.0及以后版本仅支持可编程管线
扩展支持支持大量扩展,适合高端图形应用扩展有限,更注重基础性能和兼容性
性能与资源需求对硬件要求较高针对低功耗和资源有限设备优化
开发难度相对复杂,功能多简化接口,易于学习和使用

详细说明

1. 用途和设计目标

  • OpenGL 是桌面图形API,设计时考虑了高性能图形渲染和广泛功能支持。
  • OpenGL ES 是针对嵌入式设备(如智能手机、平板、嵌入式游戏机)优化,减少复杂功能,提升性能和效率。

2. 功能差异

  • OpenGL 有固定功能管线(传统)和可编程管线(Shader)两种模式。
  • OpenGL ES 1.x 支持固定管线,2.0+只支持可编程管线,强制使用Shader。
  • OpenGL 支持更多纹理格式、多重采样、多渲染目标等高级功能,OpenGL ES 省略或简化这些以降低硬件负担。

3. 性能与硬件需求

  • OpenGL 偏向高性能GPU,依赖强大的硬件。
  • OpenGL ES 适配移动GPU,注重功耗和带宽限制。

4. 开发环境差异

  • OpenGL 主要在 Windows、Linux、macOS 桌面环境开发。
  • OpenGL ES 广泛用于 Android、iOS、嵌入式 Linux 等移动和嵌入式系统。

总结

| 你需要桌面级高性能图形渲染,且硬件条件充足 → 选 OpenGL。
| 你开发移动端或嵌入式设备应用,且受限于功耗和性能 → 选 OpenGL ES。

好的!下面我帮你写一组简单的 OpenGL 和 OpenGL ES 的绘制三角形示例代码对比,演示两者的 API 差异和用法差异。示例均为核心代码片段,重点突出不同点。


1. OpenGL (桌面版) 简单绘制三角形

// 顶点着色器 (GLSL)
const char* vertexShaderSource = R"(
#version 330 core
layout (location = 0) in vec3 aPos;
void main() {
    gl_Position = vec4(aPos, 1.0);
}
)";

// 片段着色器
const char* fragmentShaderSource = R"(
#version 330 core
out vec4 FragColor;
void main() {
    FragColor = vec4(1.0, 0.5, 0.2, 1.0);
}
)";

void renderTriangle() {
    float vertices[] = {
        0.0f,  0.5f, 0.0f,  // 顶点1
       -0.5f, -0.5f, 0.0f,  // 顶点2
        0.5f, -0.5f, 0.0f   // 顶点3
    };

    unsigned int VBO, VAO;
    glGenVertexArrays(1, &VAO);  // 创建顶点数组对象
    glGenBuffers(1, &VBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // 使用着色器程序 (编译和链接代码略)

    glDrawArrays(GL_TRIANGLES, 0, 3);

    // 解绑
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

2. OpenGL ES 2.0 (移动嵌入式) 简单绘制三角形

// 顶点着色器 (GLSL ES)
const char* vertexShaderSource = R"(
attribute vec4 aPos;
void main() {
    gl_Position = aPos;
}
)";

// 片段着色器
const char* fragmentShaderSource = R"(
precision mediump float;
void main() {
    gl_FragColor = vec4(1.0, 0.5, 0.2, 1.0);
}
)";

void renderTriangle() {
    GLfloat vertices[] = {
        0.0f,  0.5f, 0.0f,  // 顶点1
       -0.5f, -0.5f, 0.0f,  // 顶点2
        0.5f, -0.5f, 0.0f   // 顶点3
    };

    GLuint VBO;
    glGenBuffers(1, &VBO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    GLint posAttrib = glGetAttribLocation(program, "aPos");
    glEnableVertexAttribArray(posAttrib);
    glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), 0);

    glDrawArrays(GL_TRIANGLES, 0, 3);

    glDisableVertexAttribArray(posAttrib);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

关键区别点总结

项目OpenGLOpenGL ES 2.0
着色器版本#version 330 core无版本或 #version 100
变量限定词in, outattribute(顶点),varying(片段)
片段颜色输出自定义输出变量只能写入 gl_FragColor
顶点数组对象(VAO)支持部分版本不支持(需手动管理)
精度限定符不需要需要在片段着色器声明精度
API 函数调用支持 VAO 等只能用 VBO 和手动管理顶点属性

明白!下面我给你写一个完整的、最简化的 OpenGL ES 2.0 三角形绘制示例(包含着色器编译、链接、绘制),示范基础的流程。代码是用 C 语言和 EGL + GLES2 的风格,适合嵌入式或移动平台开发参考。


OpenGL ES 2.0 简单三角形完整示例(核心代码)

#include <GLES2/gl2.h>
#include <EGL/egl.h>
#include <stdio.h>
#include <stdlib.h>

// 顶点着色器源码
const char* vertexShaderSrc =
    "attribute vec4 aPos;\n"
    "void main() {\n"
    "  gl_Position = aPos;\n"
    "}";

// 片段着色器源码
const char* fragmentShaderSrc =
    "precision mediump float;\n"
    "void main() {\n"
    "  gl_FragColor = vec4(1.0, 0.5, 0.2, 1.0);\n"
    "}";

// 编译着色器
GLuint compileShader(GLenum type, const char* src) {
    GLuint shader = glCreateShader(type);
    glShaderSource(shader, 1, &src, NULL);
    glCompileShader(shader);

    // 检查编译状态
    GLint compiled;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
    if (!compiled) {
        GLint infoLen = 0;
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
        if (infoLen) {
            char* infoLog = (char*)malloc(infoLen);
            glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
            printf("Shader compile error: %s\n", infoLog);
            free(infoLog);
        }
        glDeleteShader(shader);
        return 0;
    }
    return shader;
}

// 创建着色器程序
GLuint createProgram(const char* vertSrc, const char* fragSrc) {
    GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertSrc);
    GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragSrc);
    if (!vertexShader || !fragmentShader) return 0;

    GLuint program = glCreateProgram();
    glAttachShader(program, vertexShader);
    glAttachShader(program, fragmentShader);
    glBindAttribLocation(program, 0, "aPos"); // 绑定顶点属性位置0
    glLinkProgram(program);

    // 检查链接状态
    GLint linked;
    glGetProgramiv(program, GL_LINK_STATUS, &linked);
    if (!linked) {
        GLint infoLen = 0;
        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
        if (infoLen) {
            char* infoLog = (char*)malloc(infoLen);
            glGetProgramInfoLog(program, infoLen, NULL, infoLog);
            printf("Program link error: %s\n", infoLog);
            free(infoLog);
        }
        glDeleteProgram(program);
        return 0;
    }

    // 删除着色器对象
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
    return program;
}

int main(int argc, char** argv) {
    // 省略 EGL 初始化上下文的代码(不同平台不同,需先创建 EGLContext 和 EGLSurface)

    // 创建程序
    GLuint program = createProgram(vertexShaderSrc, fragmentShaderSrc);
    if (!program) {
        printf("Failed to create program\n");
        return -1;
    }

    // 三角形顶点数据
    GLfloat vertices[] = {
        0.0f,  0.5f, 0.0f,  // 顶点1
       -0.5f, -0.5f, 0.0f,  // 顶点2
        0.5f, -0.5f, 0.0f   // 顶点3
    };

    // 使用程序
    glUseProgram(program);

    // 传递顶点数据
    GLint posAttrib = glGetAttribLocation(program, "aPos");
    glEnableVertexAttribArray(posAttrib);
    glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 0, vertices);

    // 清屏
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);

    // 绘制三角形
    glDrawArrays(GL_TRIANGLES, 0, 3);

    // 交换缓冲(平台相关)

    // 省略 EGL 清理代码

    return 0;
}

说明:

  • compileShader:编译顶点或片段着色器,包含错误检测。
  • createProgram:创建并链接着色器程序。
  • 使用 glVertexAttribPointerglEnableVertexAttribArray 传递顶点数据。
  • 省略了 EGL(或其他平台上下文)初始化和交换缓冲,因平台差异较大。
  • 这个示例展示了 OpenGL ES 2.0 的核心渲染流程和 API 使用。

明白!这里给你一个基于 Windows + GLFW + OpenGL 3.3 的完整最简绘制三角形示例代码。用 C 语言写,包含窗口创建、OpenGL 上下文初始化、着色器编译和渲染循环。


Windows + GLFW + OpenGL 3.3 三角形示例

#include <GL/glew.h>    // GLEW 用于加载 OpenGL 函数
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <stdlib.h>

// 顶点着色器源码
const char* vertexShaderSource = "#version 330 core\n"
    "layout (location = 0) in vec3 aPos;\n"
    "void main() {\n"
    "  gl_Position = vec4(aPos, 1.0);\n"
    "}\0";

// 片段着色器源码
const char* fragmentShaderSource = "#version 330 core\n"
    "out vec4 FragColor;\n"
    "void main() {\n"
    "  FragColor = vec4(1.0, 0.5, 0.2, 1.0);\n"
    "}\0";

void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
    glViewport(0, 0, width, height);
}

int main() {
    // 初始化 GLFW
    if (!glfwInit()) {
        fprintf(stderr, "Failed to initialize GLFW\n");
        return -1;
    }

    // 设置 OpenGL 版本(3.3核心版)
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // MacOS 需要
#endif

    // 创建窗口
    GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL 3.3 Triangle", NULL, NULL);
    if (!window) {
        fprintf(stderr, "Failed to create GLFW window\n");
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);

    // 初始化 GLEW
    glewExperimental = GL_TRUE; // 使 GLEW 使用现代方法获取函数指针
    if (glewInit() != GLEW_OK) {
        fprintf(stderr, "Failed to initialize GLEW\n");
        return -1;
    }

    // 设置视口大小
    glViewport(0, 0, 800, 600);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    // 编译顶点着色器
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);

    // 检查编译错误
    GLint success;
    char infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        fprintf(stderr, "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n%s\n", infoLog);
    }

    // 编译片段着色器
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);

    // 检查编译错误
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        fprintf(stderr, "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n%s\n", infoLog);
    }

    // 创建着色器程序并链接
    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    // 检查链接错误
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        fprintf(stderr, "ERROR::PROGRAM::LINKING_FAILED\n%s\n", infoLog);
    }

    // 删除着色器对象,已链接到程序中
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    // 顶点数据(一个三角形)
    float vertices[] = {
         0.0f,  0.5f, 0.0f,  // 顶点1
        -0.5f, -0.5f, 0.0f,  // 顶点2
         0.5f, -0.5f, 0.0f   // 顶点3
    };

    // 创建 VAO 和 VBO
    GLuint VAO, VBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    // 绑定 VAO
    glBindVertexArray(VAO);

    // 绑定 VBO 并上传数据
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // 解绑
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    // 渲染循环
    while (!glfwWindowShouldClose(window)) {
        // 输入
        if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
            glfwSetWindowShouldClose(window, 1);

        // 渲染指令
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // 使用着色器程序,绘制三角形
        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLES, 0, 3);

        // 交换缓冲区和轮询事件
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // 释放资源
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteProgram(shaderProgram);

    glfwTerminate();
    return 0;
}

使用说明:

  • 需要先安装 GLFW(官网:https://www.glfw.org/ )和 GLEW(官网:http://glew.sourceforge.net/)
  • 编译时链接 glfw3.libglew32.lib 和 OpenGL 库(Windows上是 opengl32.lib
  • 该示例用现代 OpenGL 3.3 核心版本,使用着色器编程和顶点数组对象(VAO)