BABYLON.Material in the inspector

When my custom material (SimpleMaterial) class does not show as a Material in the inspector but as a TransformNode and NO Material properties. It like if its NOT derived from StandardMaterial or PBRMaterial… it wont show as a Material in the inspector.

Example Simple Material Class:

class MyTesterMat extends BABYLON.PushMaterial

But this is how it shows in the inspector:

Also it does not show the TOP level class is show the as the base class of StandardMaterial of PBRMaterial

But if i a class like MyTestStandard extends BABYLON.StandardMaterial is does not show in the inspector as MyTestStandard but instead shows up as StandardMaterial

you have to make sure to provide a getClassName() function that will return “StandardMaterial”

What about my subclass PushMaterial showing up as a TransformNode in the Inspector ???

This is because it is the default behavior when the getClassName() function is not defined

But my Simple Material DOES have getGlassName():

    public clone(name: string): MyTestMaterial {
        return BABYLON.SerializationHelper.Clone<MyTestMaterial>(() => new MyTestMaterial(name, this.getScene()), this);
    }

    public serialize(): any {
        var serializationObject = BABYLON.SerializationHelper.Serialize(this);
        serializationObject.customType = "MyTestMaterial";
        return serializationObject;
    }

    public getClassName(): string {
        return "MyTestMaterial";
    }

and

BABYLON._TypeStore.RegisteredTypes["MyTestMaterial"] = MyTestMaterial;

But my Simple Material in the inspector (which is using MyTestMaterial and is rendering corretly in the scene) as a TransformNode with no material properties on the right :frowning:

You have to return something MAterial at least for the inspector to catch up

I dont get that… Return what ?? And Where ??

FYI … This is my TestSimple Push Material Class

/**
 * Babylon Shader Defines
 * @class TestSimpleDefines
 */
class TestSimpleDefines extends BABYLON.MaterialDefines {
    public DIFFUSE = false;
    public CLIPPLANE = false;
    public CLIPPLANE2 = false;
    public CLIPPLANE3 = false;
    public CLIPPLANE4 = false;
    public ALPHATEST = false;
    public DEPTHPREPASS = false;
    public POINTSIZE = false;
    public FOG = false;
    public NORMAL = false;
    public UV1 = false;
    public UV2 = false;
    public VERTEXCOLOR = false;
    public VERTEXALPHA = false;
    public NUM_BONE_INFLUENCERS = 0;
    public BonesPerMesh = 0;
    public INSTANCES = false;

    constructor() {
        super();
        this.rebuild();
    }
}
/**
 * Babylon Shader Material
 * @class TestSimple
 */
class TestSimple extends BABYLON.PushMaterial {
    @BABYLON.serializeAsTexture("diffuseTexture")
    private _diffuseTexture: BABYLON.BaseTexture;
    @BABYLON.expandToProperty("_markAllSubMeshesAsTexturesDirty")
    public diffuseTexture: BABYLON.BaseTexture;

    @BABYLON.serializeAsColor3("diffuse")
    public diffuseColor = new BABYLON.Color3(1, 1, 1);

    @BABYLON.serialize("disableLighting")
    private _disableLighting = false;
    @BABYLON.expandToProperty("_markAllSubMeshesAsLightsDirty")
    public disableLighting: boolean;

    @BABYLON.serialize("maxSimultaneousLights")
    private _maxSimultaneousLights = 4;
    @BABYLON.expandToProperty("_markAllSubMeshesAsLightsDirty")
    public maxSimultaneousLights: number;

    private _renderId: number;

    constructor(name: string, scene: BABYLON.Scene) {
        super(name, scene);
    }

    public needAlphaBlending(): boolean {
        return (this.alpha < 1.0);
    }

    public needAlphaTesting(): boolean {
        return false;
    }

    public getAlphaTestTexture(): BABYLON.Nullable<BABYLON.BaseTexture> {
        return null;
    }

