0

It was hard to describe the problem in a single line so this is the situation.

I am going to build a big Javascript project with Three.js so I'm trying to grasp it's OOP concepts.

1) I created a 3D world Object
2) A base 3D_object class with child classes
3) In the sample bellow you see an option 1 and an option 2 these should produce the same result, but somehow they don't.
Any idea why ? The complete source is in the snippet.

(Three.js should be included before the script and I am assuming there is a 'resources/object.json' file )

Here is a github link of the project, maybe someone will find it this way. (probably need to run it on a local python server for example to bypass the cross-origin file loading problem in chrome)

//create world
    var myWorld = new World(500,500);
    myWorld.AddWorldToPage();


    //load simple model in the world
    var cube = new Cube();
    myWorld.addToScene(cube);


    // load json model in the world
    //option 1
    // myWorld.addToSceneTemp();

    //option 2 OO (not working)
    var jsonObject = new Object_3D_JSON();
    function afterModelLoaded(){
        console.log("after loading is done");
        myWorld.addToScene(jsonObject);

    }
    jsonObject.loadModel(afterModelLoaded);


    myWorld.render();

// Inhertit convencience method
//=====================================================================================================
function inheritsF / rom(child, parent) {
  child.prototype = new parent();
  child.prototype.constructor = child;
}



// 3D Objects
//=====================================================================================================

// 3D object class
//=====================================================================================================
function Object_3DClass() {
    this._geometry = new THREE.BoxGeometry(1, 1, 1);
    this._material = new THREE.MeshBasicMaterial({
      color: 0xff00ff
    });
    this._mesh = new THREE.Mesh(this._geometry, this._material);
  }
  //Get 3D mesh
Object_3DClass.prototype.getMesh = function() {
  return this._mesh;
}

//Animate Object
Object_3DClass.prototype.animateFrame = function() {
  this._mesh.rotation.x += 0.01;
  this._mesh.rotation.y += 0.01;
}
Object_3DClass.prototype.setPosition = function(x, y, z) {
    this._mesh.position.set(x, y, z);
  }
  // END 3D object class
  //===================================================================================================




// 3D Cube class
//=====================================================================================================
function Cube() {
  this._geometry = new THREE.BoxGeometry(1, 1, 1);
  this._material = new THREE.MeshBasicMaterial({
    color: 0x00ff00
  });
  this._mesh = new THREE.Mesh(this._geometry, this._material);
}
inheritsFrom(Cube, Object_3DClass)
  // END OF 3D Cube class
  //=====================================================================================================



// 3D JSON Model class
//=====================================================================================================
function Object_3D_JSON() {

  // instantiate a loader
  this._loader = new THREE.JSONLoader();
  this._mesh = null;


}
inheritsFrom(Object_3D_JSON, Object_3DClass);
//loadModel
Object_3D_JSON.prototype.loadModel = function(whenReady_Fn) {
    //   _geometry = this._geometry;
    var self = this;
    // load a resource
    this._loader.load(
      // resource URL
      'resources/object.json',
      // Function when resource is loaded
      function(geometry, materials) {
        console.log("loading");
        // this._material = new THREE.MultiMaterial( materials );
        self._material = new THREE.MeshBasicMaterial({
          color: 0xffffff
        });
        self._mesh = new THREE.Mesh(geometry, materials);
        self._geometry = geometry;
        whenReady_Fn();
        // scene.add( this._mesh );
      },
      //onProgress
      function() {},
      //onError
      function() {
        console.log("resource not found");
      }
    );
  }
  // END OF 3D JSON Model class
  //=====================================================================================================


// World class
//=====================================================================================================

var World = (function() {
  // World constructor
  function World(width, height) {
    //private members
    //===========================
    this._width = width;
    this._height = height;
    this._scene = new THREE.Scene();

    this._camera = new THREE.PerspectiveCamera(75, this._width / this._height, 0.1, 1000);
    this._camera.position.set(6.8, 9.5, 12.2);
    this._camera.lookAt(new THREE.Vector3(0, 0, 0));

    this._renderer = new THREE.WebGLRenderer();
    this._renderer.setSize(this._width, this._height);


    this._worldName = "Tubrines";
    this._object_3DList = [];


    return _privatePrintMessage.call(this, "message");
  }


  //public
  //===========================
  //functions
  World.prototype.AddWorldToPage = function() {
    document.body.appendChild(this._renderer.domElement);
  }

  World.prototype.render = function() {
    //zichzelf meegeven aan AnimationFrame
    requestAnimationFrame(this.render.bind(this));

    this._object_3DList[0].animateFrame();



    this._renderer.render(this._scene, this._camera);
  }

  World.prototype.addToScene = function(object_3DClass) {

    this._scene.add(object_3DClass.getMesh());
    this._object_3DList.push(object_3DClass);

  }

  World.prototype.addToSceneTemp = function() {
    _scene = this._scene;
    _object_3DList = this._object_3DList;


    //  instantiate a loader
    var loader = new THREE.JSONLoader();
    // load a resource
    loader.load(
      // resource URL
      'resources/object.json',
      // Function when resource is loaded
      function(geometry, materials) {
        // var material = new THREE.MultiMaterial( materials );
        var material = new THREE.MeshBasicMaterial({
          color: 0xff00ff
        });
        var mesh = new THREE.Mesh(geometry, material);
        _scene.add(mesh);
        _object_3DList.push(mesh);
      });
  }



  //private functions
  //===========================
  function _privatePrintMessage(message) {
    // return prefix + this._foo;
    console.log("World class: " + this._worldName + " " + message);
  }

  return World;
})();
// END OF World class
//=====================================================================================================




//create world
var myWorld = new World(500, 500);
myWorld.AddWorldToPage();


//load simple model in the world
var cube = new Cube();
myWorld.addToScene(cube);


// load json model in the world
//option 1
// myWorld.addToSceneTemp();

//option 2 OO (not working)
var jsonObject = new Object_3D_JSON();

function afterModelLoaded() {
  console.log("after loading is done");
  myWorld.addToScene(jsonObject);

}
jsonObject.loadModel(afterModelLoaded);


myWorld.render();
<!DOCTYPE html>
<html>

<head>
  <meta charset=utf-8>
  <title>My first three.js app</title>
  <style>
    body {
      margin: 0;
    }
    canvas {
      width: 100%;
      height: 100%
    }
  </style>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>

<body>
  <script src="script.js"></script>
</body>

</html>

11
  • 1
    What do you mean by not working? Commented Jan 26, 2017 at 17:36
  • Feeding the "mesh" from the object class to the renderer doesn't produce any image. What I am trying to do is get the mesh form the "object" class and pass it to my "world" class so the world can render the object. If i do it in the non-OOP way (simply creating the mesh inside the world object ), Three.js renders the 3D model perfectly. Commented Jan 26, 2017 at 17:45
  • I'm thnking you're missing a binding when you call jsonObject.loadModel(afterModelLoaded). Did you get any errors in the console? Commented Jan 26, 2017 at 18:08
  • I guess It should be somewhere in that direction yes ^^, but strangely no errors. The weirdest thing is: I can use the console to navigate through the private variables and nothing seems to be missing. The "world" object seems to know my mesh, but it won't render it. I have no idea where to go to with this problem. Commented Jan 26, 2017 at 18:12
  • Here is a github link of the project, maybe someone will find it this way. (probably need to run it on a local python server for example to bypass the cross-origin file loading problem in chrome) Commented Jan 26, 2017 at 18:21

1 Answer 1

1

You are trying to pass a list of materials without telling three.js it's a multimaterial.

Change this line:

self._mesh = new THREE.Mesh( geometry , materials );

to:

var materialSet = new THREE.MultiMaterial( materials );
self._mesh = new THREE.Mesh( geometry , materialSet );

And now that you're using the proper json supplied material, you need to add a light to the scene, otherwise the lambert materials in your model will not show. (lambert materials require lights, basic materials do not, which is why the cube worked).

    this._scene = new THREE.Scene();

    var spotLight = new THREE.SpotLight( 0xffffff );
    spotLight.position.set( 100, 1000, 100 );

    spotLight.castShadow = true;

    spotLight.shadow.mapSize.width = 1024;
    spotLight.shadow.mapSize.height = 1024;

    spotLight.shadow.camera.near = 500;
    spotLight.shadow.camera.far = 4000;
    spotLight.shadow.camera.fov = 30;

    this._scene.add( spotLight );
Sign up to request clarification or add additional context in comments.

2 Comments

Oh wow Thanks! It's fixed!, I copied the code from a more complicated project I made before. (with all these settings) So I was convinced that it was something related to the new OOP approach ':)
Always keep in mind that without lights, a lambert material appears black. View the source of the json to see the material types of your json files. In a 3d json file it will be shown as a property called "shading" with a value of "lambert." You can write your own code to examine the json file yourself to know what's needed to display the file, e.g. add objects such as a spotlight or pointlight, set the material as a multimaterial or single material, etc. There are different code patterns you can use to modify your classes depending on the situation and data at hand. <-- that's true OOP.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.