THREE.js disposing gltf objects - javascript

I have a THREE.js project that includes an imported gltf object:
loader.load("myObj.gltf",
function(gltf){
scene.add(gltf.scene);
},
undefined,
function(error){alert(error);});
Later, I clone the object:
let newObj = oldObj.clone();
In order to clear up memory, I have to dispose of the new cloned object, but not the original. How would I go about doing this? I tried dispose(), but that did not work.

If you clone 3D objects like meshes, lines or point clouds in three.js, their materials, textures and geometries are not cloned but shared. So it should be sufficient to just remove cloned objects from the scene.
You can read more about what type of entities have a dispose() method in the following guide: https://threejs.org/docs/index.html#manual/en/introduction/How-to-dispose-of-objects

Related

Three.js skinning issue from OpenAssetImport-converted model

I've been trying to understand the maths behind Three.JS's skinning and I've been stuck there for a while.
My use case is loading "any" 3D model that is passed through OpenAssetImport and saved in a custom model format (mostly built for a custom native render, but it's just a representation of assimp's data structures).
In this model format I track:
Meshes (obviously)
Nodes (as in the 'assimp' definition of nodes)
Bones
For each bone, I track:
The node which it is attached to
The individual 'bind matrix' as defined by assimp
I'm then struggling to re-construct the skeleton in Three.JS. My attempt is this:
Generate all the 'nodes' (as in, 'assimp' nodes) as simple THREE.Object3D
Attach the meshes when required
For each bone
Find the node (THREE.Object3D) it's attached to
Create a new THREE.Bone
Apply assimp's 'bind matrix' to the ThreeJS bone with bone.applyMatrix(assimpBone.bindMatrix)
Set the THREE.Bone as a child of the THREE.Object3D
Create a THREE.Skeleton with the array of THREE.Bone objects
Attach it to the mesh with 'attached' bind mode
However, for some models this works, while for others I have big errors with meshes being de-formed (even if the base mesh is still at least recognizable).
Example mesh loaded with skinning disabled:
Same mesh loaded with skinning enabled:

Three.js - update Mesh Colour of Object3D

I have a Three.js Object3D that I would like to update the colour of.
I originally construct the Mesh using a MeshStandardMaterial and add it into the scene. Later, I look up this object by ID and retrieve an Object3D from the scene. How can I update the colour of the Mesh at this point - is it possible?
If I have to delete the 3D object and add an entirely new one - is there a way to retrieve the geometry that was originally used to construct it from the Object3D itself? I would rather not store a mapping of the original geometry to an object's ID, as this would make the code messy. One option I can think of is to store the geometry on Object3D.UserData, but this is again suboptimal as currently the Meshes are constructed elsewhere - and then added to the scene (user data is available only once it has been added to the scene).
I find a way to add texture into a Object3D.
You can map children property to update material of meshes.
function onLoad(object) {
// `children` is an array of `Mesh` than contain 1 or more Meshes
object.children.forEach((mesh) => {
if (!mesh) return;
const material = mesh.material;
material.map = ghostColorTexture;
material.normalMap = ghostNormalTexture;
});
}
const objLoader = new OBJLoader();
objLoader.load(
'/models/ghost/model/ghost.obj',
onLoad,
undefined,
function (error) {
console.error('error', error);
}
);
An Object3D can be a Mesh that's composed of a Geometry and a Material. If you want to update the color, simply select that material, and assign a new color to it:
object.material.color.setHex(0xff9900); // Sets to orange
In the docs, you can see that .color is a property of MeshStandardMaterial and .material is a property of Mesh

Adding Physics to OBJ Model in ThreeJS

I am trying to use PhysiJS with ThreeJS. I have an OBJ model that I exported from Blender. When I load it with OBJLoader, I see that it is a BufferGeometry. I also notice that it is missing a vertices property, which is what PhysiJS looks for.
My ThreeJS version is r101. I would appreciate any suggestions. If there is a more suitable library, I am open to that too. I am also happy to provide any clarifications.
If you need to convert your BufferGeometry to Geometry, you can simply use the .fromBufferGeometry() method.
// Called when your obj finishes loading
onLoadComplete(obj) {
var geom = new THREE.Geometry();
geom.fromBufferGeometry(obj);
// Now you'll have access to vertices
console.log(geom.vertices);
}

