#[GLIUM] - passing struct as uniform to shaders

9 messages · Page 1 of 1 (latest)

cold galleon
#

hi everyone, how can I pass a struct as a uniform to a shader in glium?
this is the struct in my rust program and then in my shader:

#[derive(Debug, Copy, Clone)]
pub struct Material {
     pub ambient: [f32; 3],
     pub diffuse: [f32; 3],
     pub specular: [f32; 3],
     pub shininess: f32,
}
struct Material {
     vec3 ambient;
     vec3 diffuse;
     vec3 specular;
     float shininess;
};

I use a UniformBuffer like this:

let material_buffer = glium::uniforms::UniformBuffer::new(&display, object.renderable.material).unwrap();

let uniforms = uniform! {
  ...
  material: &material_buffer,
}

and it doesn't throw errors nor does it crash, but the material values in the shader are all zeros and make the shapes balck.
I think i have to implement AsUniformValue for Material but I don't know what to put in the as_uniform_value function....

tacit osprey
#

I don't know how glium handles this, but in OpenGL your structs used in uniform buffers have to meet so-called "std140" layout

#

first of all to have any control over the layout at all, you must declare your struct #[repr(C)]

#

then, vec3s are weird in std140: they have a size of 12 bytes but an alignment of 16 bytes, which means that there is padding between consecutive vec3s

#

Rust doesn't understand this so you have to do it yourself (or find a library that does)

#

Adjust your struct like this:

#[derive(Debug, Copy, Clone)]
#[repr(C)]                       // <----
pub struct Material {
     pub ambient: [f32; 4],      // <----
     pub diffuse: [f32; 4],      // <----
     pub specular: [f32; 3],
     pub shininess: f32,
}

The extra components in ambient and diffuse get the alignment of the following vectors right. You can set them to zero or whatever.

#

However, it may be that glium has a better solution to this problem; I haven't used it so I don't know.

cold galleon
#

thank you so much, I'll try to work with this std140

cold galleon
# tacit osprey Adjust your struct like this: ```rust #[derive(Debug, Copy, Clone)] #[repr(C)] ...

It's not working 😅 ...
I tried with the padding (both on all three vecs, and on just the first two, just in case) putting layout(std140) on the shader struct and #[repr(C)] on the rust struct. I tried UniformBlock, AsUniformValue (I can't figure out how I should implement it), UniformBuffer, I even tried the c++ way (in c++ you would set the uniform with its name in a c-string like glUniform3f("material.ambient", ...)), but the rust macro uniform! doesn't have a rule for the dot in this case so it won't let me do it, I tried passing the value to uniforms called just like the fields of the struct (without material. or anything) and it surprisingly didn't complain saying like "no uniform called ...", but still it didn't do anything. Out of frustration I even tried to pass an array to see if the documentation for UniformBuffer was telling the truth, but nothing, not even arrays are passed correctly... I don't know what else to do, because clearly I'm doing something wrong lol