OpenGL-ES 学习(6)---- 立方体绘制
目录
- 立方体绘制基本原理
- 立方体的顶点坐标和绘制顺序
- 立方体颜色和着色器
- 实现效果和参考代码
立方体绘制基本原理
一个立方体是由8个顶点组成,共6个面,所以绘制立方体本质上就是绘制这6个面共12个三角形

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

立方体的顶点坐标和绘制顺序
立方体坐标定义如下:
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个三角形,不同的面和顶点的绑定关系如下:






立方体颜色和着色器
这里为立方体的每个顶点定义不同的颜色,同时在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";
实现效果和参考代码
最终实现效果:


参考代码如下:
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 codeGLuint programObject = esLoadProgram(vertexShaderSource, fragmentShaderSource);if (programObject == 0) {return GL_FALSE;}// turn on depth testglEnable(GL_DEPTH_TEST);glDepthFunc(GL_LESS);glClearColor(0.0, 0.0, 0.0, 1.0);// Store the program objectuserData->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 indicesif (userData->vboIds[0] == 0 && userData->vboIds[1] == 0) {// Only allocate on the first drawglGenBuffers(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_BUFFERglBindBuffer(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, ¤tts);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 viewportglViewport(0, 0, 640, 480);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glUseProgram(userData->programObject);uMVPMatrixUpdateRotate(esContext,userData->deltaTime);DrawPrimitiveWithVBOs(esContext);// Swap bufferseglSwapBuffers(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);}
}
相关文章:
OpenGL-ES 学习(6)---- 立方体绘制
目录 立方体绘制基本原理立方体的顶点坐标和绘制顺序立方体颜色和着色器实现效果和参考代码 立方体绘制基本原理 一个立方体是由8个顶点组成,共6个面,所以绘制立方体本质上就是绘制这6个面共12个三角形 顶点的坐标体系如下图所示,三维坐标…...
《数据结构与算法基础 by王卓老师》学习笔记——类C语言有关操作补充
1.元素类型说明 2.数组定义 3.C语言的内存动态分配 4..C中的参数传递 5.传值方式 6.传地址方式 例子...
高频面试题基本总结回顾2(含笔试高频算法整理)
干货分享,感谢您的阅读! (暂存篇---后续会删除,完整版和持续更新见高频面试题基本总结回顾(含笔试高频算法整理)) 备注:引用请标注出处,同时存在的问题请在相关博客留言…...
《深入浅出MySQL:数据库开发、优化与管理维护(第3版)》
深入浅出MySQL sql执行流程第一步:通过连接器进行连接第二步:解析器解析 SQL第三步:执行SQL 行记录存储格式行溢出日志数据库三大范式第一范式第二范式第三范式 索引索引分类B树索引BTree vs Hash需要索引1、字段需要频繁的查询操作2、字段用…...
VBA技术资料MF171:创建指定工作表数的工作簿
我给VBA的定义:VBA是个人小型自动化处理的有效工具。利用好了,可以大大提高自己的工作效率,而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套,分为初级、中级、高级三大部分,教程是对VBA的系统讲解&#…...
【效率提升】新一代效率工具平台utools
下载地址:utools uTools这款软件,是一款功能强大且高度可定制的效率神器,使用快捷键alt space(空格) 随时调用,支持调用系统应用、用户安装应用和市场插件等。 utools可以调用系统设置和内置应用,这样可以方便快捷的…...
Jmeter插件管理器,websocket协议,Jmeter连接数据库,测试报告的查看
目录 1、Jmeter插件管理器 1、Jmeter插件管理器用处:Jmeter发展并产生大量优秀的插件,比如取样器、性能监控的插件工具等。但要安装这些优秀的插件,需要先安装插件管理器。 2、插件的下载,从Availabale Plugins中选择ÿ…...
Android中ViewModel+LiveData+DataBinding的配合使用(kotlin)
Android 中 ViewModel、LiveData 和 Data Binding 的配合使用(Kotlin) 摘要 本文将介绍如何在 Android 开发中结合使用 ViewModel、LiveData 和 Data Binding 进行数据绑定和状态更新。我们将详细探讨这三者之间的关系,并展示如何在 Kotlin…...
Elasticsearch 避免常见查询错误和陷阱
Elasticsearch 作为一款强大的搜索引擎和分析工具,已经被广泛应用于各种场景中。然而,在使用 Elasticsearch 进行查询时,如果不注意一些常见的错误和陷阱,可能会导致查询效率低下、结果不准确甚至系统性能下降。本文旨在总结一些常…...
【PyQt】20-QTimer(动态显示时间、定时关闭)
QTimer 前言一、QTimer介绍二、动态时间展示2.1 代码2.2 运行结果 三、定时关闭3.1 介绍他的两种用法1、使用函数或Lambda表达式2、带有定时器类型(高级) 3.2 代码3.3 运行结果 总结 前言 好久没学习了。 一、QTimer介绍 pyqt里面的多线程可以有两种实…...
[深度学习] 自编码器Autoencoder
自编码器(Autoencoder)是一种无监督学习算法,主要用于数据的降维、特征提取和数据重建。自编码器由两个主要部分组成:编码器(Encoder)和解码器(Decoder)。其基本思想是将输入数据映射…...
模型微调、智能体、知识库之间的区别
使用开源模型微调和使用知识库与智能体(agent)的区别主要体现在工作原理、应用场景和实现目标上。以下是对这三者的详细对比: 开源模型微调 定义: 微调是对预训练模型(例如BERT、GPT等)进行额外训练&…...
七日世界Once Human跳ping、延迟高、丢包怎么办?
七日世界是一款开放世界为轴点的生存射击游戏,玩家将进入一个荒诞、荒芜的末日世界,在这里与好友一起对抗可怖的怪物和神秘物质星尘的入侵,给这个星球留下最后的希望,共筑一片安全的领地。不过有部分玩家在游玩七日世界的时候&…...
机器人控制系列教程之关节空间运动控制器搭建(1)
机器人位置控制类型 机器人位置控制分为两种类型: 关节空间运动控制—在这种情况下,机器人的位置输入被指定为一组关节角度或位置的向量,这被称为机器人的关节配置,记作q。控制器跟踪一个参考配置,记作 q r e f q_{re…...
[linux]sed命令基础入门详解
sed是一种流编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”,接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这…...
Charles抓包工具系列文章(一)-- Compose 拼接http请求
一、背景 众所周知,Charles是一款抓包工具,当然是http协议,不支持tcp。(如果你想要抓tcp包,请转而使用wireshark,在讲述websocket的相关技术有梳理过wireshark抓包) 话说回来,char…...
OLMo:真正完全开源的大模型
最近,又有一家机构AI2(Allen Institute for AI)开源了一个LLM:OLMo,它的英文全称就叫Open Language Model。相比之前开源的大模型,OLMo的独特之处是完全开源,除了训练的模型,OLMo还开…...
51单片机STC89C52RC——12.1 数据存储芯片AT24C02
目的/效果 利用存储芯片AT24C02存储数据,LCD1602显示存储的数据。 一,STC单片机模块 二,AT24C02存储芯片 2.1 介绍 AT24C02是一个2K位串行CMOS E2PROM,内部含有256个8位字节,采用先进CMOS技术实质上减少了器件的功…...
融入云端的心跳:在Spring Cloud应用中集成Eureka Client
融入云端的心跳:在Spring Cloud应用中集成Eureka Client 引言 在微服务架构中,服务发现是一个关键组件,它允许服务实例之间相互发现并通信。Netflix Eureka是Spring Cloud体系中广泛使用的服务发现框架。Eureka提供了一个服务注册中心&…...
CocosCreator构建IOS的wwise教程
CocosCreator构建IOS教程 添加wwise教程: 1.添加include 2.添加SoundEngine 3.添加Profile-iphoneos下面lib下面的.a 4.导入js调用C++的文件 5.导入这些文件 6.初始化ios绝对路径和TTS语音合成对象 6.获得根目录绝对路径,加载pck需要找到绝对路径。怎么找绝对路径? #impor…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
rknn toolkit2搭建和推理
安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 ,不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源(最常用) conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...
书籍“之“字形打印矩阵(8)0609
题目 给定一个矩阵matrix,按照"之"字形的方式打印这个矩阵,例如: 1 2 3 4 5 6 7 8 9 10 11 12 ”之“字形打印的结果为:1,…...
