LearnOpenGL_Hello Triangle

本文详细介绍了OpenGL中的VertexBufferObject (VBO) 和VertexArrayObject (VAO) 的概念及其使用方法。VBO用于管理显存中的顶点数据,而VAO则封装了渲染对象的状态,包括EBO和顶点属性指针配置等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

Vertex Buffer Object(VBO)

一个openGL系统中可以有多个VBO,我们利用VBO来管理显存,VBO不是存储空间,一个VBO在显存中映射一块用于存储顶点数据的空间,并使用VBO中存储的数据来描述和管理这块空间,因此VBO是对象/结构体。系统中每次只能绑定一个VBO,绑定后就能访问到这个VBO对应的空间。绑定VBO就相当于在操作系统中更换页表,保证对存储空间访问的独立性。

Vertex Array Object(VAO)

VAO相当于一个进程控制块,主要用于保存进程上下文。当我们要切换进程时(更换渲染对象),我们需要切换EBO、顶点属性指针配置等,为了将这些切换操作进行封装,我们将这些需要切换的内容封装在VAO。于是所有的切换操作简化为一次VAO的bind。从VAO绑定到VAO解绑为止,glVertexAttribPointer、glEnableVertexAttribArray、glEnableVertexAttribArray、glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO)、glDisableVertexAttribArray产生作用的结果都会保存在VAO中。

注意:VAO不直接保存绑定的VBO,而是通过glVertexAttribPointer的调用,更新VAO中存储的指向显存的指针,及顶点数据存储的方式(stride)。当调用glVertexAttribPointer时,由于已经处在某个VBO的上下文中,所访问到的地址必定是当前VBO所对应的地址,直接将这个地址存储在指针中,不需要另外存储VBO。可以通过修改代码验证VAO的存储方式。

 

    ///create a vertex buffer obj
    unsigned int VBO;
    glGenBuffers(1, &VBO);
    ///bind the obj to mem
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    ///cp data
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);


    ///create a vertex array obj
    unsigned int VAO;
    glGenVertexArrays(1, &VAO);
    ///进入VAO的上下文   在此之前已进入VBO,使用VBO对应的存储空间
    glBindVertexArray(VAO);


    ///create a element buffer obj
    unsigned int EBO;
    glGenBuffers(1, &EBO);
    ///绑定EBO 在VAO中记录EBO 用于下次绑定VAO时,绑定EBO
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    ///设置指针属性,并保存至VAO,注意此时仍使用之前绑定的VBO,因此指针指向VBO对应的存储区
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    ///在解绑VAO之前解绑VBO不影响VAO的设置
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

 结果:

 


 修改解绑VBO的时间,如下:

    ///在设置指针属性之前解绑VBO
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);


    //glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

 结果:

在设置指针属性之前解绑VBO,导致不能正确的访问到VBO对应的存储区,不能为VAO的指针设置正确的地址,导致出错。


修改绑定VBO的时间,如下: 

    ///create a vertex buffer obj
    unsigned int VBO;
    glGenBuffers(1, &VBO);
    ///bind the obj to mem
    //glBindBuffer(GL_ARRAY_BUFFER, VBO);
    ///cp data
    //glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);


    ///create a vertex array obj
    unsigned int VAO;
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);




    ///create a element buffer obj
    unsigned int EBO;
    glGenBuffers(1, &EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);


    ///修改绑定VBO的时间
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);


    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

结果: 

 只要在设置指针属性之前绑定VBO就能正确设置指针。


在解绑VAO之前解绑EBO,如下:

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    ///解绑EBO
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

 结果:

 VAO保存的是在解绑解绑VAO之前,最后的EBO状态,因此,VAO保存的EBO id是0,导致错误。由于VAO不直接存储VBO,在解绑VAO之前,是可以解绑VBO的。

 

 

 

 

### 使用 `lv_draw_triangle` 函数绘制三角形 在 LVGL 图形库中,`lv_draw_triangle` 是用于绘制三角形的一个重要函数。为了正确使用该函数来创建并显示一个三角形,需要了解其参数以及如何配置绘图对象。 以下是具体实现方式: #### 创建和初始化绘图区域 首先,在调用 `lv_draw_triangle` 前需准备好绘图缓冲区与上下文环境。通常情况下这一步由框架自动完成;但如果是在自定义场景下工作,则可能要手动设置这些资源。 ```c // 初始化LVGL库 (一般只需要做一次) lv_init(); // 如果硬件支持的话可以初始化显示器驱动 disp_drv_t disp_drv; disp_drv.init = my_disp_init; /*Display init function*/ disp_drv.flush = my_disp_flush; /*Flush callback to draw the framebuffer on the display*/ lv_disp_drv_register(&disp_drv); ``` #### 定义顶点坐标 接着定义构成目标三角形三个角的坐标位置。这里假设我们要在一个矩形窗口内居中放置一个小三角形作为例子说明。 ```c static void create_centered_triangle(lv_obj_t *parent){ // 获取父容器尺寸以计算中心点偏移量 lv_area_t parent_coords; lv_obj_get_coords(parent, &parent_coords); int16_t width = lv_area_get_width(&parent_coords); int16_t height = lv_area_get_height(&parent_coords); // 计算三角形各顶点相对于父级控件的位置 const lv_point_t triangle_points[] = { {width / 2 - 50 ,height/2}, // 左侧底部端点 {width / 2 ,height/2-87}, // 上方尖端 {width / 2 + 50 ,height/2} // 右侧底部端点 }; } ``` #### 调用 `lv_draw_triangle` 进行渲染 最后就是实际执行绘制操作的部分了。注意传递给此函数的是之前准备好的顶点数组指针以及其他必要的样式属性等信息。 ```c void draw_triangle_on_canvas(){ static lv_style_t style; // 设置填充颜色和其他视觉效果 lv_style_init(&style); lv_style_set_bg_color(&style, lv_palette_main(LV_PALETTE_RED)); lv_style_set_border_width(&style, 0); // 开始绘画过程... lv_opa_t opa = LV_OPA_COVER; // 不透明度设为完全不透光 bool anti_aliasing = true; // 启用抗锯齿功能 lv_draw_ctx_t ctx; lv_draw_ctx_init(&ctx, NULL, &style, NULL); // 执行真正的图形绘制命令 lv_draw_triangle(&ctx, triangle_points, // 输入顶点列表 sizeof(triangle_points)/sizeof(*triangle_points), // 点数 &style, // 样式描述符 opa, // 整体透明度级别 anti_aliasing); // 是否开启边缘平滑处理 } ``` 以上代码片段展示了如何利用 `lv_draw_triangle` 来构建一个简单的红色等腰直角三角形,并将其置于指定容器内的中央位置[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值