Почему при отправке структуры в буфер хранилища шейдеров я получаю ненужные данные? - PullRequest
1 голос
/ 09 мая 2020

Я работаю над приложением трассировки лучей на основе opengl на C ++. Я хотел бы отправить данные со стороны процессора во фрагментный шейдер. Данные представляют собой дерево иерархий ограничивающего тома (BVH). К сожалению, на стороне шейдера я получил ненужные данные, когда я пытался записать координаты как цвет с помощью gl_fragcolor. Не знаю почему. Приветствуется любая помощь.

У меня есть эта структура на стороне процессора:

struct FlatBvhNode {

        glm::vec4 min;   
        glm::vec4 max;
        int order;
        bool isLeaf;
        bool createdEmpty;
        vector<glm::vec4> indices;

        FlatBvhNode() { }

        FlatBvhNode(glm::vec3 min, glm::vec3 max, int ind, bool isLeaf, bool createdEmpty, vector<glm::vec3> indices) {
            this->min=glm::vec4(min.x, min.y, min.z, 1.0f);
            this->max=glm::vec4(max.x, max.y, max.z, 1.0f);
            this->order=ind;
            this->isLeaf=isLeaf;
            this->createdEmpty=createdEmpty;

            indices.reserve(2);
            for (int i = 0; i < indices.size(); i++) {
                this->indices.push_back(glm::vec4(indices.at(i).x, indices.at(i).y, indices.at(i).z, 1));
            }
        }
    };

Я хотел бы получить указанную выше структуру в шейдере фрагмента как:

struct FlatBvhNode{     //base aligment     aligned offset
    vec3 min;           // 16 byte          0
    vec3 max;           // 16 byte          16
    int order;          // 4 byte           20
    bool isLeaf;        // 4 byte           24
    bool createdEmpty;  // 4 byte           28
    vec3 indices[2];    // 32 byte          32
};

Я не уверен, что выровненные смещения правильные. Я читал, что vec3 обрабатываются как 16 байтов, логические и целые числа - как 4 байта. Во-вторых, выровненное смещение должно быть равным или кратным базовому aligment.

Я отправляю приведенную выше структуру с этим кодом:

    vector<BvhNode::FlatBvhNode>* nodeArrays=bvhNode.putNodeIntoArray();
    unsigned int nodesArraytoSendtoShader;
    glGenBuffers(1, &nodesArraytoSendtoShader);
    glBindBuffer(GL_SHADER_STORAGE_BUFFER, nodesArraytoSendtoShader);

    glBufferData(GL_SHADER_STORAGE_BUFFER, nodeArrays->size() * sizeof(BvhNode::FlatBvhNode),  nodeArrays, GL_STATIC_DRAW);
    glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 2, nodesArraytoSendtoShader, 0, nodeArrays->size() * sizeof(BvhNode::FlatBvhNode));
    glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);

1 Ответ

1 голос
/ 09 мая 2020

Когда вы указываете буферный объект хранилища шейдеров , тогда вы должны использовать квалификатор std430.
См. Спецификация профиля ядра API OpenGL 4.6; 7.6.2.2 Стандартная единообразная компоновка блока .

Если вы хотите использовать в шейдере следующую структуру данных:

struct FlatBvhNode
{     
                        // base aligment    aligned offset
    vec4 min;           // 16 byte          0
    vec4 max;           // 16 byte          16
    int  order;         // 4 byte           32
    int  isLeaf;        // 4 byte           36
    int  createdEmpty;  // 4 byte           40
    vec4 indices[2];    // 32 byte          48
};

layout(std430) buffer TNodes
{
    FlatBvhNode nodes[];
}

, тогда вы должны учитывать, что indices - это массив типа vec4. Следовательно, indices выравнивается по 16 байтам.

Это соответствует следующей структуре данных в c ++

struct FlatBvhNode {

        glm::vec4 min;   
        glm::vec4 max;
        int order;
        int isLeaf;
        int createdEmpty;
        int dummy; // alignment
        std::array<glm::vec4, 2> indices;
}

Обратите внимание, а std::vector инкапсулирует динамические массивы c размера, std::array инкапсулирует массивы фиксированного размера. std::array<glm::vec4, 2> соответствует glm::vec4[2], но std::vector<glm::vec4> больше похоже на glm::vec4* и некоторую дополнительную информацию о размере.

...