Object color apply does not work? - three.js

I have loaded object in three js. When i apply the color it does not work.
I have below code used i got error in,
child.material.color is undefined
I have used below code
var geometry = new THREE.PlaneGeometry( 0.8, 1 );
var loader = new THREE.OBJLoader( manager );
loader.load( file, function ( object ) {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material.ambient.setHex(0xFF0000);
child.material.color.setHex(0x00FF00);
}
} );

I think child.material.color.setHex() is enough to apply/set the color of an object.
So try to remove the following line from your code.
child.material.ambient.setHex(0xFF0000);
Here is the working fiddle sample: http://jsfiddle.net/ev3tuLuc/109/

Related

A-Frame THREE.TextureLoader loading texture whice is looking whitewashed

I am updating an a-image scr using THREE.TextureLoader
let loader = new THREE.TextureLoader()
const imgload = loader.load(
'./test.png',
function ( texture ) {
firstFrameImage.getObject3D('mesh').material.map = texture
firstFrameImage.getObject3D('mesh').material.needsUpdate = true
},
// onProgress callback currently not supported
undefined,
// onError callback
function ( err ) {
console.error( 'An error happened.' );
}
)
Its updating the texture but its making the texture whitewashed. Can any one help?
Original image:
original
Updated texture coming as:
after update
Try to fix this by doing this:
texture.encoding = THREE.sRGBEncoding;
Color deviations like this mostly occur because of wrong color space definitions.

Loading multiple fbx

Trying to load multiple fbx in a function, i try different ways to do that in same function, separate functions, same loader, different loaders, etc. but nothing seems to work and the result is same it only loads the first .fbx.
This is the code that i have:
function loadModels(){
//model1
var loader1 = new THREE.FBXLoader();
loader1.load( 'models/model1.fbx', function ( model1 ) {
scene.add( model1 );
} );
//model2
var loader2 = new THREE.FBXLoader();
loader2.load( 'models/model2.fbx', function ( model2 ) {
scene.add( model2 );
} );
animate();
}
Had same issue. Fixed by replacing examples/js/loaders/FBXLoader.js to newer version from https://github.com/mrdoob/three.js/ (current revision 96)
Problem was that FBXLoader.js had exact same typing "FBXTree" for variable and function name

How to clone a Skinned Mesh?

