mrdoob / three.js

JavaScript 3D Library.

Home Page:https://threejs.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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
image

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)
image

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.
CaptureCode
DebugVec2

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);
image

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);
image

IF i switch the order, so resolution THEN time is binded correctly
image


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)

@Mugen87 yeah, you summarized it in 2 lines rather than my explanations that took a lot 😂😂