RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 921705
Accepted
Alex Nem
Alex Nem
Asked:2020-12-17 00:01:03 +0000 UTC2020-12-17 00:01:03 +0000 UTC 2020-12-17 00:01:03 +0000 UTC

着色器中未成形块的 std140 对齐(OpenGL、GLSL)

  • 772

看起来我不太明白在将统一缓冲区传递给着色器时如何正确对齐。

据我了解,如果使用统一缓冲区而不是常规 unform 变量将数据传输到着色器,那么写入这些缓冲区的数据必须对齐。可以进行这种对齐的格式之一是 std140。

std140 标记规则是这样的:

标量值(int、float、bool - 占用 4 个字节)。向量要么是 8 字节(vec1,vec2)要么是 16 字节(vec3,vec4)。矩阵就像多个向量(取决于维度)。结构的大小等于其所有成员的大小(考虑到上述规则),如有必要,填充到 16 的重数。

在着色器中,我声明了以下结构:

// Структура описывающая параметры мапинга текстуры
struct TextureMapping
{
    vec2 offset;
    vec2 origin;
    vec2 scale;
    mat4 rotation;
};

原来结构本身应该占用 8 + 8 + 8 + 64 字节(88 字节)最多为 16 的倍数(最接近的值是 16 的倍数是 96),少了 8 个字节。但稍后会详细介绍。

接下来,我声明一个使用这些结构的统一块:

// UBO-блок с параметрами маппинга текстур
layout(std140) uniform textureMapping
{
    TextureMapping diffuseTexMapping;
    TextureMapping specularTexMapping;
    TextureMapping bumpTexMapping;
};

然后,已经在 C++ 代码中,我创建了这个结构的类似物,以便将数据传递给着色器。这一切看起来像这样:

结构本身

struct TextureBasicMapping
{
    glm::vec2 offset;    // Сдвиг текстуры
    glm::vec2 origin;    // Центральная точка
    glm::vec2 scale;     // Масштабирование
    glm::mat4 rotation;  // Поворот (используется только часть 2*2)
};

然后,我自己创建统一缓冲区,因为它有 3 个这样的结构:

// Создать UBO-буфер для параметров маппинга текстуры и выделить память
glGenBuffers(1, &uboTextureMapping_);
glBindBuffer(GL_UNIFORM_BUFFER, uboTextureMapping_);
glBufferData(GL_UNIFORM_BUFFER, 3 * sizeof(TextureBasicMapping), nullptr, GL_STATIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);

但不要忘记,最多 16 个重数,该结构TextureBasicMapping缺少 8 个字节。事实证明,为了正确地将数据传输到着色器,您需要在结构本身的某处添加这个 8 字节填充。所以,我不太明白在哪里。

经过无数次测试,结果证明,为了正确传输数据,这个非常 8 字节的填充必须在glm::mat4 rotation. 结果,结构开始看起来像这样:

struct TextureBasicMapping
{
    glm::vec2 offset;    // Сдвиг текстуры
    glm::vec2 origin;    // Центральная точка
    glm::vec4 scale;     // Масштабирование (vec2 + 8 байт выравнивания)
    glm::mat4 rotation;  // Поворот (используется только часть 2*2)
};

但为什么会在那里?为什么不是最后?为什么不是一开始?它是如何工作的?我将不胜感激详细的解释。

c++
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    user7860670
    2020-01-28T06:06:49Z2020-01-28T06:06:49Z

    事实是,计算管道旨在针对具有 2 个或 4 个机器单元的向量块(即 8 个字节的 vec2 和 16 个字节的 vec4)的操作进行锐化。为了有效地按块组织操作,它们必须沿着以下基向量的边界对齐:

    • 1 MU 块总是在 2 MU 块的开头或中间开始。
    • 2 个 MU 的块总是在 4 个 MU 的块的开头或中间开始。
    • 3 个或更多机器单元的块总是从 4 个机器单元块的开头开始。

    请注意,大小不是在任何地方直接指定的,只是可以将未使用的空间添加到块中,以便遵循块的对齐方式:

    struct s1
    {
        vec2 offset; // 0 +2 
        vec2 origin; // 2 +2
    };               // 4
    
    struct s2
    {
        vec3 offset; // 0 +3
        float dd;    // 3 +1
        vec4 origin; // 4 +4
    };               // 8
    
    struct s3
    {
        vec3 offset; // 0 +3
                     // 3 +1 иначе следующий блок будет не выровнен
        vec2 origin; // 4 +2
                     // 6 +2 иначе следующая структура будет не выровнена
    };               // 8
    
    struct s4
    {
        float offset; // 0 +1
                      // 1 +3 иначе следующая структура будет не выровнена
    };                // 4
    
    struct s5
    {
        float offset; // 0 +1
                      // 1 +1 иначе следующий блок будет не выровнен
        vec2 origin;  // 2 +2
    };                // 4
    
    struct s6
    {
        float offset; // 0 +1
                      // 1 +3 иначе следующий блок будет не выровнен
        vec4 origin;  // 4 +4
    };                // 8
    
    struct TextureBasicMapping
    {
        glm::vec2 offset;   // 0 +2
        glm::vec2 origin;   // 2 +2
        glm::vec2 scale;    // 4 +2
                            // 6 +2 иначе следующий блок будет не выровнен
        glm::mat4 rotation; // 8 +16
    };                      // 24
    
    • 1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    是否可以在 C++ 中继承类 <---> 结构?

    • 2 个回答
  • Marko Smith

    这种神经网络架构适合文本分类吗?

    • 1 个回答
  • Marko Smith

    为什么分配的工作方式不同?

    • 3 个回答
  • Marko Smith

    控制台中的光标坐标

    • 1 个回答
  • Marko Smith

    如何在 C++ 中删除类的实例?

    • 4 个回答
  • Marko Smith

    点是否属于线段的问题

    • 2 个回答
  • Marko Smith

    json结构错误

    • 1 个回答
  • Marko Smith

    ServiceWorker 中的“获取”事件

    • 1 个回答
  • Marko Smith

    c ++控制台应用程序exe文件[重复]

    • 1 个回答
  • Marko Smith

    按多列从sql表中选择

    • 1 个回答
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Suvitruf - Andrei Apanasik 什么是空? 2020-08-21 01:48:09 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5