How to access loaded model with objectLoader - three.js

I am trying to load an external model using ObjectLoader. I am using the following code
loader.load( 'teapot.obj', function ( object ) {
globalobject=object;
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material.map = texture;
console.log(child);
child.position.x = 3;
child.position.y = -6;
child.position.z = -17;
child.scale.x=.04;
child.scale.y=.04;
child.scale.z=.04;
child.name='tea';
scene.add( child );
}
});
But when I try to access this object in my render method using the following code it shows error
scene.getObjectByName('tea').rotation.z+=.01;
I saw using console that scene.getObjectByName('tea') is undefined
I can use all other standard Mesh objects using the above command but what is the problem with my object loaded using loader?
Can anyone help me to get the way?

If you have multiple childs in one obj file then append some number to differentiate between multiple mesh.
Then this should work:
scene.getObjectByName( "objectName" );
This answer may help

Related

THREE.WebGLProgram Shader Error because of defined v1 constant

I am using Three.js and I am loading an HDR as an environment map for the scene. Upon loading, I receive this error:
The line in questions is this:
I am assuming that the defined v1 causes an issue in this line because it is not undefined.
I am loading the HDR map like this:
return new Promise((resolve, reject) => {
new RGBELoader()
.setDataType(THREE.HalfFloatType)
.load(
path, // <-- hdr file
(texture) => {
// I tried fromEquirectangular and fromCubemap
// const envMap = this.pmremGenerator.fromEquirectangular(texture).texture;
const envMap = this.pmremGenerator.fromCubemap(texture).texture;
texture.needsUpdate = true;
resolve({ envMap });
},
undefined,
reject
);
});
Does anyone know what is causing this issue in THREE?
const envMap = this.pmremGenerator.fromCubemap(texture).texture;
I doubt this method call is correct. RGBELoader can not load textures in the cube map format. You probably want to use fromEquirectangular(). Before using this method, you need this line in your onLoad() callback:
texture.mapping = THREE.EquirectangularReflectionMapping;
Besides, please check if the usage of PMREMGenerator is actually necessary in your app. In latest releases, three.js internally uses PMREMGenerator to prepare environment maps for the usage with PBR materials.

The function "getRenderProxy" to get a ThreeJS Mesh from an object's fragId in Forge Viewer doesn't work correctly

I'm trying to get a threeJS Mesh from Autodek Forge objects using the function
'viewer.impl.getRenderProxy(viewer.model, fragId)'.
The problem that I encounter is if I put this function in a loop routine to get Meshs of multiple objects, I get just a random Mesh.
To find out the problem's origin, I used a similar function that is :
'viewer.impl.getFragmentProxy(viewer.model, fragId)'
and it worked just fine.
Her is the routine code that I use and the result :
for(let i = 0, len = nodNamee.length; i < (len); i = i+3){
var instanceTree = viewer.model.getData().instanceTree;
var fragIds = [];
instanceTree.enumNodeFragments(nodNamee[i+1], function(fragId){
fragIds.push(fragId);
});
fragIds.forEach(function(fragId) {
var renderProxy = viewer.impl.getRenderProxy(viewer.model, fragId);
fragtoMesh.push(renderProxy);
//var fragmentproxy = viewer.impl.getFragmentProxy(viewer.model, fragId);
//fragtoProxy.push(fragmentproxy);
});
}
Result :
Arry of fragtoMesh
This is because the getFragmentProxy method always returns the same instance of THREE.Mesh, just with different properties. Basically, the method works like this under the hood:
let cachedMesh = new THREE.Mesh();
// ...
getRenderProxy(model, fragId) {
// Find the geometry, material, and other properties of the fragment
cachedMesh.geometry = fragGeometry;
cachedMesh.material = fragMaterial;
// ...
return cachedMesh;
}
// ...
Note that this is a performance optimization because if the getFragmentProxy (which is only meant for internal use) function returned a new instance every time it's called by other parts of Forge Viewer, it would cause a huge memory churn.
So in your case, if you really need to store all the THREE.Mesh instances in an array, you'll need to clone them or copy their individual properties into separate THREE.Mesh objects.

Why is this Threejs cloned Group loaded via GLTFLoader misbehaving?