I need to have multiple identical, animated models on a scene. If possible, I would like them to have a shared geometry and material, but if it is impossible, having them instanced per model will suffice too.
Unfortunately, the only way to achieve this result I found is to go through JSONLoader for every model instance.
SkinnedMesh does have a clone() method, but it seems not to be fully implemented yet. If used and both original and cloned mesh are present on the scene, only one will appear, and cloned one will be without animation.
I have attempted to use this example with shared skeletons:
https://github.com/mrdoob/three.js/pull/11666
...and indeed it works, but I need to be able to play different animations for every model instance, having them all play the same one is not sufficient, sadly. I hoped I could do similar hax and insert my own skeleton (made out of bones from the JSON file), but it behaves very much like if I just used clone() from SkinnedMesh.
I am using this code:
https://github.com/arturitu/threejs-animation-workflow/blob/master/js/main.js
Basically what I'd like to achieve is
var onLoad = function (geometry, materials) {
window.geometry = geometry;
character = new THREE.SkinnedMesh(
geometry,
new THREE.MeshFaceMaterial(materials)
);
character2 = character.someMagicalClone();
scene.add(character);
scene.add(character2);
(...)
I need any clue... and while I wait for help, I am busily deconstructing constructor for SkinnedMesh and JSONLoader for clues ;)
Thanks in advance!
I found a solution in this pull request:
https://github.com/mrdoob/three.js/pull/14494
in short, there are two functions added:
function cloneAnimated( source ) {
var cloneLookup = new Map();
var clone = source.clone();
parallelTraverse( source, clone, function ( sourceNode, clonedNode ) {
cloneLookup.set( sourceNode, clonedNode );
} );
source.traverse( function ( sourceMesh ) {
if ( ! sourceMesh.isSkinnedMesh ) return;
var sourceBones = sourceMesh.skeleton.bones;
var clonedMesh = cloneLookup.get( sourceMesh );
clonedMesh.skeleton = sourceMesh.skeleton.clone();
clonedMesh.skeleton.bones = sourceBones.map( function ( sourceBone ) {
if ( ! cloneLookup.has( sourceBone ) ) {
throw new Error( 'THREE.AnimationUtils: Required bones are not descendants of the given object.' );
}
return cloneLookup.get( sourceBone );
} );
clonedMesh.bind( clonedMesh.skeleton, sourceMesh.bindMatrix );
} );
return clone;
}
function parallelTraverse( a, b, callback ) {
callback( a, b );
for ( var i = 0; i < a.children.length; i ++ ) {
parallelTraverse( a.children[ i ], b.children[ i ], callback );
}
}
As I understand it rebinds cloned skeleton to the cloned mesh.
so topic example could look like:
var onLoad = function (geometry, materials) {
window.geometry = geometry;
character = new THREE.SkinnedMesh(
geometry,
new THREE.MeshFaceMaterial(materials)
);
character2 = cloneAnimated(character); // <-- used that new function
scene.add(character);
scene.add(character2);
(...)

get back to normal after the traverse in threejs

in threejs am working around with the traverse method to apply the WireframeHelper for the models that is loaded using OBJMTLLoder, for this kind of models we must use traverse to apply the Wireframe for child of the Object, so here i can apply the wireframes and so on using traverse but after the traverse i can't get back to my normal object meaning that i can't remove the wireframes with the traversed mesh, the mesh is added with the scene with scene.add( wfh ); where wfh is WireframeHelper , but if i use scene.remove( wfh ); to remove the meshed WireframeHelper it doesn't work
i need to know that after the traverse we can get back to normal ?? in most cases am using traverse to make changes on my model:
Here is the code:
scene.traverse ( function (child)
{
if (child instanceof THREE.Mesh)
{
wfh = new THREE.WireframeHelper( child, 0xffffff );
scene.add( wfh );
}
});
updated code:
globalObject.traverse ( function (child) {
if (child instanceof THREE.Mesh)
{
wfh = new THREE.WireframeHelper( child,whfcolor );
wfh.name = "wireframe_helper";
wfh.material.opacity = 0.2;
wfh.material.transparent = true;
globalObject.add( wfh );
}
});
here globalObject is global variable assigned to Object now i can see the wireframe_helper on the child of the Object and can remove the wireframe by following code
globalObject.traverse( function ( child ) {
if (child instanceof THREE.Object3D)
{
//alert(child.name);
if ( child.name && child.name === "wireframe_helper" && child.material ) {
//alert('hi');male-02-1noCullingID_male-02-1noCulling.JP
globalObject.remove( child );
//child.material.wireframe = true;
}
}
});
after removed the wireframe still wireframe is remains some part of the Object any clue on this ?? and am getting
TypeError: this.children[i] is undefined
this.children[ i ].traverse( callback );
on line three.js 7885
WireframeHelper() creates an object that is added to the scene-graph. When you are using the helper inside a traverse() operation you are adding many objects to the scene. So if you want to remove them, you have to save them off to a variable (array in this case since you have many of them). So something like this should work:
First name the helper inside the first traverse():
wfh = new ...
wfh.name = "wireframe_helper";
scene.add( wfh );
then you should be able to do:
scene.traverse ( function (child)
{
if (child.name === "wireframe_helper")
{
scene.remove( child );
}
}
The code above would probably crash when trying to traverse a child that has been removed.
Here is updated code:
to_remove = [];
scene.traverse ( function (child)
{
if (child.name === "wireframe_helper")
to_remove.push( child );
}
for (var i = 0; i < to_remove.length(); i++)
scene.remove( to_remove[i] );

WebGLRenderingContext ERROR loading texture maps

First of all, thank you for this wonderfull work, i'm having a lot of fun working with three.js.
I tried to find answer about a recurent issue, .WebGLRenderingContext: GL ERROR :GL_INVALID_OPERATION : glDrawElements: attempt to access out of range vertices in attribute 2
I'm making a website in webgl, i spend few week understanding all about three.js but i can't fix this issue.
I get this message on Chrome and firefox (latest) each time i try to load a canvas into a map, bumpmap and specmap.
All my mesh are loaded from obj files, by the way i rewrote OBJMTLLoader.js to be able to load more parameters from obj files and more.
here the code used to load image.
THREE.MTLLoader.loadTexture = function ( url, mapping, onLoad, onError ) {
var isCompressed = url.toLowerCase().endsWith( ".dds" );
var texture = null;
if ( isCompressed ) {
texture = THREE.ImageUtils.loadCompressedTexture( url, mapping, onLoad, onError );
} else {
var image = new Image();
texture = new THREE.Texture( image, mapping );
var loader = new THREE.ImageLoader();
loader.addEventListener( 'load', function ( event ) {
texture.image = THREE.MTLLoader.ensurePowerOfTwo_( event.content );
texture.needsUpdate = true;
if ( onLoad )
onLoad( texture );
} );
loader.addEventListener( 'error', function ( event ) {
if ( onError ) onError( event.message );
} );
loader.crossOrigin = this.crossOrigin;
loader.load( url, image );
}
return texture;
};
I'm pretty sure it is from this, because when i disable this function, no more warning.
Is it because the mesh has a texture with an empty image while loading datas ?
Is there any restriction on the dimensions of image ?
For now everything works fines, but i feel strange having those message in console.
Thanks
This error become because the Three.js buffers are outdated. When your add some textures (map,bumpMap ...) to a Mesh, you must recompose the buffers like this :
ob is THREE.Mesh, mt is a Material, tex is a texture.
tex.needsUpdate = true;
mt.map = tex;
ob.material = mt;
ob.geometry.buffersNeedUpdate = true;
ob.geometry.uvsNeedUpdate = true;
mt.needsUpdate = true;
That's all folks !
Hope it's help.
Regards.
Sayris

Resources