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…...

掌握 SQL Server 中的 FLOOR 函数:数据舍入的艺术
掌握 SQL Server 中的 FLOOR 函数:数据舍入的艺术 引言 在数据分析和处理中,我们经常需要对数值进行精确控制,比如将数值舍入到特定的精度。SQL Server 提供了多种数学函数,其中 FLOOR 函数就是用来执行向上舍入操作的强大工具。…...

【折腾笔记】兰空图床使用Redis做缓存
前言 最近发现我部署在群晖NAS上的兰空图床程序在高并发的情况下会导致图片加载缓慢或出现图片加载失败的情况,于是我查阅了官方文档资料并进行了一系列的测试,发现兰空图床如果开启了原图保护功能,会非常的吃CPU的性能,尤其是在…...

【Ubuntu】如何用指令设置静态IP
这里介绍的是利用netplan 的配置文件一般在 /etc/netplan/ 目录下,文件名类似 01-network-manager-all.yaml。 用 nano/ vim 编辑器打开配置文件: sudo nano /etc/netplan/01-network-manager-all.yaml # 替换成你的文件名修改配置文件 network:versi…...

mechanize - 自动化与HTTP web服务器的交互操作
1、前言 随着自动化测试的普及与落地推广,出现了众多知名的自动化测试工具,如Selenium 、Robot Framework、Playwright等。本文将介绍一款在Python环境下的mechanize库,这个库能够模拟浏览器行为,支持发送HTTP请求、解析HTML页面和…...

【Android】保留elevation层级效果,舍弃阴影效果
关于elevation属性 elevation是高度,海拔的意思 该属性可以设置View在父容器中的层级,即z属性 当view的elevation高于其它view时,它将显示在最上方,并产生阴影效果 关闭阴影效果 view的高度阴影,通过outlineProvi…...

Java新手启航:Windows下JDK安装,开启编程之旅
你是不是对编程充满好奇,想要迈入Java的世界,却不知道从何开始?别担心,每一个Java大师都是从安装JDK开始的,而今天,我将手把手教你如何轻松完成JDK的安装,让你迈出编程之旅的第一步! 接下来&am…...

c++指针和引用之高难度(二)习题讲解
1.【单选题】 int a[4] { 1001,1002,1003,1004 }; int* p{ &a[1] }; p[1] ? A 1001 B 1002 C 1003 解析:这道题考察了指针和数组可以混用。p 指向了 数组 a[0] 的地址,也就是 1002 的地址,此时 *p p[0]…...

UNIAPP编译到微信小程序时,会多一层以组件命名的标签
UNIAPP编译到微信小程序时,会多一层以组件命名的标签 解决方案 可以配置virtualHost来配置 export default {options: {virtualHost: true} }...

工业自动化控制中心
目录 一 设计原型 二 后台源码 一 设计原型 二 后台源码 using System; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms;namespace 工业自动化控制中心 {public partial class Form1 : Form{public Form1(){InitializeComponent();}pri…...

【Git】GitIgnore不生效
这里可能有两种原因,一个没有刷新Git缓存,二是Git忽略规则有问题 更新Git缓存 git rm -r --cached . git add . git commit -m "modify git ignore rule"Ignore规则 检查下忽略文件的目录表示是否正确 XXX忽略任意目录下名为XXX的文件 …...