[SOLVED][LWJGL] [GLSL] Structures and UBO

I am improving my Lightning system and make it more structured.
In my fragment shader I’ve got the following structure:


const int MAX_NUM_LIGHTS = 20;

layout(std140)struct Light { // Simple point lights for testing
	vec3 color;
	float intensity;
	vec3 position;
};

layout(std140)uniform Lights {
	Light lights[MAX_NUM_LIGHTS];
};

When I fill my UBO with the following floats: (index: value)


0: 1.0 //Light 1 color.r
1: 1.0 //Light 1 color.g
2: 1.0 //Light 1 color.b
3: 100.0 //Light 1 intensity
4: 64.0 //Light 1 position.x
5: 10.0 //Light 1 position.y
6: 64.0 //Light 1 position.z
7: 0.0 //Light 2 color.r
8: 0.0 //Light 2 color.g
9: 0.0 //Light 2 color.b
10: 100.0 //Light 2 intensity
11: 32.0 //Light 2 position.x
12: 10.0 //Light 2 position.y
13: 32.0 //Light 2 position.z
14: 0.0
....

Everything works fine for the first light, but the second light has a blue color, while it should have a black color.

Am I missing something important when I fill my UBO?

What happens when you Change Light1 and 2? Can you show us more from your shader?

Your layout is in std140. Learn more about it. The idea is that it makes everything into blocks of 4 floats. It makes sure everything fills up those 4 floats (without overflow). Matrices count as many different vectors.

Ex.
block 1-
vec3 takes up 3 spaces of the first block
the float of intensity fills up the first block

block 2-
vec3 takes up 3 spaces of the block
(the next vec3 does not fit in this block so you have to add it in the next block)

I don’t really have time atm to explain this well. Read more about std140 layout. This is how your data should be inputed


block 1-
0: 1.0 //Light 1 color.r
1: 1.0 //Light 1 color.g
2: 1.0 //Light 1 color.b
3: 100.0 //Light 1 intensity

block 2-
4: 64.0 //Light 1 position.x
5: 10.0 //Light 1 position.y
6: 64.0 //Light 1 position.z
7: X //empty spot anything can go here.

block 3-
8: 0.0 //Light 2 color.r
9: 0.0 //Light 2 color.g
10: 0.0 //Light 2 color.b
11: 100.0 //Light 2 intensity

block 4-
12: 32.0 //Light 2 position.x
13: 10.0 //Light 2 position.y
14: 32.0 //Light 2 position.z
14: X //empty spot
....

Thank you, I will look some more in the layouts. Problem solved! :wink:

it’s not just the layout.

the final memory layout is up to the compiler and may be different on different gpu’s. to be very sure that you setup and fill the buffer correctly you need to use alot introspection :

http://www.opengl.org/wiki/Program_Introspection#Uniforms_and_blocks

for instance, compiler may remove a block-uniform if it is not used.

it is the layout.

http://www.opengl.org/wiki/Interface_Block_(GLSL)#Memory_layout

yes. “shared” layout is even more friendly in terms of constructing the buffer for it.

but still, it may change. just saying, if you want to be very sure you need to use the introspection and rely on that instead of what the documentation says. ran into that issue by myself :slight_smile: works fine on one gpu and different on another.

You are correct that it is usually safer to do these things manually due to problems with drivers, but technically std140 should be uniform across all GPUs.

Just another question: when I would add a 2nd array to the uniform block, will that change anything to the spacing:


const int MAX_NUM_LIGHTS = 8;
layout(std140)struct DirectionalLight {
	vec3 color;
	float intensity;
	//DirectionalLight specific properties
	vec3 direction;
};
layout(std140)struct PointLight {
	vec3 color;
	float intensity;
	//PointLight specific properties
	vec3 position;
};

layout(std140)uniform Lights {
	PointLight pointLights[MAX_NUM_LIGHTS];
	DirectionalLight directionalLights[MAX_NUM_LIGHTS];
};

Because when I fill it with the following way, it works for the pointLights, but not for directionalLights:


		int pln = 0, dln = 0;
		float[] val = new float[MAX_NUM_LIGHTS * 8 + MAX_NUM_LIGHTS * 8]; //PointLight size + DirectionalLight size
		for (Light l : lights) {
			if (l instanceof PointLight) {
				PointLight pl = (PointLight) l;
				int n = pln;
				val[n] = pl.getColor().x; // For simplicity the color is a Vector3f
				val[n + 1] = pl.getColor().y;
				val[n + 2] = pl.getColor().z;
				val[n + 3] = pl.getIntensity();
				val[n + 4] = pl.getPosition().x;
				val[n + 5] = pl.getPosition().y;
				val[n + 6] = pl.getPosition().z;
				pln += 8;
			} else if (l instanceof DirectionalLight) {
				DirectionalLight dl = (DirectionalLight) l;
				int n = MAX_NUM_LIGHTS * 8 + dln;
				val[n] = dl.getColor().x;
				val[n + 1] = dl.getColor().y;
				val[n + 2] = dl.getColor().z;
				val[n + 3] = dl.getIntensity();
				val[n + 4] = dl.getDirection().x;
				val[n + 5] = dl.getDirection().y;
				val[n + 6] = dl.getDirection().z;
				dln += 8;
			}
		}
		ubo.setBufferData(val);

I’ve been googling, but couldn’t find the answer

just cannot stress it enough :wink:

if you use the introspection-api you get all indices, offsets, strides, array-lengths, types and whatnots to fill the buffer properly, for every possible layout and compiler behaviour. :point:

Thank you for that information, now I got the following problem.
Where is the function in LWJGL to query all that information, because they SHOULD be in GL31, but they aren´t…
[icode]glGetActiveUniformBlocki(int program, int uniformBlockIndex, int pname)[/icode] is in the javadoc, but I have the latest LWJGL version, but it is still not in the classes available.

EDIT: restarted eclipse and it is there. :wink:

Then you probably have multiple LWJGL versions in your classpath…

This method exists:

org.lwjgl.opengl.GL31.glGetActiveUniformBlocki(program, uniformBlockIndex, pname)

You go girl!