[SOLVED] UniformBufferObject-Data's Offset violating Spec for some reason?

Started by Source_of_Truth, April 26, 2020, 16:11:48

Previous topic - Next topic

Source_of_Truth

Hi people of the LWJGL-Forum  :)

Okay, given this UBO:

layout (std140) uniform BaseRenderData {
	mat4 viewMatrix;
	mat4 projectionMatrix;
	vec3 camPosition;
	float cameraAngleVertical;
	float cameraAngleHorizontal;
};


I would expect to fill it using the following code:

//'buffer' is a 'FloatBuffer', using only floats here
buffer.rewind();

//send over matrices data (matrices are org.joml.Matrix4f-objects):
viewMatrix.get(buffer);
bufferToPutMatricesIn.position( 16 );
projectionMatrix.get(buffer);
bufferToPutMatricesIn.position( 32 );

//send over camera data, all of these members are floats:
buffer.put(camera.position.x);
buffer.put(camera.position.y);
buffer.put(camera.position.z);
buffer.put(0.f); //!!!!!!!
buffer.put(camera.verticalAngle);
buffer.put(camera.horizontalAngle);


Now, I have marked a specific line with !!!!!!!, which is giving me a headache. Since my UBO is of std140 layout, the vec3 I am using here should have the size of a vec4, hence I need to add this "dead" data.
However, keeping this line in the code will break the shader, with the vertical angle's value becoming the horizontal one and and horizontal one not being applied. Aka, it is an offset-problem. Question is **WHY?** Removing the line makes everything behave correctly, which is a violation of OpenGL spec as far as I understand it.

I am not ready to believe that my device's driver has a bug that severe. Anybody got an idea?

For reference, I am using LWJGL 3.2.3.

KaiHH

You are probably misunderstanding std140.
When you have a vec3 and immediately after it a float, then the float will fill up the vec3 to make it a vec4. So, basically, the following float will be the vec3's 'w' component, making it a vec4. What's important here is the alignment of a data type.
The vec3 will have an alignment of a vec4, which is true in your case. However, the following float will simply need to have an alignment of a float, which is just a 4-bytes boundary, which is just after the vec3's z component.
If you had a vec3 and then following a vec4, then the vec4 would need to have an alignment of 16 bytes, which would mean that you would have had a padding of 4 bytes right after the vec3.
In essence: Not every vec3 is padded to a vec4. It rather depends on the alignment requirements of any following member.

So simply put: Your driver behaves completely according to spec.