So I am trying to clone the soldier model from the Three.js examples, because I want more than one later:
https://threejs.org/examples/webgl_animation_skinning_blending.html
I changed line 93 to read:
const loader = new GLTFLoader();
loader.load( 'https://threejs.org/examples/models/gltf/Soldier.glb', function ( gltf ) {
model = gltf.scene.clone();
scene.add( model );
model.traverse( function ( object ) {
if ( object.isMesh ) object.castShadow = true;
} );
But now the soldier is huge.
Why is this happening and is there a fix for it?
Here is a jsfiddle showing the problem:
https://jsfiddle.net/paranoidray/jLpzk374/22/
If you check out the jsfiddle and change line 93 and remove the clone() call.
Everything works again...
Any help would be very much appreciated.
Please clone gltf.scene like so:
model = SkeletonUtils.clone( gltf.scene );
Cloning of skinned meshes is not yet supported in the core. However, you can use SkeletonUtils.clone() to perform this task.
https://jsfiddle.net/yesxrq7g/

THREE AnimationMixer.clipAction() throws cannot parse trackname at all

I am trying to load some simple keyframe animation (just positions) using the JSON loader.
Using the dev branch r80.
To load the entire scene (made and animated in softimage, exported to FBX, imported into blender, exported using the THREE JSON export script). The file looks good and loads ok.
But when i try to load the animation using:
object.traverse( function ( child ) {
switch(child.name) {
case "dae_scene:helium_balloon_model:helium_balloon_model":
//do anim
console.log(object.animations[0]);
animationClips.balloon1 = object.animations[0]; //
//animationClips.balloon1.weight = 1;
animationMixer = new THREE.AnimationMixer( child );
var sceneAnimation = animationMixer.clipAction(animationClips.balloon1);
sceneAnimation.play();
break;
}
}
it produces:
three.min.js?ver=4.5.4:712 Uncaught Error: cannot parse trackName at all: dae_scene:helium_balloon_model:helium_balloon_model.position
Anyone who can point me in the right direction?

Make a instance of the Object returned by the THEE.js OBJMTLLoader

I'm deply sory about ask this question again here. I know that the members os Stack Overflow are not for my exclusive
use but a realy need to find a solution to this problem.
Let me explain better because last time I was not that clear about what I wanted.
Iam using the THREE.JS to develop a RPG like game. What I have in mind is a game just like IronBane MMO but without
the web server function for now (just use for the single player).
I'm relative new to THREE.js and, in some point, I start to work in a library to handle the object loadings im
my level. Because I use the 3DStudio Max to make de models, I decide to use the OBJMTLLoader library provided.
I've nailed the function to load de static objects and its something like this.
function loadObject(obj,mtl,pos){ // Adiciona objeto sem vinculá-lo a uma variável
var loader = new THREE.OBJMTLLoader();
loader.load( obj, mtl, function ( object ) {
object.position.set(pos[0],pos[1],pos[2]);
scene.add( object );
});
}
The problem comes when I need to intance this object. I tried many things for example:
function addObject(obj,mtl){ // Declara e adiciona um objeto no mapa
var conteudo;
var loader = new THREE.OBJMTLLoader();
loader.load( obj,mtl, function( object ){
conteudo = object;
});
setTimeout(function(){
scene.add( conteudo );
},1000);
The conteudo variable came undefined of course. I understand then that I need to wait the object to load first. It
takes about 2 render cicles. For this I use then the setTimeout function. With the scene.add( conteudo ) the object
was sucessfuly added to the scene. I try then to use a
return conteudo;
and, when I call...
var objeto = new addObject('object path','material path')
I get a instance of addObject and not Object3D as I expected. I try also to declare a array outside de function and
push it from inside the addObject like this:
function addObject(obj,mtl,objectArray)
var loader = new THREE.OBJMTLLoader();
loader.load( obj,mtl, function( object ){
conteudo = object;
});
setTimeout(function(){
scene.add( conteudo );
objectArray.push( conteudo );
},1000);
In this second one when I console.log the array I get:
Array[1]
0 : THREE.Object3D
length : 1
but when I try to use Array[0] or console.log(Array.length) I get undefined and 0 respectivly.
I would realy appreciate if someone could help-me solve this one. That would be awesome. Thanks you!
consider waiting with adding the objects.
function init(next){
var loader = new THREE.OBJMTLLoader();
loader.load( obj, mtl, function ( object ) {
object.position.set(pos[0],pos[1],pos[2]);
conteudo = object;
next();
});
}
function next(){
scene.add( conteudo );
objectArray.push( conteudo );
console.log(objectArray)
... work from here, here you are sure that the model is loaded ...
}
init(next);
This waits until the object is loaded and then it will execute next.

Resources