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 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.mfbz.cn/a/747501.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

调试代码Pair-wise-Similarity-module-master

第一步:运行.py文件生成json文件 问题一:json.decoder.JSONDecodeError: Invalid \escape: line 1 column 31616 (char 31615) 解决: for dataset in dataset_list:with open(datasetmap[dataset] ".csv", "r") as li…

ETO外汇:日元技术分析,美元/日元、欧元/日元、英镑/日元未来走势如何?

摘要: 根据近期的市场分析,美元/日元、欧元/日元和英镑/日元这三组货币对在未来的走势将受到多方面因素的影响。本文将从技术角度对每一组货币对进行详细分析,帮助投资者了解可能的支撑和阻力位,以及未来的走势预期。通过对关键技…

基于Transformer的自监督学习在NLP中的前沿应用

1. 引言 自然语言处理(NLP)领域正经历一场由自监督学习(Self-Supervised Learning, SSL)和Transformer架构共同驱动的革命。自监督学习通过巧妙地利用未标注数据,大大减少了对人工标注的依赖,而Transforme…

第二节课 6月13日 ssh密钥登陆方式

centos和ubuntu openssh服务的初始安装 一、实验:ubuntu系统激活root用户 ubuntu系统如何激活root用户,允许root用户ssh登陆? 1、ubuntu默认root用户未设置密码,未激活 激活root用户,设置root密码 sudo passwd roo…

无线幅频仪制作(WiFi通信)-含STM32源程序,JAVA上位机与设计报告

资料下载地址:无线幅频仪制作(WiFi通信)-含STM32源程序,JAVA上位机与设计报告 目录 项目功能 1、 系统方案1.1 比较与选择 1.1.1 控制器的论证与选择 1.1.2 信号源的论证与选择 1.1.3 放大器模块的论证与选择 1.1.4 键盘与显示模块的论证与选择 1.1.5 网络通…

GPOPS-II教程(3): 航天器最优控制问题

文章目录 问题描述GPOPS代码main functioncontinuous functionendpoint function完整代码代码仿真结果 最后 问题描述 例子出自论文 Direct solution of nonlinear optimal control problems using quasilinearization and Chebyshev polynomials(DOI:1…

CircuitBreaker断路器-Resilience4j

目录 背景分布式架构面临的问题:服务雪崩如何解决? CircuitBreakerResilience4jCircuitBreaker 服务熔断服务降级三种状态转换例子参数配置案例demo作业 BulkHead隔离特性SemaphoreBulkhead使用了信号量FixedThreadPoolBulkhead使用了有界队列和固定大小…

Ubuntu22安装PyCharm

下载(社区版) 官网下载地址 解压 sudo tar -xzvf pycharm-community-2024.1.4.tar.gz 软件移动到指定目录下(根据不同版本修改) sudo mv pycharm-community-2024.1.4/ /usr/local/PyCharm/运行 cd /usr/local/PyCharm/pycha…

Altera不同系列的型号命名规则

Altera芯片型号:10AX07H4F34I3SG 20nm工艺 资源: 大数据 云计算 人工智能 图像处理 MSEL

固定翼无人机入门(二)

这里讲讲无人机的路径跟踪控制相关知识,路径跟踪需要制导率(平面)和控制器,在无人机中较为常用的是L1制导率,不过L1制导率是控制无人机在二维平面上的转向,此处还引入总能量控制,控制无人机的高…

Vue3学习笔记<->开发环境安装

背景 公司开始做产品开发,前端就选择使用了vue,替换了传统的jsp。公司要求每个开发人员都要前后端都可以开发,于是就开始学习vue了。 安装环境 安装node.js node.js下载地址:node.js下载地址 安装:选在安装路径&…

Web渗透:逻辑漏洞

逻辑漏洞是指应用程序的逻辑中存在缺陷,导致应用程序无法按照预期执行,可能被攻击者利用来执行未授权的操作或绕过安全措施。逻辑漏洞通常不依赖于常见的输入验证漏洞或技术漏洞,而是利用系统设计或实现中的问题;本文以两个例子举…

makefile中的用户自定义变量

makefile: CC gcc CFLAGS -Isub -Isub -O2 OBJS add_int.o add_float.o sub_int.o sub_float.o main.o TARGET ccb RM rm -f $(TARGET):$(OBJS)$(CC) -o $(TARGET) $(OBJS) $(CFLAGS) $(OBJS):%.o:%.c$(CC) -c $(CFLAGS) $< -o $ clean:-$(RM) $(TARGET) $(OBJS)编译运…

使用命令行创建uniapp+TS项目,使用vscode编辑器

一:如果没有pnpm,先安装pnpm 二:使用npx工具和degit工具从 GitHub 上的 dcloudio/uni-preset-vue 仓库克隆一个名为 vite-ts 的分支,到项目中. 执行完上面命令后,去manifest.json添加appid(自己微信小程序的Id),也可不执行直接下一步,执行pnpm install ,再执行pnpm:dev:mp-weix…

OPenFast中AeroDyn,ElastoDyn,ElastoDyn_Tower,ServoDyn的作用!

在OpenFAST中&#xff0c;这四个文件分别有不同的作用&#xff0c;它们用于定义风力涡轮机不同部分的特性和行为。以下是每个文件的总结及其作用&#xff1a; NRELOffshrBsline5MW_Onshore_AeroDyn15.dat 作用&#xff1a;这是AeroDyn模块的输入文件&#xff0c;用于定义风力涡…

Android C++系列:内存知识整理

1. 控制C的内存分配 在嵌入式系统中使用C的一个常见问题是内存分配&#xff0c;即对new 和 delete 操作符的失控。 具有讽刺意味的是&#xff0c;问题的根源却是C对内存的管理非常的容易而且安全。具体地说&#xff0c;当一个对象被消除时&#xff0c;它的析构函数能够安全的释…

基线核查--渗透

基线检查 基线核查概念 it中定义&#xff1a; 基线为初始的标准&#xff0c;以后更改就要经过授权&#xff0c;形成下一基线。 软件配置管理的基线&#xff1a;1功能基线&#xff0c;分配基线&#xff0c;产品基线 安全配置基线--基线核查 安全基线可以说是木桶理论&…

RocketMQ 和 Kafka 关于消息队列的推拉模式是怎么做的?

引言&#xff1a;在当今的大数据和分布式系统中&#xff0c;消息队列扮演着至关重要的角色&#xff0c;它们作为系统之间通信和数据传输的媒介&#xff0c;为各种场景下的数据流动提供了可靠的基础设施支持。在消息队列的设计中&#xff0c;推拉模式是两种常见的消息传递机制&a…

搜索引擎的原理与相关知识

搜索引擎是一种网络服务&#xff0c;它通过互联网帮助用户找到所需的信息。搜索引擎的工作原理主要包括以下几个步骤&#xff1a; 网络爬虫&#xff08;Web Crawler&#xff09;&#xff1a;搜索引擎使用网络爬虫&#xff08;也称为蜘蛛或机器人&#xff09;来遍历互联网&#…

云计算【第一阶段(21)】引导过程与服务控制

目录 一、linux操作系统引导过程 1.1、开机自检 1.2、MBR引导 1.3、GRUB菜单 1.4、加载 Linux 内核 1.5、init进程初始化 1.6、简述总结 1.7、初始化进程centos 6和7的区别 二、排除启动类故障 2.1、修复MBR扇区故障 2.1.1、 实验 2.2、修复grub引导故障 2.2.1、实…