shawn0326 / zen-3d

JavaScript 3D library.
MIT License
196 stars 24 forks source link

ShaderMaterial clone problem #15

Closed SoundAndColour closed 3 years ago

SoundAndColour commented 3 years ago

Hi Shawn, I really like your engine for it's performance and features and would like to use it in a professional project. But I'm stuck for several days now with a ShaderMaterial issue, Here's what I've achieved so far:

1) Created a working custom ShaderMaterial ( with lots of copypaste from your code :)

2) Altered the GLTFLoader to accept an array of custom materials instead of creating default ones - works fine with built-in materials.

var material;

if ( scope.options.manager.customMaterials )
{
    if ( scope.options.manager.customMaterials.length > primitive.material )
    {
        material = scope.options.manager.customMaterials[ primitive.material ];
    }
}
else
{
    material = dependencies.materials[primitive.material];
}

3) But with my custom ShaderMaterial I'm getting the following error:

GLTFLoader.js:95 TypeError: Cannot read property 'vertexShader' of undefined

at this line in zen3d.ShaderMaterial:

this.vertexShader = shader.vertexShader || "";

At the moment I'm using a gltf without any embedded textures, just the mat ids, and throw in a newly created material. Which works fine with built-in materials, but not for my ShaderMaterial. I don't have a clue what is happening...

Thanks for your help in advance & best regards!

shawn0326 commented 3 years ago

The constructor of zen3d.ShaderMaterial needs to pass in a shader parameter, which is required, otherwise an error will occur.

new zen3d.ShaderMaterial({
  uniforms: {},
  vertexShader: '...',
  fragmentShader: '...'
})

In your case, I suggest that you can inherit ShaderMaterial to implement a material class that does not need to pass in parameters, so that you can replace the material in the loader according to your logic.

class CustomMaterial extends zen3d.ShaderMaterial {
  constructor() {
    let shader = {
      uniforms: {},
      vertexShader: '...',
      fragmentShader: '...'
    };
    super(shader);
  }

  // ...
}

However, some work needs to be done when assigning material attributes later, for example, some textures or attributes cannot be assigned to your custom material in a correct way.

Another solution is that you can traverse and replace the material after the GLTFLoader is loaded, so that there is no need to change the GTLFLoader, which may be easier for you to implement.

SoundAndColour commented 3 years ago

Hi, thanks for your quick reply =D

I'm sorry but I still don't get the point. I don't want to inherit ShaderMaterial, just create one and pass it along. That's how I do it:

1) Create a valid ShaderMaterial like so:

var material = new zen3d.ShaderMaterial
({
        uniforms: {}, // empty, as they will be filled by GLTFLoader
        vertexShader: fastlit_vert, // <- valid shader code
        fragmentShader: fastlit_frag // <- valid shader code
});
material.diffuseMap = diffuseMap;
material.normalMap = normalMap;
material.aoMap = aoMap;

2) Pass it to the GLTFLoader like so:

this.loader.load( data, onLoad, onProgress, onError, [ material ] );

3) Literally the first thing happening on the GLTFLoader side:

GLTFLoader.prototype.load = function( url, onLoad, onProgress, onError, customMaterials ) {
          this.manager.customMaterials = customMaterials;

Now, this works without errors when using zen3d.PBRMaterial, but not with my zen3d.ShaderMaterial.

4) However it kind of works when I disable the material cloning in GLTFLoader:

if (useVertexTangents || useVertexColors || useFlatShading || useSkinning) {
                                                //material = material.clone();

But the skinned mesh now looks deformed and animations are wrong. Obviously some material uniforms or attributes are not passed along.

Thanks again & best regards!

shawn0326 commented 3 years ago

ah...seems like shaderMaterial.clone() has bug, let me see ...

shawn0326 commented 3 years ago

ah...seems like shaderMaterial.clone() has bug, let me see ...

@SoundAndColour bug fixed on dev branch.

SoundAndColour commented 3 years ago

Works like a charm now, great =D Thanks a lot!