New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better Documentation for Structured Uniforms #10759

Open
frederikaalund opened this Issue Feb 8, 2017 · 16 comments

Comments

Projects
None yet
9 participants
@frederikaalund

frederikaalund commented Feb 8, 2017

Description of the problem

By structured uniform, I mean a uniform of the form:

struct parameters {
    float scale, height, width, offset, baseline;
};
uniform parameters transition_model;

Currently, the uniform documentation only states that

Uniform structures and arrays are also supported.

but doesn't go into further detail on how to set such uniforms using three.js. I had to figure out the proper syntax by stepping through the source code. For future reference, the syntax is:

material.uniforms = {
    transition_model: { value: {
        scale: pScale,
        height: pHeight,
        width: pWidth,
        offset: pOffset,
        baseline: pBaseline
    }
}

This old issue thread is the only reference I could find on structured uniforms in three.js. Moreover, said issue doesn't conclude on a single syntax (nor is the correct syntax even mentioned).

It would be nice to have this topic covered in the official documentation. Just like there already is a nice example of regular (non-structured) uniform usage.

Three.js version
  • Dev
  • r84
  • ...
Browser
  • All of them
  • Chrome
  • Firefox
  • Internet Explorer
OS
  • All of them
  • Windows
  • Linux
  • Android
  • IOS
Hardware Requirements (graphics card, VR Device, ...)
@mrdoob

This comment has been minimized.

Owner

mrdoob commented Feb 15, 2017

/cc @looeee

@looeee

This comment has been minimized.

Collaborator

looeee commented Feb 15, 2017

Yeah, improving the docs for ShaderMaterial and RawShaderMaterial is on my list! It'll probably be a couple of weeks before I have time to do it though. In the meantime @frederikaalund if you want to add this yourself that would be great!

@hayatoikoma

This comment has been minimized.

hayatoikoma commented Mar 30, 2017

@looeee
Would you be able to provide a small example of how to pass an array of structured uniforms? It seems that it is still not documented, and I couldn't find its example for the latest version (r84).

@looeee

This comment has been minimized.

Collaborator

looeee commented Mar 31, 2017

@hayatoikoma - read the first comment in this thread by @frederikaalund. He describes how to do it there.

@hayatoikoma

This comment has been minimized.

hayatoikoma commented Mar 31, 2017

Sure. I understood how we can pass a set of uniforms as a struct to a shader from the first comment, but I don't know how I can pass an array of a struct. For example, I would like to pass an array of transition_model to a shader. It would be similar to how multiple light sources are passed to a shader, but I still haven't been able to figure out how I can achieve it.

InUniformsLib.js, such array of structured uniforms are defined like

	directionalLights: { value: [], properties: {
		direction: {},
		color: {},

		shadow: {},
		shadowBias: {},
		shadowRadius: {},
		shadowMapSize: {}
	} },

Would you provide an example of how I can pass actual values to directionalLights.value? Should I provide any values to directionalLights.properties?

@looeee

This comment has been minimized.

Collaborator

looeee commented Mar 31, 2017

Ah I see. I'm afraid I don't know the answer to that, but if you ask over on the forum, discourse.threejs.org, or on stackoverflow someone might help you.

@hayatoikoma

This comment has been minimized.

hayatoikoma commented Apr 3, 2017

I was finally able to find a way by myself. For example,

uniforms.directionalLights = { value: [], properties: {
	direction: {},
	color: {},
} };

var dLight0;
dLight0.direction = new THREE.Vector3( 0, 1, 0 );
dLight0.color = new THREE.Color();
uniforms.directionalLights.value.push( dLight0 );

var dLight1;
dLight1.direction = new THREE.Vector3( 1, 0, 0 );
dLight1.color = new THREE.Color();
uniforms.directionalLights.value.push( dLight1 );

worked to parse an array of structured uniforms to a shader. I can add it to the documentation if it is appropriate.

I am also thinking that it would be great to have this functionality to Uniform.js. If somebody can confirm that my understanding is correct and it is worth doing, I would be happy to extend Uniform.js to support structured uniforms and its array.

@mrdoob

This comment has been minimized.

Owner

mrdoob commented Apr 3, 2017

worked to parse an array of structured uniforms to a shader. I can add it to the documentation if it is appropriate.

That'd be great!

@mrdoob

This comment has been minimized.

Owner

mrdoob commented Apr 3, 2017

I am also thinking that it would be great to have this functionality to Uniform.js. If somebody can confirm that my understanding is correct and it is worth doing, I would be happy to extend Uniform.js to support structured uniforms and its array.

/ping @bhouston

@bhouston

This comment has been minimized.

Contributor

bhouston commented Apr 4, 2017

Yikes. While I wrote the original version of structured uniforms it was refactor by @tschw and I'd have to read through the code to figure it out. Sorry, I am not any more help that you guys reading through it as well.

@hayatoikoma

This comment has been minimized.

hayatoikoma commented Apr 5, 2017

@bhouston I see. Thank you.

Would anyone let me know which file I should read through? Are there any unit tests to check this functionality?

@WestLangley

This comment has been minimized.

Collaborator

WestLangley commented Apr 5, 2017

@hayatoikoma I think it would be sufficient to add an example of passing a struct, and an example of passing an array of structs, to https://threejs.org/docs/?q=unifor#Reference/Core/Uniform.

@tschw

This comment has been minimized.

Contributor

tschw commented Apr 13, 2017

Thanks for the ping, Ben!

Actually it was more than just a refactor, but in fact a completion. It handles any GLSL uniform you can declare, as long as you resemble the same structure in JavaScript.

The docs on structured uniforms (including multidimensional arrays) read:

Uniform structures and arrays are also supported. GLSL arrays of primitive type must either be
specified as an array of the corresponding THREE objects or as a flat array containing the data
of all the objects. In other words; GLSL primitives in arrays must not be represented by arrays.
This rule does not apply transitively.

An array of vec2 arrays, each with a length of five vectors, must be an array of arrays, of
either five Vector2 objects or ten numbers.

And some types are marked with (*) which means:

(*) Same for an (innermost) array (dimension) of the same GLSL type, containing the components
of all vectors or matrices in the array.

This is rather detailed.

Put bluntly, you either have to go "completely high level" or "flat" for the innermost array (where a one-dimensional array is always "innermost" - the "flat" way is a direct pass-through to WebGL / OpenGL ES2, see specs for details).

The rest is just like you'd expect: Structure members are mapped to object properties (which is pretty much the JS equivalent) and arrays to arrays. Wouldn't hurt to state that explicitly, I guess, but since there are no restrictions except those imposed by GLSL, there's really not much more to say about it.

@tschw

This comment has been minimized.

Contributor

tschw commented Apr 13, 2017

For the .properties vs. .value story, I honestly have no clue. I never had anything to do with .properties.

I remember .value being kind-of historical leftover, because we didn't want to break existing code, and also because there's the optional .needsUpdate...

@hayatoikoma

This comment has been minimized.

hayatoikoma commented Apr 14, 2017

@tschw
Thank you for the detailed explanation. It actually worked without .properties. I was expecting that .properties was used for checking if all elements in a JS array have the same properties.

It seems that .properties was introduced in 7985c8b?diff=split by @bhouston and became unnecessary at 494e016?diff=split by @tschw .

I understood that the description describes every types supported in Three.js, but I guess it would be more informative to write some examples as I couldn't figure it out easily. As a matter of fact, the only example I found for an array of structured uniforms in UniformsLib.js seems the old way.

So, is it safe to provide example like the following code?

uniforms.directionalLights = { value: [] };

var dLight0;
dLight0.direction = new THREE.Vector3( 0, 1, 0 );
dLight0.color = new THREE.Color();
uniforms.directionalLights.value.push( dLight0 );

var dLight1;
dLight1.direction = new THREE.Vector3( 1, 0, 0 );
dLight1.color = new THREE.Color();
uniforms.directionalLights.value.push( dLight1 );

What would happen if some of the elements does not have the same properties? As I still have questions on the behaviors and don't understand the implementation details, I may not be qualified to write more examples...

@tschw

This comment has been minimized.

Contributor

tschw commented Apr 14, 2017

So, is it safe to provide example like the following code?

Yes, that's basically how it works.

What would happen if some of the elements does not have the same properties?

I don't remember - it's not a good idea on the JS end (heterogeneous arrays poison JIT compilation) and diversity of that kind lets suspect a chaotic programming style, so I wouldn't promote it in the docs and, due to the performance critical nature of uniform upload with WebGL (version 1), it's probably best left undefined behavior.

Actually, I never indented this interface to be the final thing, since uniforms do not belong onto a scene graph. Similarly, materials are not the same as shaders. Instead the data that goes into a uniform is either the property of an object or its associated material, or something managed by the renderer (e.g. camera or lights that can reach the object). A custom shader would declare those bindings, but not the associated data. Multiple materials can share the same shader, while the renderer would manage its multiple instances that need to be compiled for everything to just work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment