Extending Mesh Class?

This may be more of the TypeScript question, but why does this not work. I just wish to add a boolean property to a Mesh class without the sneaky :any.

export class MenuItem3D extends Mesh{
    private _isChecked: Boolean = false;
    constructor(name:string,scene:Scene) {
        super(name,scene);
        this._isChecked = false;
    }
    public get isChecked() {
        return this._isChecked;
    }
    public set isChecked( checked: Boolean) {
        this._isChecked = checked;
    }
}

This line, properly typed :
let t:OptionItem3D = OptionItem3D.CreatePlane( "test", 10 , scene )

Errors with : ā€œType ā€˜Mesh’ is missing the following properties from type ā€˜MenuItem3D’: _isChecked, isCheckedā€

let t:any= OptionItem3D.CreatePlane( "test", 10 , scene )

Allows for compile.

https://playground.babylonjs.com/#S4CF48#1

Thanks

1 Like

I just found .metadata:any

I’ll just place it there, but still curious why this doesn’t work.

I think the issue is that the static methods like CreatePlane create and return a Mesh object (which doesn’t have property isChecked defined), rather than creating and returning an OptionItem3D object as wanted.

2 Likes

did you try extending the Mesh prototype? Not recommending it, but that’s how you can modify the Mesh object. Here is an example on the scene itself, which defines a property and a function that uses that property:
Babylon.js/geometryBufferRendererSceneComponent.ts at c843dcbc3875e9eee184152a10b857f7af9f4993 Ā· BabylonJS/Babylon.js (github.com)

1 Like

A pretty clean and easy way, IMO, to implement static functions like CreatePlane is to call the original method and pass the created plane mesh through the subclass constructor to the Mesh constructor (as the source parameter, which will essentially clone the mesh). Like this below for the CreatePlane function for example:

public static CreatePlane(name: string, size: number, scene: BABYLON.Scene, updatable?: boolean, sideOrientation?: number) : MenuItem3D {
    const planeMesh = super.CreatePlane(name, size, scene, updatable, sideOrientation);
    const menuItem3D = new MenuItem3D(name, scene, null, planeMesh);
    planeMesh.dispose();
    return menuItem3D;
}

And here’s a playground for it. Note, to fix the warning we could use MeshBuilder.CreatePlane instead of the deprecated (but still supported) Mesh.CreatePlane.

1 Like

@Blake : ahhhh. that makes sense.

And you example works like a charm. Is there a downside to this?

I’m looking to incorporate all the interactivity in the class as well and more complex meshes. Perhaps there’s a better class to extend in the case of having interactivity in it? I’m now thinking the Transform Node and with a public function it could create it’s own children and interactivity within multiple meshes/lights ect.

I had previously done something crazy like this, mapping over the vertex data, which worked but seemed very wrong and didn’t give me a unique class… :slight_smile:

class GizmoPointer3D extends Mesh{
    constructor( name,scene ) {
        super( name, scene );
        /* build pointer using prims */
        var cylinder =  MeshBuilder.CreateCylinder("cylinder", {height: 6, diameter: 0.5}, scene );
        var cone =  MeshBuilder.CreateCylinder("cone", {height:3,diameterTop: .3, diameterBottom:2,  tessellation: 12}, scene );
        cylinder.setPivotPoint(  new Vector3( 0,-3,0) );
        cylinder.position =  new Vector3(0,3,0)
        cone.position =  new Vector3(0,5,0)

        /* merge prims */
        var mesh:Mesh =  Mesh.MergeMeshes([ cylinder,cone]);
        mesh.setPivotPoint(  new Vector3( 0,0,0) );
        mesh.material = null;

        /* transfer vertex data to .this Mesh */
        var vertexData = new VertexData();
        vertexData.positions = mesh.subMeshes[0].getMesh()._getPositionData( false )
        vertexData.indices = mesh.subMeshes[0].getMesh().getIndices()
        var normals = [];
        VertexData.ComputeNormals( vertexData.positions, vertexData.indices, normals );
        vertexData.applyToMesh( this );

        /* set name */
        this.name = name;

        /* clean up construction mesh */
        mesh.dispose();
     }
}
2 Likes

Hmm, the only downside I can see is it taking maybe a tiny bit longer to create the MenuItem3D object than a normal mesh, but I think that would likely be an insignificant one-time cost, compared to the gains in simplicity and cleanliness.

As for TransformNode vs Mesh, if it’s just a parent and not itself rendered then I would go with a TransformNode parent, because it’s lighter…

Hmm, that’s interesting, your implementation looks like it should work, as far as creating a unique class :thinking:

Thanks Blake!

This got me exactly where ( I think ) I want to be… I’ve added a ā€œBlue Printā€ node extending the Transform node, which includes some interactivity and access to itself all nicely contained!

I do not envision having thousands of these in my scene, so unless there is some huge performance hit for doing it this way, this is the way I’m going.

https://playground.babylonjs.com/#S4CF48#5

class BluePrintNode extends BABYLON.TransformNode{
    private mesh1:BABYLON.Mesh;
    private light1:BABYLON.Light;

    constructor( name: string,
        scene: BABYLON.Nullable<BABYLON.Scene> = null, m1:BABYLON.Mesh,l1:BABYLON.Light ){
        super( name, scene );
    }
   public static CreateBoxAndLight( name:string,scene:BABYLON.Scene) : BluePrintNode {
        const m1 = BABYLON.MeshBuilder.CreateBox("box", {size: 1}, scene);
        m1.position = new BABYLON.Vector3(1,0,-3);
        m1.parent = this;

        const l1 = new BABYLON.PointLight("pointLight", new BABYLON.Vector3(0,5,0), scene);
        l1.diffuse =new BABYLON.Color3( 1,0,0);
        l1.parent = this;

        m1.actionManager = new BABYLON.ActionManager( scene );
        m1.actionManager.registerAction(
            new BABYLON.ExecuteCodeAction(
                {trigger:  BABYLON.ActionManager.OnPickDownTrigger},
                function (evt) {
                    l1.diffuse = new BABYLON.Color3( Math.random(),Math.random(),Math.random())
                }
            )
        );
        return new BluePrintNode( name,scene,m1,l1);
    }
}
1 Like

I’m starting to understand how people have some seriously long play grounds… hahah so much fun.

I added linking of the meshs to the transform ( which I missed ) and added animation via registerBeforeRender multiple instances…plus Randomization and material changes…

okay I need to stop now… :slight_smile:

https://playground.babylonjs.com/#S4CF48#9

4 Likes