How to assign to variable content of Three.js model file - javascript

When you export your model from Blender to Three.js you end up with a file with JSON data inside. I know two ways of loading this model from that file:
var loader = new THREE.JSONLoader()
var material = new THREE.MeshPhongMaterial({color: '#8080a0'})
1.
loader.load('tower.json', function (geometry) {
var mesh = new THREE.Mesh(geometry, material)
})
2. Edit tower.js file and add
var tower =
in first line. Then you can load it with:
var towerModel = loader.parse(tower)
var mesh = new THREE.Mesh(towerModel.geometry, material)
I like second solution more because using loader.load() function every time you want to create a mesh when you have thousands of meshes based on the same model is very slow and can easly kill your browser.
So my question is - can I get JSON data from tower.json file into a variable without editing the file manually? The best solution would be to get JSON data into a variable without making changes to the file.

I would go for option 1.
It sounds very strange to add a loader to a source file.
To keep things clean you should keep loaders and data sources (your model files) separated if you ask me.
Why would you reload the same model anyway. You should just store it in a variable and reuse it. It is a waste of CPU and memory to load the same geometry twice.
You can do easily something like this to optimize things. It is just a concept but I hope you get the idea:
// Storage for model files
myFiles = {
tower: 'tower.json',
car: 'car.json'
};
// Storage for loaded geometries
myModels = {
tower: null,
car: null
};
// Loader, loads only first time from file then from storage
var load = function( modelName ){
if( myModels[modelName] === null ){
loader.load(myFiles[modelName], function (geometry) {
myModels[modelName] = geometry;
});
}
var model = new THREE.Mesh(myModels[modelName], material)
scene.add( model );
}
You can rework it how you think is best.

Related

.3ds loader does not load materials and textures

I am trying to load quite complex .3ds model into three.js using TDSLoader exactly the same way as in three.js/examples: https://github.com/mrdoob/three.js/blob/master/examples/webgl_loader_3ds.html
but what I get looks like this Result when it is supposed to look like this Loaded using https://3dviewer.net/. I can see that this online viewer uses three.js so it is possible. I also know that TDSLoader loads textures but does not map them for some reason (if I move texture out of the folder I get an load resource error). Code looks like this:
var loader = new THREE.TextureLoader();
var normal = loader.load('textures/normal.png');
var loader = new THREE.TDSLoader();
loader.setPath('textures/');
loader.load('textures/CAT_336D.3ds', function (object) {
object.traverse(function (child) {
if (child instanceof THREE.Mesh) {
child.material.normalMap = normal;
}
});
scene.add(object);
});
My model has 23 types of materials but the loader loads only 2 - black and yellow, you can see that glass, metal and others are missing. How do I map all textures and materials? Maybe it does not work because the model is too big? (over 160 meshes, around 30MB)

How to remove and dispose of all child geometry and meshes from an Object3D?

In this project I am working on I have several Collada models being displayed and then removed when not needed anymore. There seems to be a memory leak somewhere in the project and I am looking for ways to get it to run as smooth as possible as time is not on my sideā€¦
I feel like I don't remove the meshes the right way and that this might cause some of the memory leakage I have.
I load the objects with LoadObject(level_1_character, "Assets/Level_1_Character.dae"); for example, where level_1_character is a Object3D. This calls the following function:
function LoadObject(name, url) {
var mesh, geometry, material, animation;
var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load(url, function(col) {
mesh = col;
geometry = col.scene;
name.name = url.toString();
name.add(geometry);
});
}
I add the objects to the scene depending on the level through scene.add(level_1_character); and then remove it by doing the following:
level_1_character.traverse(function(child){
if (child instanceof THREE.Mesh) {
child.material.dispose();
child.geometry.dispose();
}
});
I am not sure if this actually fully removes the object though. It seems as though the objects still are present in memory. Any idea what I'm doing wrong here?

How to automatically update a mesh on changing parameters on THREE.js