    // Methods
    public isReadyForSubMesh(mesh: BABYLON.AbstractMesh, subMesh: BABYLON.SubMesh, useInstances?: boolean): boolean {
        if (this.isFrozen) {
            if (this._wasPreviouslyReady && subMesh.effect) {
                return true;
            }
        }

        if (!subMesh._materialDefines) {
            subMesh._materialDefines = new TestSimpleDefines();
        }

        var defines = <TestSimpleDefines>subMesh._materialDefines;
        var scene = this.getScene();

        if (!this.checkReadyOnEveryCall && subMesh.effect) {
            if (this._renderId === scene.getRenderId()) {
                return true;
            }
        }

        var engine = scene.getEngine();

        // Textures
        if (defines._areTexturesDirty) {
            defines._needUVs = false;
            if (scene.texturesEnabled) {
                if (this._diffuseTexture && BABYLON.MaterialFlags.DiffuseTextureEnabled) {
                    if (!this._diffuseTexture.isReady()) {
                        return false;
                    } else {
                        defines._needUVs = true;
                        defines.DIFFUSE = true;
                    }
                }
            }
        }

        // Misc.
        BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);

        // Lights
        defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);

        // Values that need to be evaluated on every frame
        BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);

        // Attribs
        BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);

        // Get correct effect
        if (defines.isDirty) {
            defines.markAsProcessed();
            scene.resetCachedMaterial();

            // Fallbacks
            var fallbacks = new BABYLON.EffectFallbacks();
            if (defines.FOG) {
                fallbacks.addFallback(1, "FOG");
            }

            BABYLON.MaterialHelper.HandleFallbacksForShadows(defines, fallbacks, this.maxSimultaneousLights);

            if (defines.NUM_BONE_INFLUENCERS > 0) {
                fallbacks.addCPUSkinningFallback(0, mesh);
            }

            //Attributes
            var attribs = [BABYLON.VertexBuffer.PositionKind];

            if (defines.NORMAL) {
                attribs.push(BABYLON.VertexBuffer.NormalKind);
            }

            if (defines.UV1) {
                attribs.push(BABYLON.VertexBuffer.UVKind);
            }

            if (defines.UV2) {
                attribs.push(BABYLON.VertexBuffer.UV2Kind);
            }

            if (defines.VERTEXCOLOR) {
                attribs.push(BABYLON.VertexBuffer.ColorKind);
            }

            BABYLON.MaterialHelper.PrepareAttributesForBones(attribs, mesh, defines, fallbacks);
            BABYLON.MaterialHelper.PrepareAttributesForInstances(attribs, defines);

            var shaderName = "Test Simple";
            var join = defines.toString();
            var uniforms = ["world", "view", "viewProjection", "vEyePosition", "vLightsType", "vDiffuseColor",
                "vFogInfos", "vFogColor", "pointSize",
                "vDiffuseInfos",
                "mBones",
                "vClipPlane", "vClipPlane2", "vClipPlane3", "vClipPlane4", "diffuseMatrix"
            ];
            var samplers = ["diffuseSampler"];
            var uniformBuffers = new Array<string>();

            BABYLON.MaterialHelper.PrepareUniformsAndSamplersList(<BABYLON.EffectCreationOptions>{
                uniformsNames: uniforms,
                uniformBuffersNames: uniformBuffers,
                samplers: samplers,
                defines: defines,
                maxSimultaneousLights: this.maxSimultaneousLights
            });
            subMesh.setEffect(scene.getEngine().createEffect(shaderName,
                <BABYLON.EffectCreationOptions>{
                    attributes: attribs,
                    uniformsNames: uniforms,
                    uniformBuffersNames: uniformBuffers,
                    samplers: samplers,
                    defines: join,
                    fallbacks: fallbacks,
                    onCompiled: this.onCompiled,
                    onError: this.onError,
                    indexParameters: { maxSimultaneousLights: this._maxSimultaneousLights - 1 }
                }, engine), defines);

        }
        if (!subMesh.effect || !subMesh.effect.isReady()) {
            return false;
        }

        this._renderId = scene.getRenderId();
        this._wasPreviouslyReady = true;

        return true;
    }

    public bindForSubMesh(world: BABYLON.Matrix, mesh: BABYLON.Mesh, subMesh: BABYLON.SubMesh): void {
        var scene = this.getScene();

        var defines = <TestSimpleDefines>subMesh._materialDefines;
        if (!defines) {
            return;
        }

        var effect = subMesh.effect;
        if (!effect) {
            return;
        }
        this._activeEffect = effect;

        // Matrices
        this.bindOnlyWorldMatrix(world);
        this._activeEffect.setMatrix("viewProjection", scene.getTransformMatrix());

        // Bones
        BABYLON.MaterialHelper.BindBonesParameters(mesh, this._activeEffect);

        if (this._mustRebind(scene, effect)) {
            // Textures
            if (this._diffuseTexture && BABYLON.MaterialFlags.DiffuseTextureEnabled) {
                this._activeEffect.setTexture("diffuseSampler", this._diffuseTexture);

                this._activeEffect.setFloat2("vDiffuseInfos", this._diffuseTexture.coordinatesIndex, this._diffuseTexture.level);
                this._activeEffect.setMatrix("diffuseMatrix", this._diffuseTexture.getTextureMatrix());
            }

            // Clip plane
            BABYLON.MaterialHelper.BindClipPlane(this._activeEffect, scene);

            // Point size
            if (this.pointsCloud) {
                this._activeEffect.setFloat("pointSize", this.pointSize);
            }

            BABYLON.MaterialHelper.BindEyePosition(effect, scene);
        }

        this._activeEffect.setColor4("vDiffuseColor", this.diffuseColor, this.alpha * mesh.visibility);

        // Lights
        if (scene.lightsEnabled && !this.disableLighting) {
            BABYLON.MaterialHelper.BindLights(scene, mesh, this._activeEffect, defines, this.maxSimultaneousLights);
        }

        // View
        if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== BABYLON.Scene.FOGMODE_NONE) {
            this._activeEffect.setMatrix("view", scene.getViewMatrix());
        }

        // Fog
        BABYLON.MaterialHelper.BindFogParameters(scene, mesh, this._activeEffect);

        this._afterBind(mesh, this._activeEffect);
    }

    public getAnimatables(): BABYLON.IAnimatable[] {
        var results = [];

        if (this._diffuseTexture && this._diffuseTexture.animations && this._diffuseTexture.animations.length > 0) {
            results.push(this._diffuseTexture);
        }

        return results;
    }

    public getActiveTextures(): BABYLON.BaseTexture[] {
        var activeTextures = super.getActiveTextures();

        if (this._diffuseTexture) {
            activeTextures.push(this._diffuseTexture);
        }

        return activeTextures;
    }

    public hasTexture(texture: BABYLON.BaseTexture): boolean {
        if (super.hasTexture(texture)) {
            return true;
        }

        if (this.diffuseTexture === texture) {
            return true;
        }

        return false;
    }

    public dispose(forceDisposeEffect?: boolean): void {
        if (this._diffuseTexture) {
            this._diffuseTexture.dispose();
        }

        super.dispose(forceDisposeEffect);
    }

    public clone(name: string): TestSimple {
        return BABYLON.SerializationHelper.Clone<TestSimple>(() => new TestSimple(name, this.getScene()), this);
    }

    public serialize(): any {
        var serializationObject = BABYLON.SerializationHelper.Serialize(this);
        serializationObject.customType = "TestSimple";
        return serializationObject;
    }

    public getClassName(): string {
        return "TestSimple";
    }

    // Statics
    public static Parse(source: any, scene: BABYLON.Scene, rootUrl: string): TestSimple {
        return BABYLON.SerializationHelper.Parse(() => new TestSimple(source.name, scene), source, scene, rootUrl);
    }
}
BABYLON._TypeStore.RegisteredTypes["TestSimple"] = TestSimple;

I don’t get that i have to return something. Im guess i am just missing it :frowning:

Change getClassName to return “StandardMaterial” unless I am mistaken on what delta is saying.

Or even fhahdbeksbfvwjstdbwbrrMaterial.

It’s looking for material in the name?

Yep @Pryme8 is right

Oh ok… You mean make my class names

public getClassName(): string {
        return "TestSimpleMaterial";
    }

… Does the class need to actuall end with ‘Material’ or just what we return in getClassName ???

What about the RegisterTypes call:

BABYLON._TypeStore.RegisteredTypes["TestSimple"] = TestSimple;

Does that need to be:

BABYLON._TypeStore.RegisteredTypes["TestSimpleMaterial"] = TestSimple;

???

I guess it would be BETTER to name your classes with the literal ‘Material’ Like MyTestMaterial

2 Likes