Search code examples
javascriptthree.jsextend

How to extend THREE.Mesh class for constructor function


I'm playing around with Three.js and making a (simple!) model of the solar system. I am trying to make a constructor function to build out the planets and moons, this is what I've been trying so far but I get an error saying:

setShadow() is not a function:

var body = function(size, color) {
  this.sphere = new THREE.Mesh(new THREE.SphereGeometry(size, 32, 32), 
                               new THREE.MeshLambertMaterial({color:color}))
  return this.sphere
}

body.prototype = Object.create(THREE.Mesh.prototype);
body.prototype.constructor = body;

body.prototype.setShadow = function() {
  this.sphere.castShadow = true
  this.sphere.receiveShadow = true
}

Alternatively, I've tried using THREE.MESH.call(this, geometry, material) where THREE.SphereGeometry = geometry and THREE.MeshLambertMaterial = material are defined outside the constructor function. Is this something in particular I need to worry about with Three.js or am I just approaching this incorrectly?

Edit: Alternative try ->

var body = function() {
      THREE.Mesh.call(this)
      return this
    }

    body.prototype.setShadow = function() {
      this.castShadow = true
      this.receiveShadow = true
      return this
    }
    body.prototype = Object.create(THREE.Mesh.prototype);
    body.prototype.constructor = body;

    var example = new body(new THREE.SphereGeometry(70, 32, 32), new THREE.MeshLambertMaterial({color:this.getRandColor()}))

It seems like everything inherits correctly, but I'm confused as to why the setShadow function is not working correctly?

EDIT 2: actually got this error when trying .call(this) :

this.updateMorphTargets is not a function


Solution

  • You made a mistake in your constructor while extending the THREE.Mesh class.

    Try like this:

    var Body = function(size, color) {
        THREE.Mesh.call(
            this, 
            new THREE.SphereGeometry(size, 32, 32), 
            new THREE.MeshLambertMaterial({color:color})
        );
    }
    
    Body.prototype = Object.create(THREE.Mesh.prototype);
    Body.prototype.constructor = Body;
    

    There is no need to return anything in the constructor since the object created will be automatically returned.

    And in your setShadow method you should simply point to this since the properties castShadow and receiveShadow are direct properties of your newly created Body class (inherited from THREE.Object3D through THREE.Mesh).

    Body.prototype.setShadow = function() {
        this.castShadow = true;
        this.receiveShadow = true;
    }
    

    It is also good practice to use capitals for the first character of your constructor so in my code I changed body to Body. Make sure you rename all other references accordingly.

    Here a demonstration in a fiddle