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…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
yaml读取写入常见错误 (‘cannot represent an object‘, 117)
错误一:yaml.representer.RepresenterError: (‘cannot represent an object’, 117) 出现这个问题一直没找到原因,后面把yaml.safe_dump直接替换成yaml.dump,确实能保存,但出现乱码: 放弃yaml.dump,又切…...
pgsql:还原数据库后出现重复序列导致“more than one owned sequence found“报错问题的解决
问题: pgsql数据库通过备份数据库文件进行还原时,如果表中有自增序列,还原后可能会出现重复的序列,此时若向表中插入新行时会出现“more than one owned sequence found”的报错提示。 点击菜单“其它”-》“序列”,…...