I'm new to Threejs and to javascript in general. I'm building a mesh based on a json parameters object and it works great.
Now I'm adding some UI components (button, slider, etc) to change the json and rebuild the mesh. I'm writing some monkey-code and I'm sure it can be avoided. Now my stuff works correctly but I'm sure that the problem can be solved more elegantly.
This is my actual workflow:
on slider change use a callback
that callback calls a setter
the setter change the JSON parameters and rebuild the mesh
I'm sure all this can be automated by simply change the JSON and some javascript magic.
Here is the actual pseudocode:
sliderWidth.onChange( function(newValue) {
MyObject3D.setWidth(newValue);
});
and this is a skelton of my MyObject3D:
var MyObject3D = function(parameters) {
this.parameters = parameters;
this.init();
};
MyObject3D.prototype.init = function() {
var geometry = this.initGeometry();
var material = new THREE.MeshPhongMaterial( { color: this.parameters.color, shading: THREE.FlatShading } );
this.mesh = new THREE.Mesh(geometry, material);
}
MyObject3D.prototype.setWidth = function(n) {
this.parameters.width = n;
scene.remove( this.mesh );
this.init();
scene.add( this.mesh );
}
I'm sure that with the javascript high-dinamicity and with all brand new frameworks this piece of code can be easily automated. I've looked mainly at d3.js and at angular.js. In particular d3.js seems to be perfect with the enter-update-exit paradigm (but I didn't find a standard way to conjugate it with Three.js) and angular for sure has to be something in it.
Any kind of advice on structure, pattern, specific use case or examples based on one of the frameworks mentioned THREE.js, d3.js, angular.js) can be enlightening. Actually I'd prefer a solution with angular.js..
There was an excellent talk about using three.js and angular.js which exactly showcases your problem.
https://www.youtube.com/watch?v=mCIZoLaPJxM&t=8m5s
Im using angular directives that watch on a specific attribute and then execute some logic onchange in my projects.
$scope.$watch($attrs.something, function(changedSomething){
doSomeLogicWith(changedSomething);
});

grouped collada models onload three.js

I am currently loading in a bunch of elements of a model and adding them to a group. I then want to be able to move the group as a whole unit after they load.
My issue is, how can I run code once I have ensured that all of my models have loaded?
I don't understand how to use the .onload function with the colladaLoader & its callback functions. Also, is it a bad idea to use a self executing function like I have here? I am not sure how else to go through a list and load in all the models.
My code is below. I have tried to use a hack, by using the counter "complete" but it doesn't work all of the time. Thanks!
for ( var i=0; i<object.asset.length; i++ ) {
loader = new THREE.ColladaLoader();
asset = furniture.asset[i];
(function(asset) {
loader.load(asset["path"], function(collada, materials) {
//this function scales & positions model
var mesh = daeAttributes(collada, object, asset, newMaterial);
var scene = get_scene();
group.add( mesh );
complete++;
//when all assets have been loaded, add the group to the scene
if (complete===object.asset.length-1) {
//want to move the group once all the models are loaded
group = moveModel(group, object);
scene.add( group );
render();
};
});
})(asset);
Update
So if I have a list >1, of unique objects to load in, it works. If there is only 1 object it doesn't load that one object.
If you put everything inside of this it should work:
<body onload="myFunction()">

Can't load converted from FBX to JSON model using THREE.JSONLoader

I converted an FBX model to JSON using convert-to-threejs.py, but I can't get three.js (r58) to load it. It says "Uncaught TypeError: Cannot read property 'length' of undefined". The error is at line 9930 in three.js which line is for ( i = 0; i < json.uvs.length; i++ ) ...
Here's the converted JSON: http://pastebin.com/86ZGvKnW. You'll see that it does not, in fact, have a uvs property.
Is convert-to-threejs.py outdated? If so, what's the alternative? If not, how can I get this model to load?
Here's my code:
window.loader = new THREE.JSONLoader();
loader.load('jet.json', function(geometry) {
// Never gets to here; error is thrown first
console.log(geometry);
});
Oh, I see. The actual model is embedded in that JSON file. I want embeds["Embed_31_jet 3"].
FBX files converted to JSON seem to describe complete scenes. So, instead of THREE.JSONLoader, use THREE.SceneLoader.
For example
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(...);
var loader = new THREE.SceneLoader();
loader.load('jet.json', function(res) {
scene.add(res.scene);
renderer.render(res.scene, camera);
});

Categories