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);
Fox1942
  • 276
  • 2
  • 18
  • 2
    `vector indices;` is an object containing a pointer to dynamic memory. You've to use [`std::array`](https://de.cppreference.com/w/cpp/container/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?](https://stackoverflow.com/questions/38172696/should-i-ever-use-a-vec3-inside-of-a-uniform-buffer-or-shader-storage-buffer-o) – Rabbid76 May 09 '20 at 14:55
  • ... and read [OpenGL 4.6 API Core Profile Specification; 7.6.2.2 Standard Uniform Block Layout](https://www.khronos.org/registry/OpenGL/specs/gl/glspec46.core.pdf#page=168&zoom=100,0,381) – Rabbid76 May 09 '20 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 – Fox1942 May 09 '20 at 15:59
  • No you are wrong. The content of `vector 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. – Rabbid76 May 09 '20 at 16:00
  • Ok, I see. I will check the basics. – Fox1942 May 09 '20 at 16:37
  • So Vec3 is treated as Vec4 in GLSL and as far as I understand the only difference between std140 and std430 is that the latter one doesn't put padding at the end of the structs or arrays. I suppose the purpose of padding is for making the cpu read the memory less times. Anyway I am also sending some primitive coordinates from cpu side as vec4 and receive these in a SSBO of frag shader as a vec3 array. The object appears in the window, so It seems fine. But when I change vec3 array to vec4 in frag shader's ssbo, the object appears in a wrong way. What can be the problem? – Fox1942 May 09 '20 at 23:22

1 Answers1

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.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • "When you specify the then you have to use" something missing from the sentence. Btw, thank you for your help! – Fox1942 May 09 '20 at 16:05
  • 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. – Fox1942 May 10 '20 at 01:06
  • 1
    @Tom I recommend to use `int` instead of `bool` (on both sides). – Rabbid76 May 10 '20 at 06:03