glslpyside6qt3d

How do I create Uniform Object Buffers in Qt3d with PySide 6?


I'm writing a 3d game level editor with PySide6, using Qt3d (not QML). I stumbled upon a problem - I don't know how to create a Uniform Buffer Objects with Qt3d. Basically I want to pass a list of lights to the shader programs.

Here are definitions of my UBOs:

struct SunInfo {
    vec3    direction;
    vec3    color;
    float   intensity;
}

struct LightInfo {
    vec3    position;
    vec3    rotation;
    vec3    color;
    float   cone_inner;
    float   cone_outer;
    float   radius;
}

uniform SunInfo sun;
uniform LightInfo lights[MAX_NUM_LIGHTS];

I tried searching through the examples on the internet... There's only explanation on how to create single value uniforms (QParameter). I tried it on the above single block SunLight - I created a QBuffer and assigned it to a QParameter with a "sun" name, but that didn't work. No errors - just no result. The shader works, if I pass the sun parameters as single values, but that won't be possible for an array of other lights.


Solution

  • I figured out what my problem was - in my Python code I created a QParameter with instance name - "sun". It should be the UBO block name - "SunInfo".

    Another problem I encountered was with packing of the buffer itself. I had to read up on all the layout qualifiers, but figured out that my SunInfo block (vec3, vec3, float) had to be packed to 32 bytes, with a format "3f 4x 3f f". Basically first vec3 is followed by 4 bytes of padding, whereas the latter vec3 was packed together with a float into 16 bytes.

    I don't know if there is a way to query offsets of block members in Qt3d, like you can using OpenGL API itself. Therefore I switched my block definition inside shader to:

    layout (std140, binding=auto) uniform SunInfo {
        vec3    direction;
        vec3    color;
        float   intensity;
    }sunInfo;
    

    which standarizes the layout. In case the layout gets different on different GPU cards.