简体   繁体   中英

Three.JS + OOP in javascript, can't pass a 3D JSON object to other class

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> 

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 );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM