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

2024-06-23 18:12

本文主要是介绍OpenGL-ES 学习(6)---- 立方体绘制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

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

立方体绘制基本原理

一个立方体是由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 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, &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 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)---- 立方体绘制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1087897

相关文章

使用Python绘制蛇年春节祝福艺术图

《使用Python绘制蛇年春节祝福艺术图》:本文主要介绍如何使用Python的Matplotlib库绘制一幅富有创意的“蛇年有福”艺术图,这幅图结合了数字,蛇形,花朵等装饰,需要的可以参考下... 目录1. 绘图的基本概念2. 准备工作3. 实现代码解析3.1 设置绘图画布3.2 绘制数字“2025”3.3

使用Python绘制可爱的招财猫

《使用Python绘制可爱的招财猫》招财猫,也被称为“幸运猫”,是一种象征财富和好运的吉祥物,经常出现在亚洲文化的商店、餐厅和家庭中,今天,我将带你用Python和matplotlib库从零开始绘制一... 目录1. 为什么选择用 python 绘制?2. 绘图的基本概念3. 实现代码解析3.1 设置绘图画

Python绘制土地利用和土地覆盖类型图示例详解

《Python绘制土地利用和土地覆盖类型图示例详解》本文介绍了如何使用Python绘制土地利用和土地覆盖类型图,并提供了详细的代码示例,通过安装所需的库,准备地理数据,使用geopandas和matp... 目录一、所需库的安装二、数据准备三、绘制土地利用和土地覆盖类型图四、代码解释五、其他可视化形式1.

如何用Python绘制简易动态圣诞树

《如何用Python绘制简易动态圣诞树》这篇文章主要给大家介绍了关于如何用Python绘制简易动态圣诞树,文中讲解了如何通过编写代码来实现特定的效果,包括代码的编写技巧和效果的展示,需要的朋友可以参考... 目录代码:效果:总结 代码:import randomimport timefrom math

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss