How do I pass an array of Vector3 into glsl through ShaderMaterial?

Hello,

I am trying to pass a dynamic size array of Vector3 into fragment shader. I get that there are methods like setFloats which I could use to add dynamic size array of floats, but I want the shader to automatically update uniform value whenever values in Vector3 changes. I want something like

const v1 = new Vector3(1,2,3);
const v2 = new Vector3(4,5,6);

const material = new ShaderMaterial(...my params...);
material.setInt("uSize", 2);
material.setVector3s("uMyVectors", [v1, v2]);

Then inside fragment shader

uniform int uSize;
uniform vec3 uMyVectors[uSize];

The size of array, uSize, is flexible, that is why I try to avoid calling setVector3 for each vector. This is possible in OpenGL. I’m curious if Babylon has that support?

Any help would be appreciated!

material.setArray3 would be the way to go. You would need to expand your vector array in a float array first.

2 Likes

Thank you for your response!

The problem with using that is that it does not automatically update the value inside the shader. For example, if I do something like:

const material = new ShaderMaterial(...my params...);
const v = new Vector3(1,2,3);
material.setArray3("uMyVectors", v.asArray());

Then the values of initial vector v will be passed onto shader, but when I update the vector

v.x = 5;

Then, the updated value would not be passed into the shader automatically. I could try to call setArray3 every frame, but I think that would be too inefficient?

Weird… Could you create a quick repro in the babylon Playground ?

It seems like it could be a bug as it should work like the other ones.

Sure! In here, the color of sphere is supposed to switch between red and purple every 2 seconds. It works with setColor3 but not with setArray3.

The reason I don’t want to use setColor3 is because it only accepts 1 vec3 in shader, but I could have any number of colors.

I get that when we create array, the value is simply copied, not referenced. So, in case I want to pass flexible number of values of components of vector3 and color3, like

material.setFloats([v1.x, v1.y, v2.y, v2.z]);

How do I do so so that whenever vectors v1 and v2 update, the shader updates automatically without calling setFloats again? Is this possible?

It is because in this case you copy the color in the array. You could work directly with the array instead ? https://playground.babylonjs.com/#BJDST5#3

Thank you for your reply!
So what if I want to use the values directly from vector/color? For example, I want to pass a position of object A. So when I move A, which changes values in its x y z of position, I want the shader to update automatically just like setVector3 or setColor3, except there may be any number of vectors/colors. Is it possible?
Currently in my project I’m working on, I create a custom class that extends ShaderMaterial, then dynamically call setVector3 and setColor3 multiple times with dynamic name assigning, then dynamically edit the shader string in the constructor.

You need to copy the data from the object to the array every frame as the data structure are different. I would advise to do it in the onBindObservable of the material.