Issue 1:
I was looking at the ThreeJS materials. There are four materials that are nearly the same thing. Basic, Lambert, Phong and NormalMap.

NormalMap seems to have all the features of Lambert and Phong and even has the ability to turn off things like Specular (to create a Lambert material.)

I think that Basic is a material where color is set into emissive and it isn't affected by lights.

Thus maybe four different materials could be combined into one.

I am wondering if it is worth keeping all of these materials around on the shader side of things.

I think that with proper use of DEFINES (as it is already done) we can have for the most part a single vertex / fragment shader pair for all standard materials. The variations can be completely controlled via the DEFINES rather than constructing new shaders via including snippets. I think that with proper use of DEFINES in the more complex shader you can still get the speed you would get from a simple Lambert shaders.

One full shader is a lot easier to maintain than three (or four) very similar shaders. (I also struggle trying to follow the code because of the way the snippets are combined -- I wonder if there is an alternative design possible here that is easier to grok.)

Even if we combined things, we could still keep the existing material classes around for creating specialized materials for those that do not want to deal with all the options explicitly. Or one can create a factory class for creating common sub-types of StandardMaterials. But underneath these would all refer to the same shader, they would just provide simplified parameters to users.

BTW I am open to other design suggestions regarding the shaders. I do not have that much experience with dynamic shader generation designs.

(I push this in part because the more we use a single shader for everything the more can group together objects into batches... Now there are some additional complications, specifically one needs to be able to control the variations without defines to do full batches, but that can come later as an option I think.)

Issue 2:
Note: I don't want to bury the lede for this request, so I moved a brief summary to the top of the issue. Please refer to the second and third headings for a more detailed background and rationale!

Proposal

When loading models with GLTFLoader, it would be nice if we could retain associations between glTF scene graph elements and the Three.js objects that correspond to them. I briefly discussed this problem with @donmccurdy and he suggested that one of the following approaches might be acceptable:

Decorate Three.js objects via userData e.g., material.userData.gltfMeta.index = 3

Expose a lookup table somewhere e.g., parser.getDefinition( material: THREE.Material ): GLTF.Material

What do others think about this problem? Would you be willing to consider a change that makes either of the suggested enhancements?

Background

Three.js' GLTFLoader currently produces an artifact that contains a Three.js scene graph as well as a GLTFParser instance that holds the original, deserialized glTF.

The GLTFParser holds associations between the elements in the original glTF and the Three.js scene graph. These associations are expressed both by GLTFParser.prototype.getDependencies and the cache object on the GLTFParser instance.

In some cases, the relationship between the original glTF element and the associated Three.js objects is obscured and cannot be trivially re-established. For example, materials associated with a skinned mesh are cloned, and the resulting clones are cached against a key that cannot be reconstructed easily:

three.js/examples/jsm/loaders/GLTFLoader.js

Lines 2118 to 2127
in
648c4bb

cachedMaterial = material.clone();

if ( useSkinning ) cachedMaterial.skinning = true;

if ( useVertexTangents ) cachedMaterial.vertexTangents = true;

if ( useVertexColors ) cachedMaterial.vertexColors = true;

if ( useFlatShading ) cachedMaterial.flatShading = true;

if ( useMorphTargets ) cachedMaterial.morphTargets = true;

if ( useMorphNormals ) cachedMaterial.morphNormals = true;

this.cache.add( cacheKey, cachedMaterial );

Description of the problem

Consider a model editor that allows a user to:

Load a glTF with any shape

Interactively change the value of any field of any element of the glTF

See the result of the change rendered in real time

Export a new glTF

In an ideal world, the editor should faithfully re-export the model with its original hierarchy and shape. The only meaningful change in the exported file should be the one made interactively by the user.

In the pursuit of this goal, it is very useful (and probably required) that an association between the source glTF scene graph and the Three.js scene graph be made, so that for any change we make to a glTF element, we can reflect that change in the rendered Three.js scene in real-time without completely re-loading the glTF.

Some of the information required to correctly correlate the glTF scene graph with the Three.js scene graph is lost or obscured, and this makes the above described editor scenario very difficult (perhaps impossible) to achieve.

Three.js version

Dev

r115

...

Browser

All of them

Chrome

Firefox

Internet Explorer

OS

All of them

Windows

macOS

Linux

Android

iOS

Hardware Requirements (graphics card, VR Device, ...)