Setting the values of a struct array

Hello everyone, I am writing a shader and I need to somehow transfer the parameters to it.
In the code I found some structure, but I do not understand how it works.

struct Light {
    vec4 position;
    vec4 ambient;
    vec4 diffuse;
    vec4 specular;
    vec3 spotDirection;
    float spotCutOff;
    float constantAttenuation;
    float linearAttenuation;
    float quadraticAttenuation;
    float spotExponent;
    float spotLightCosCutOff;
};
uniform Light lights[numLights];

How do I set the parameters in the shader?

Something like this should work for passing a struct to a ShaderMaterial or RawShaderMaterial:

const uniforms = {
    Light: { value: {
        position: new THREE.Vector4(),
        ambient:  new THREE.Vector4(),
        diffuse: new THREE.Vector4(),
        specular: new THREE.Vector4(),
        spotDirection:  new THREE.Vector(),
        spotCutOff: 1.0,
        ....
    }
}

const mat = new THREE.ShaderMaterial( { 
    uniforms: uniforms,
    vertexShader: `...`,
    fragmentShader: `...`,
    ...
} );

How do I understand this for one light source? But if we say there will be 10?)

Build upon @looeee example by passing an object array to the uniform value, i.e.:

var lightdef={
              position: new THREE.Vector4(),
              ambient:  new THREE.Vector4(),
             ...
             spotCutOff: 1.0};


const uniforms = {
    Lights: { value: 
                  [lightdef,
                  ...
                  lightdef]
             }
};

Per webGL 1.0 specifications, arrays allow dynamic indexing with constant expression and can’t be a variable. The only exception is for uniform access in vertex shaders, which can be indexed using any expression. The same applies when you want to access the object from the array. The implementation of this specification may depends on the platform compiler though, so for setup/test purpose I would try without a variable…

In other words:

ok: uniform Lights lights[10]; may not be ok: uniform Lights lights[count];

ok: lights[1]
may not be ok: lights[i]
1 Like

This should be fine - at least it’s the way it seems to be done here:
https://github.com/mrdoob/three.js/blob/dev/src/renderers/shaders/ShaderChunk/lights_pars.glsl#L92

@korner look at this file to see how multiple light uniforms are defined in three.js. Perhaps it can be adapted for your use case.

1 Like

Thanks guys :relaxed:
Everything works as it should.