Distorted UVs on a single object in my Three.js scene

I've been putting together a 3d model of a house and right now I'm stuck with yet another aggravating roadblock like those three.js has gotten me accustomed to.
I'm creating my scene in Maya and using the OBJ exporter to write obj and mtl files that I then import into three.js. I have about 9 objects in my scene, ungrouped, children only to the world, history deleted, and with texture maps that have ambient occlusion and lighting baked into them assigned to them via shadingMaps.
I've actually had little luck actually using the mtl file, so I just copied my texture maps and loaded them separately and created materials out of them in three.js.
Now, all of these objects look just fine in the browser, except for the simplest one, the walls and floor object. This is what the object looks like in Maya:
As you can see, a rather simple mesh with minimal polys looking beautiful in Maya.
I've learned that when I export objects into obj files, only one UV channel is supported, so I copy my UVs into the default channel and delete all other UV channels before exporting. This is the UV map:
But when I assign this material in the browser, I get a strange texture distortion like so:
It's like the UVs are all over the place. I would seriously doubt that my approach is anywhere close to being on target if it weren't for those 8 other (more complex, mind you) objects which all display fine.
, including part of the wall that I've cut out of the problematic piece, which is part of the bathroom.
Does anyone have a clue as to how I can troubleshoot this? I've tried exporting straight to js from Maya, but I'm having even more problems with that approach. I've tried converting the obj file into js using the packaged browser-based converter. I've spent days on this and am not making any progress.
Here's some relevant code.
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer({antialias: true} );
var wallTexture = THREE.ImageUtils.loadTexture("obj/final_walls.jpg");
var wallMaterial = new THREE.MeshLambertMaterial( {color: 0x929EAC, map:wallTexture} );
var manager = new THREE.LoadingManager();
var loader = new THREE.OBJMTLLoader( manager );
loader.load( 'obj/wallOnly.obj','obj/wallOnly.mtl', function ( object ) {
object.children[2].material = wallMaterial;
floorplan.add(object);
camera.lookAt( object );
} );
Please help!!
OMG! After running my head through the wall, I finally found the solution!
I've discovered that the problem was not as much a distortion of the texture as it was a random swapping of uv faces. That's right! For some reason, the webGL renderer randomly swapped some faces of the object with others.
Out of total coincidence I turned my mesh into quads instead of triangles and, voila!, that fixed everything. QUADS!!! I wasted friggin 3 solid days on triangles!!!

Three.js load multiple separated objects / JSONLoader

is it possible to load a scene (e.g. two different cubes) exported from blender to json and identify them?
I need to distinguish between them e.g. to make one rotating and the other moving.
Thank you in advance!
Denv
edit+++
Thank you for your answer!
So if I load two cubes in one JSON file:
loader.load("untitled1.js", function(geometry, materials) {
mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial(materials));
mesh.scale.set( 10, 10, 10 );
mesh.position.y = 0;
mesh.position.x = 0;
scene.add( mesh );
});
How can I move first cube?
mesh.getObjectById(0).position.x = 15;
Doesn't seems to work.
Thank you!
Yes, it is possible to load an entire scene from a json file exported from Blender!
I achieved that with the following process: (Using three.js r80)
First you have to name your different objects in Blender like in the following image Outliner.
Then you can export the file using Three.js json exporter add-on for Blender, but taking care of marking the Scene checkbox like in the following:
Using this option your json file now contains all the meshes on the Blender's Outliner, as you can verify using any text editor. It doesn't matter if the meshes were selected or not.
It is important to know that the root (or parent) object isn't a Geometry anymore. It is labeled with the Object type by now. To access the children objects (of Mesh type) you can use the getObjectByName method on the root object like in the following code:
jsonloader.load( "obj/Books.json", function ( loadedObj ) {
var surface = loadedObj.getObjectByName("Surface");
var outline = loadedObj.getObjectByName("Outline");
var mask = loadedObj.getObjectByName("Mask");
// Watch the objects properties on console:
console.log(loadedObj);
console.log(surface);
console.log(outline);
console.log(mask);
} );
If we check the browser's console, we can see the proper objects assigned. And from now, you can manipulate the children objects independently (move, rotate, change materials, etc.)
Each object loaded has an associated .id. So you can use the Object3D.getObjectById() to find it and apply transforms on it.

Categories

Resources