WebGLRenderer: UBO / Uniform Buffer Object - Vec2 is not binded correctly.
dghez opened this issue · comments
Description
I'm trying to give a go to UBO / UniformBufferObject
but I noticed one weird thing.
I'm setting a vec2 but looks like is keeping only one value (y) and set the other to 0
globalUniforms.resolution = new Uniform(new Vector2(11, 33))
globalUniforms.add(globalUniforms.resolution)
But if you check the screenshot, it's correct as vec2 of floats but as you can notice values are 33 and 0, instead of 11 and 33
After that i tried to bind a Vector3
and so far is binded correctly
globalUniforms.resolution = new Uniform(new Vector3(11, 33, 77))
globalUniforms.add(globalUniforms.resolution)
Reproduction steps
See above, explained in details
Code
// code goes here
Live example
Screenshots
No response
Version
0.166.0
Device
Desktop, Mobile
Browser
Chrome, Firefox
OS
MacOS
I tried to reproduce on chrome under windows on this example https://threejs.org/examples/webgl_ubo.html
But I don't have the issue.
Ok, @AlaricBaraou was able to recreate on a stackblitz (not jsfiddle because i couldn't run spector).
LINK: https://stackblitz.com/edit/vitejs-vite-z3emzj?file=main.js
So, if I set ONLY the resolution is binded correctly
const globalUniforms = new THREE.UniformsGroup();
globalUniforms.setName('Global');
globalUniforms.resolution = new THREE.Uniform(new THREE.Vector2(11, 33));
globalUniforms.add(globalUniforms.resolution);
If i add a float before is not working
const globalUniforms = new THREE.UniformsGroup();
globalUniforms.setName('Global');
globalUniforms.time = new THREE.Uniform(0);
globalUniforms.add(globalUniforms.time);
globalUniforms.resolution = new THREE.Uniform(new THREE.Vector2(11, 33));
globalUniforms.add(globalUniforms.resolution);
IF i switch the order, so resolution THEN time is binded correctly
I'm not that skilled into native API but i guess the issue is coming from the offset. Looking at the time>resolution example, the VEC2 is binded with an offset of 8
where it should be offset 4
(because float is... 4), and doing the offset by 8 essentially is skipping the first value.
That makes sense if you think about the fact that if the vec2 is 11,33
is binded 33,0
so essentially shifted by 1 offset. Hope is understandable ahah
Update: I guess I was 90% wrong in the prev message because after some researches looks like 8
is the correct place because everything is organised by chunks of 4 spots and vec2 can occupy only the first two OR the last two, not in the middle.
So i guess it's correct in our case like [float][null][vec2float1][vec2float2]
but looks like is like in our case [0][11][33][null]
or better [time][resolution.x][resolution.y][null]
but when access the data it takes correctly the last two.
So i guess the issue is how we are packing, the write is wrong, the read is correct.
On top of that, on my initial example of float+vec3
is working because vec3 can occupy ONLY of the first 3 slots of a chunk, not the last, so as you can see is shifted correctly to offset 16.
If i'm correct, @AlaricBaraou in your case is working because you are using 4 vec3 and a float that occupy 4 chunks in total, so the vec2 is in the new chunk, first two slots
lightingUniformsGroup.add( new THREE.Uniform( new THREE.Vector3( 0, 0, 10 ) ) ); // light position
lightingUniformsGroup.add( new THREE.Uniform( new THREE.Color( 0x7c7c7c ) ) ); // ambient color
lightingUniformsGroup.add( new THREE.Uniform( new THREE.Color( 0xd5d5d5 ) ) ); // diffuse color
lightingUniformsGroup.add( new THREE.Uniform( new THREE.Color( 0xe7e7e7 ) ) ); // specular color
lightingUniformsGroup.add( new THREE.Uniform( 64 ) ); // shininess
lightingUniformsGroup.add( new THREE.Uniform( new THREE.Vector2(1,2 ) ); // debug
So in chunks
[light.x][light.y][light.z][null] // OFFSET:0
[ambient.x][ambient.y][ambient.z][null] // OFFSET:16
[diffuse.x][diffuse.y][diffuse.z][null] // OFFSET:32
[specular.x][specular.y][specular.z][shininess] // OFFSET:48
[debug.x][debug.y][null][null] // OFFSET:64
So i guess if you add a float BEFORE the debug-vec2 you'll face the same issue
I think the issue is that the vec2
data start at the wrong location in the buffer. Normally a 8 byte boundary for vec2
is required but that is currently ignored. So instead of:
4 byte (time) | 8 byte (resolution)
the buffer should be:
4 byte (time) | 4 byte (padding) | 8 byte (resolution)