1

I am working on an opengl based raytracer application in c++. I would like to send data from the cpu side to the fragment shader. The data is a bounding volume hierarchies (BVH) tree. Unfortunately on the shader side I got junk data, when I am trying to write out the coordinates as color with gl_fragcolor. I don't know why. Any help is appreciated.

I have this structure on CPU side:

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));
            }
        }
    };

I would like to receive the above structure in the fragment shader as:

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
};

I am not sure that the aligned offsets are right. I have read that vec3s are treated as 16 bytes , booleans and integers as 4 bytes. Secondly the aligned offset has to be equal or multiple of the base aligment.

I am sending the above structure with these code:

    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);
6
  • 2
    vector<glm::vec4> indices; is an object containing a pointer to dynamic memory. You've to use std::array. In c++ code the data types are std::vec4. In the shader the types are vec3. Please read Should I ever use a vec3 inside of a uniform buffer or shader storage buffer object? Commented May 9, 2020 at 14:55
  • ... and read OpenGL 4.6 API Core Profile Specification; 7.6.2.2 Standard Uniform Block Layout Commented May 9, 2020 at 14:57
  • I believe you, that std::array is more relevant but, I was using std::vector in an other case and everything seemed fine, except one thing: on the cpu side I have to use vec4 and on the gpu side vec3s Commented May 9, 2020 at 15:59
  • No you are wrong. The content of vector<glm::vec4> indices; is not what you expect it to be. Use a debugger an investigate the memory. You can use std::vector for the buffer, but not for an element in a structure, when the structure is an element of the buffer. Please lern the basics. Commented May 9, 2020 at 16:00
  • Ok, I see. I will check the basics. Commented May 9, 2020 at 16:37

1 Answer 1

1

When you specify the Shader Storage Buffer Object, then you have to use the std430 qualifier.
See OpenGL 4.6 API Core Profile Specification; 7.6.2.2 Standard Uniform Block Layout.

If you want to use the following data structure in the shader:

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[];
}

then you have to consider, that indices is an array of type vec4. Hence indices is aligned to 16 bytes.

This corresponds to the following data structure in c ++

struct FlatBvhNode {

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

Note, while std::vector encapsulates dynamic size arrays, std::array encapsulates fixed size arrays. std::array<glm::vec4, 2> corresponds to glm::vec4[2], but std::vector<glm::vec4> is more like glm::vec4* and some additional size information.

Sign up to request clarification or add additional context in comments.

3 Comments

"When you specify the then you have to use" something missing from the sentence. Btw, thank you for your help!
I tried your solution. Everything is fine except the booleans. When I write FragColor = vec4(nodes[0].isLeaf, 1, 1, 1); to get cyan or white color, it is always giving me white no matter isLeaf is true or false. But the other variables are fine.
@Tom I recommend to use int instead of bool (on both sides).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.