Three.js - How to replace the model of an Object3D? - javascript

I'm trying to replace an object3D with a character model, with another one, while keeping all it's properties, such as the position
var object = new THREE.Object3D( );
object = models.character[0].clone( );
object.position.set( 100, 230, 15 );
scene.add( object.scene );
const clip = THREE.AnimationClip.findByName( object.animations, 'idle' );
var action = mixer.clipAction( clip );
action.play();
//...later on, replace the model, while keeping it's position
object = models.character[1].clone( );
How do I replace the model of an THREE.Object3D( )?

An Object3D doesn't have a model because it doesn't have geometry or materials. This line of code doesn't do anything because you're immediately replacing the Object3D with something else:
var object = new THREE.Object3D( );
object = models.character[0].clone( );
I think you should be using a Mesh, which is a subclass of Object3D. Now, if you want to change the "model" of a Mesh, you can access its .geometry property, and assign it a new one:
// This is the original geometry
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(100, 230, 15);
// Here we assign a new geometry to the Mesh
mesh.geometry = someOtherGeometry;

Related

Creating BoxBufferGeometry from Box3

I want to create a box mesh on the three.js scene, where points of the box mesh will be the same as bounding box of some existing object on the scene.
I have tried to create box mesh from box3 in the way displayed bellow, but i dont get the right result:
var threeObject = existing object on the scene;
var boundingBox = new THREE.Box3();
boundingBox.setFromObject(threeObject);
var geometry = new THREE.BufferGeometry();
var vertices = new Float32Array( [
boundingBox.min.x, boundingBox.min.y, boundingBox.min.z,
boundingBox.min.x, boundingBox.max.y, boundingBox.min.z,
boundingBox.min.x, boundingBox.min.y, boundingBox.max.z,
boundingBox.min.x, boundingBox.max.y, boundingBox.max.z,
boundingBox.max.x, boundingBox.min.y, boundingBox.min.z,
boundingBox.max.x, boundingBox.max.y, boundingBox.min.z,
boundingBox.max.x, boundingBox.min.y, boundingBox.max.z,
boundingBox.max.x, boundingBox.max.y, boundingBox.max.z,
] );
geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
var material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
var mesh = new THREE.Mesh( geometry, material );
viewer.scene.add(mesh);
How can I create mesh box from box3? Thank you very much for your help!
In Three.js there's no automatic way to turn Box3 into a regular BoxBufferGeometry but here's how it worked for me
const threeObject = existing object on the scene;
const box3 = new THREE.Box3();
// conform to the object size like it's a boundingBox
box3.setFromObject(threeObject);
// make a BoxBufferGeometry of the same size as Box3
const dimensions = new THREE.Vector3().subVectors( box3.max, box3.min );
const boxGeo = new THREE.BoxBufferGeometry(dimensions.x, dimensions.y, dimensions.z);
// move new mesh center so it's aligned with the original object
const matrix = new THREE.Matrix4().setPosition(dimensions.addVectors(box3.min, box3.max).multiplyScalar( 0.5 ));
boxGeo.applyMatrix(matrix);
// make a mesh
const mesh = new THREE.Mesh(boxGeo, new THREE.MeshBasicMaterial( { color: 0xffcc55 } ));
The vertices array in your code holds vertex data but they actually represent face/triangle definitions. Hence, rendering just this geometry data results in a few random triangles (not visualizing a box).
You can solve this problem by adding an index to your geometry which will represent the face definitions based on your vertices. To understand this topic, you have to know the difference between indexed and non-indexed geometries. I suggest you study the official documentation page of THREE.BufferGeometry. There are for each type of geometry official code examples.
three.js R107

Three.js: How to match EdgesHelper to Mesh

In a scene I have added several mesh objects (cubes). An EdgeHelper has been made for each cube. The cubes move and rotate and the Edgehelpers move and rotate with them.
I would like to change the color of an EdgeHelper when it's associated cube mesh is selected. (The selection method is not important).
So, given a particular cube mesh, how do I find the associated EdgeHelper object?
When you create an edgesHelper for a given mesh, all you have to do is add a new property to the mesh:
var mesh = new THREE.Mesh( ... );
var edgesHelper = new THREE.EdgesHelper( mesh );
mesh.edgesHelper = edgesHelper;
Now you can change the helper color like so:
mesh.edgesHelper.material.color.set( 0xff0000 );
three.js r.76
When you create meshes and EdgeHelpers you can assign them the same .name attribute:
mesh0.name = 0;
edgeHelper0.name = 0;
mesh1.name = 1;
edgeHelper1.name = 1;
...and so on
**if you wrap this in a loop even better
so when a mesh is selected you can read its .nameattribute and pick the corresponding edgeHelper.

ThreeJS assign array materials

