OpenGL顶点规范和绘图命令:通用顶点属性的数组 Specifying Arrays for Generic Vertex Attributes

  1. OpenGL顶点规范和绘图命令 Vertex Specification and Drawing Commands
  2. 图元类型 Primitive Types
  3. 当前顶点属性值 Current Vertex Attribute Values
  4. 顶点数组 Vertex Arrays
  5. 通用顶点属性的数组 Specifying Arrays for Generic Vertex Attributes
  6. 顶点属性除数 Vertex Attribute Divisors
  7. 使用顶点数组绘制命令 Drawing Commands Using Vertex Arrays
  8. 条件渲染 Conditional Rendering

在OpenGL中,为了设置顶点数组对象(VAO)中通用顶点属性数组的组织结构,以及如何将缓冲对象绑定到VAO以便提供顶点数据,您可以使用以下函数:

  1. 设置顶点属性格式

     void VertexAttribFormat( uint attribindex, int size, enum type, boolean normalized, uint relativeoffset );
    
     void VertexAttribIFormat( uint attribindex, int size, enum type, uint relativeoffset );
    
     void VertexAttribLFormat( uint attribindex, int size, enum type, uint relativeoffset );
    
     void VertexArrayAttribFormat( uint vaobj, uint attribindex, int size, enum type, boolean normalized, uint relativeoffset );
    
     void VertexArrayAttribIFormat( uint vaobj, uint attribindex, int size, enum type, uint relativeoffset );
    
     void VertexArrayAttribLFormat( uint vaobj, uint attribindex, int size, enum type, uint relativeoffset );
    
    • VertexAttribFormatVertexAttribIFormatVertexAttribLFormat这三个函数用于指定每个顶点属性数组的布局。它们分别对应浮点数、整数和双精度浮点数类型的属性。
    • 同样地,对于特定VAO,有对应的VertexArrayAttribFormatVertexArrayAttribIFormatVertexArrayAttribLFormat函数。

    这些函数的参数包括:

    • attribindex:要配置的顶点属性索引。
    • size:每个顶点中该属性所包含的值的数量(如3表示一个三维向量)。
    • type:存储在数组中的数据类型(如GL_FLOAT、GL_UNSIGNED_INT等)。
    • normalized(仅适用于某些类型):如果为true,则表示整型数据应归一化到[0, 1]或[-1, 1]区间。
    • relativeoffset:相对于关联的顶点缓冲开始位置的偏移量(以字节计)。
    // 生成并绑定顶点数组对象 (VAO)
     GLuint vao;
     glGenVertexArrays(1, &vao);
     glBindVertexArray(vao);
    
     // 生成并绑定顶点缓冲对象 (VBO)
     GLuint vbo;
     glGenBuffers(1, &vbo);
     glBindBuffer(GL_ARRAY_BUFFER, vbo);
    
     // 顶点数据
     GLfloat vertices[] = {
         0.0f,  0.5f, 0.0f,  // 顶点1坐标
     -0.5f, -0.5f, 0.0f,  // 顶点2坐标
         0.5f, -0.5f, 0.0f   // 顶点3坐标
     };
    
     // 将顶点数据传递到顶点缓冲中
     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
     // 配置顶点属性
     // 在这里,我们使用通用顶点属性0表示顶点位置,每个顶点有3个分量 (x, y, z),浮点型数据
     glVertexAttribFormat(0, 3, GL_FLOAT, GL_FALSE, 0);
    
     // 启用顶点属性数组
     glEnableVertexAttribArray(0);
    
     // 设置顶点缓冲绑定点,此处为0
     glBindVertexBuffer(0, vbo, 0, 3 * sizeof(GLfloat));
    
     // 解绑顶点数组对象和顶点缓冲对象
     glBindVertexArray(0);
     glBindBuffer(GL_ARRAY_BUFFER, 0);
    
     // 渲染循环中的绘制代码...
    
    // 生成并绑定顶点数组对象 (VAO)
     GLuint vao;
     glCreateVertexArrays(1, &vao);
    
     // 生成并绑定顶点缓冲对象 (VBO)
     GLuint vbo;
     glCreateBuffers(1, &vbo);
    
     // 顶点数据
     GLfloat vertices[] = {
         0.0f,  0.5f, 0.0f,  // 顶点1坐标
     -0.5f, -0.5f, 0.0f,  // 顶点2坐标
         0.5f, -0.5f, 0.0f   // 顶点3坐标
     };
    
     // 将顶点数据传递到顶点缓冲中
     glNamedBufferData(vbo, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
     // 配置顶点属性
     // 在这里,我们使用通用顶点属性0表示顶点位置,每个顶点有3个分量 (x, y, z),浮点型数据
     glVertexArrayAttribFormat(vao, 0, 3, GL_FLOAT, GL_FALSE, 0);
    
     // 启用顶点属性数组
     glEnableVertexArrayAttrib(vao, 0);
    
     // 设置顶点缓冲绑定点,此处为0
     glVertexArrayVertexBuffer(vao, 0, vbo, 0, 3 * sizeof(GLfloat));
    
     // 解绑顶点数组对象和顶点缓冲对象
     // 注意:此处不再需要调用 glBindVertexArray 和 glBindBuffer
     // Vertex Array Object (VAO) 包含了顶点缓冲的状态,因此在渲染时只需绑定 VAO 即可
     // Vertex Buffer Object (VBO) 也包含在 VAO 绑定状态中
     // 不同于 glBindBuffer,glBindVertexArray 不再需要
    
  2. 绑定顶点缓冲

    void BindVertexBuffer( uint bindingindex, uint buffer, intptr offset, sizei stride );
    
    void VertexArrayVertexBuffer( uint vaobj, uint bindingindex, uint buffer, intptr offset, sizei stride );
    
    • 使用BindVertexBufferVertexArrayVertexBuffer命令将一个缓冲对象绑定到VAO的特定绑定点,作为顶点数据源。
      • bindingindex:指定顶点缓冲区的绑定点。
      • buffer:要绑定的缓冲对象名称,若为0,则会解除当前绑定。
      • offset:从缓冲起始位置的偏移量。
      • stride:连续两个顶点之间的字节数。
  3. 同时绑定多个顶点缓冲

    void BindVertexBuffers( uint first, sizei count, const uint *buffers, const intptr *offsets, const sizei *strides );
    void VertexArrayVertexBuffers( uint vaobj, uint first, sizei count, const uint *buffers, const intptr *offsets, const sizei *strides );
    
    • BindVertexBuffersVertexArrayVertexBuffers函数可以一次绑定多个缓冲对象到不同的顶点缓冲区绑定点。

      for (i = 0; i < count; i++) {
          if (buffers == NULL) {
              BindVertexBuffer(first + i, 0, 0, 16);
          } else {
              BindVertexBuffer(first + i, buffers[i], offsets[i], strides[i]);
          }
      }
      
      for (i = 0; i < count; i++) {
          if (buffers == NULL) {
              VertexArrayVertexBuffer(vaobj, first + i, 0, 0, 16);
          } else {
              VertexArrayVertexBuffer(vaobj, first + i, buffers[i], offsets[i], strides[i]);
          }
      }
      
      // 生成并绑定顶点数组对象 (VAO)
      GLuint vao;
      glCreateVertexArrays(1, &vao);
      
      // 生成并绑定顶点缓冲对象 (VBO1)
      GLuint vbo1;
      glCreateBuffers(1, &vbo1);
      
      // 生成并绑定顶点缓冲对象 (VBO2)
      GLuint vbo2;
      glCreateBuffers(1, &vbo2);
      
      // 顶点数据1
      GLfloat vertices1[] = {
          0.0f,  0.5f, 0.0f,  // 顶点1坐标
      -0.5f, -0.5f, 0.0f,  // 顶点2坐标
          0.5f, -0.5f, 0.0f   // 顶点3坐标
      };
      
      // 顶点数据2
      GLfloat vertices2[] = {
          1.0f,  0.0f, 0.0f,  // 顶点4坐标
          0.0f, -1.0f, 0.0f,  // 顶点5坐标
          1.0f, -1.0f, 0.0f   // 顶点6坐标
      };
      
      // 将顶点数据传递到 VBO1 中
      glNamedBufferData(vbo1, sizeof(vertices1), vertices1, GL_STATIC_DRAW);
      
      // 将顶点数据传递到 VBO2 中
      glNamedBufferData(vbo2, sizeof(vertices2), vertices2, GL_STATIC_DRAW);
      
      // 配置顶点属性1
      glVertexArrayAttribFormat(vao, 0, 3, GL_FLOAT, GL_FALSE, 0);
      glEnableVertexArrayAttrib(vao, 0);
      glVertexArrayVertexBuffer(vao, 0, vbo1, 0, 3 * sizeof(GLfloat));
      
      // 配置顶点属性2
      glVertexArrayAttribFormat(vao, 1, 3, GL_FLOAT, GL_FALSE, 0);
      glEnableVertexArrayAttrib(vao, 1);
      glVertexArrayVertexBuffer(vao, 1, vbo2, 0, 3 * sizeof(GLfloat));
      
      // 使用 BindVertexBuffers 一次性绑定多个 VBO
      GLuint buffers[] = {vbo1, vbo2};
      GLintptr offsets[] = {0, 0};
      GLsizei strides[] = {3 * sizeof(GLfloat), 3 * sizeof(GLfloat)};
      
      // 0 和 1 表示两个顶点数组对象的索引
      glBindVertexBuffers(0, 2, buffers, offsets, strides);
      
      // 使用 VertexArrayVertexBuffers 一次性绑定多个 VBO
      // 这里使用 0 和 1 表示两个顶点数组对象的索引
      glVertexArrayVertexBuffers(vao, 0, 2, buffers, offsets, strides);
      
  4. 关联顶点属性与缓冲绑定

    void VertexAttribBinding( uint attribindex, uint bindingindex );
    
    void VertexArrayAttribBinding( uint vaobj, uint attribindex, uint bindingindex );
    
    • 使用VertexAttribBindingVertexArrayAttribBinding命令来指定哪个顶点属性应该从哪个缓冲绑定点读取数据。

      // 生成并绑定顶点数组对象 (VAO)
      GLuint vao;
      glCreateVertexArrays(1, &vao);
      
      // 生成并绑定顶点缓冲对象 (VBO)
      GLuint vbo;
      glCreateBuffers(1, &vbo);
      
      // 顶点数据
      GLfloat vertices[] = {
          0.0f,  0.5f, 0.0f,  // 顶点1坐标
      -0.5f, -0.5f, 0.0f,  // 顶点2坐标
          0.5f, -0.5f, 0.0f   // 顶点3坐标
      };
      
      // 将顶点数据传递到 VBO 中
      glNamedBufferData(vbo, sizeof(vertices), vertices, GL_STATIC_DRAW);
      
      // 绑定 VBO 到指定的绑定点
      glVertexArrayVertexBuffer(vao, 0, vbo, 0, 3 * sizeof(GLfloat));
      
      // 配置顶点属性
      glVertexArrayAttribFormat(vao, 0, 3, GL_FLOAT, GL_FALSE, 0);
      glEnableVertexArrayAttrib(vao, 0);
      
      // 将顶点属性绑定到指定的绑定点
      glVertexArrayAttribBinding(vao, 0, 0);
      
      // 此时,顶点属性数组已经绑定到了顶点缓冲对象的绑定点
      
      // ... 绘制代码 ...
      
      // 在这个例子中,我们首先创建了一个顶点数组对象(VAO)和一个顶点缓冲对象(VBO)。
      // 使用 glNamedBufferData 将顶点数据传递到 VBO 中。
      // 然后,通过 glVertexArrayVertexBuffer 将 VBO 绑定到 VAO 的指定绑定点(这里是 0)。
      // 接下来,配置了顶点属性,包括属性的格式和启用属性。
      // 最后,使用 glVertexArrayAttribBinding 函数将顶点属性绑定到指定的绑定点,这里是将顶点属性数组 0 绑定到绑定点 0。
      
      //这样,顶点属性数组就成功地绑定到了顶点缓冲对象的指定绑定点,可以在绘制时使用这个顶点数组对象了。
      
      
  5. 设置顶点属性指针

    void VertexAttribPointer( uint index, int size, enum type, boolean normalized, sizei stride, const void *pointer );
    
    void VertexAttribIPointer( uint index, int size, enum type, sizei stride, const void *pointer );
    
    void VertexAttribLPointer( uint index, int size, enum type, sizei stride, const void *pointer );
    
    • VertexAttribPointerVertexAttribIPointerVertexAttribLPointer函数实际上同时设置了顶点属性状态、顶点缓冲区绑定及两者间的映射关系。当调用这些函数时,系统会根据给定的大小、类型、是否归一化、步长和指针地址自动设置相关状态,并且绑定相应的缓冲对象。

      • index: 顶点着色器中顶点属性的位置索引。
      • size: 每个顶点属性的分量数量(例如,3 表示三维坐标)。
      • type: 数据类型(例如,GL_FLOAT 表示浮点数)。
      • normalized: 是否需要归一化数据。
      • stride: 相邻两个顶点属性之间的字节偏移量。
      • pointer: 第一个顶点属性的起始内存偏移量。
      // VertexAttribPointer
      // 等价于
      VertexAttrib*Format(index, size, type, {normalized, }, 0);
      VertexAttribBinding(index, index);
      if (stride != 0) {
          effectiveStride = stride;
      } else {
          compute effectiveStride based on size and type;
      }
      VERTEX_ATTRIB_ARRAY_STRIDE[index] = stride;
      // This sets VERTEX_BINDING_STRIDE to effectiveStride
      VERTEX_ATTRIB_ARRAY_POINTER[index] = pointer;
      BindVertexBuffer(index, buffer bound to ARRAY_BUFFER, (char *)pointer - (char *)NULL, effectiveStride);
      
  6. 启用/禁用顶点属性

    void EnableVertexAttribArray( uint index );
    void EnableVertexArrayAttrib( uint vaobj, uint index );
    
    void DisableVertexAttribArray( uint index );
    void DisableVertexArrayAttrib( uint vaobj, uint index );
    
    • 使用EnableVertexAttribArrayDisableVertexAttribArray(或者针对特定VAO的EnableVertexArrayAttribDisableVertexArrayAttrib)来启用或禁用某个通用顶点属性数组参与渲染过程。

总的来说,在OpenGL编程中,开发者需要通过以上API详细地配置顶点数组对象,从而定义出正确格式化的顶点数据流,方便GPU高效地处理并渲染图形。

  • 14
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值