If I assign framemat to createScene(ID,geometry,1,framemat) it works OK, if I do createScene( ID, geometry, 1, materials[ID] ) it doesn't work.
var jsonLoader = new THREE.JSONLoader(),
paths = [
"obj/jgd/GALD-JGD-frame.json",
"obj/jgd/GALD-JGD-logo.json",
"obj/jgd/GALD-JGD-light.json"
],
materials = [
"framemat",
"logomat",
"lightmat"
],
objNum = paths.length; // Cache obects.length
for ( var id = 0; id < paths.length; id++ ) {
(function(){ // IIFE start
jsonLoader.load( paths[id], function( geometry, materials ) {
createScene( id, geometry, 1, materials[id] )
}
);
})(); // IIFE end
}
CreateScene fun here:
function createScene( id, geometry, scale, material ) {
geometry.computeTangents();
objects[id]= new THREE.Mesh( geometry, material );
objects[id].scale.x = objects[id].scale.y = objects[id].scale.z = scale;
scene.add( objects[id] );
}
Your code is ambiguous : first you define an array called materials then you use the second argument of the JSONLoader and also name it materials to catch the textures in the json file, finally you use materials[id] to pass the material at the mesh creation. Which one is it ? Whereas the first array is still filled with strings, the json can have an array of materials instead of only one, worse of all the rank [id] may not exist in this one.
So you have two solutions :
If you want to create the materials independently, only keep the first array and add the missing function that transforms your strings to materials. Just remove the second argument of the JSONLoader.
If you want to use the material provided in the JSON File, the array materials is useless and can lead to other mistakes. There are two options then :
if you have one material for the whole object, write it this way : createScene(...,..., materials);
if you have several materials for the object, this way : createScene(....,....,new THREE.MeshFaceMaterial(materials);

intersectObjects not returning obj from OBJMTLLoader

I have a object that I'm adding into my scene. I also have various other cubes in the scene. I'm using the following code to fire a Ray and see if I can detect a collision:
var ray = new THREE.Raycaster(camera.position, vec);
var intersects = ray.intersectObjects( scene.children );
For some reason, the regular shapes (cubes) are detected, but the objects that loaded from the obj files are not.
var loader = new THREE.OBJMTLLoader();
loader.load( 'models/technicalTable1.obj', 'models/technicalTable1.mtl', function ( obj ) {
obj.scale.set(0.4, 0.4, 0.4);
obj.position.x = - roomWidth/2 + 100;
obj.position.y = 36;
obj.position.z = - roomLength/2 + 25;
scene.add( obj );
}, onProgress, onError );
Thanks for any help!
You need to pass the recursive flag to Raycaster.intersectObjects().
var intersects = ray.intersectObjects( scene.children, true );
three.js r.70
It doesnt work because the OBJMTLLoader creates a Three.Group
The Group does not have a raycaster.intersectObjects
(I just finished tracing it down and it went to a non implemented function
This REALLY limits the the use of OBJ objects.
I have tried JSON but since you can not load materials and have to create UVmap I find that I need a person that can 3D model or not be able to use the intersectObjects.
Not sure if this is a bug

How can I set the position of a mesh before I add it to the scene in three.js

In three.js, I want to add a mesh to a position in the scene
I've tried:
// mesh is an instance of THREE.Mesh
// scene is an instance of THREE.Scene
scene.add(mesh)
scene.updateMatrixWorld(true)
mesh.matrixWorld.setPosition(new THREE.Vector3(100, 100, 100))
scene.updateMatrix()
BUT it didn't affect anything.
What should I do ?
I would recommend you to check the documentation over here:
http://threejs.org/docs/#Reference/Objects/Mesh
As you can see on the top of the docu-page, Mesh inherits from "Object3D". That means that you can use all methods or properties that are provided by Object3D. So click on the "Object3D" link on the docu-page and check the properties list. You will find the property ".position". Click on ".position" to see what data-type it is. Paha..its Vector3.
So try to do the following:
// scene is an instance of THREE.Scene
scene.add(mesh);
mesh.position.set(100, 100, 100);
i saw it on a github earlier. (three.js r71 )
mesh.position.set(100, 100, 100);
and can be done for individuals
mesh.position.setX(200);
mesh.position.setZ(200);
reference: https://threejs.org/docs/#api/math/Vector3
detailed explanation is below:
since mesh.position is "Vector3". Vector3() has setX() setY() and setZ() methods. we can use it like this.
mesh.position = new THREE.Vector3() ; //see position is Vector3()
vector1 = new THREE.Vector3();
mesh.position.setX(100); //or this
vector1.setX(100) // because all of them is Vector3()
camera1.position.setZ(100); // or this
light1.position.setY(100) // applicable to any object.position
I prefer to use Vector3 to set position.
let group = new THREE.Group();
// position of box
let vector = new THREE.Vector3(10, 10, 10);
// add wooden Box
let woodenBox = new THREE.Mesh(boxGeometry, woodMaterial);
//update postion
woodenBox.position.copy(vector);
// add to scene
group.add(woodenBox)
this.scene.add(group);
If some one looking for way to update position from Vector3
const V3 = new THREE.Vector3(0,0,0) // Create variable in zero position
const box = new THREE.Mesh(geometry, material) // Create an object
Object.assign(box.position, V3) // Put the object in zero position
OR
const V3 = new THREE.Vector3(0,0,0) // Create variable in zero position
const box = new THREE.Mesh(geometry, material) // Create an object
box.position.copy(V3)

Categories

Resources