How to update material of cube on runtime using WebGL? - javascript

I'm using three.js for doing animations. I want to dynamically update a material of a cube mesh. Here is example:
// create cube geometry
var material1 = [new THREE.MeshBasicMaterial({color:0xBEE2FF}),.....];
var geometry = new THREE.CubeGeometry(50, 50, 50,0,0,0,material1 );
var cube = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial());
// ...
var material2 = [new THREE.MeshBasicMaterial({color:0xFFFFFF}), ...];
cube.geometry.materials = material2;
If I use CanvasRenderer, it works. But when I change to WebGL Renderer, it throws error: Uncaught TypeError: Cannot read property 'map' of undefined
How to update the material of a cube on runtime using WebGL?

With a code fragment, it is difficult to know what is causing the error, but you cannot change materials that involve the presence or not of a texture. Try keeping all of your materials of the same type. Also, you may need to set material.needsUpdate flag to true.
You can find more detail and examples in the Three.js wiki about how to update things with WebGLRenderer.
https://github.com/mrdoob/three.js/wiki/Updates
Also, here is a fiddle that does something similar to what you appear to be trying to do: http://jsfiddle.net/2FZU7/51/
EDIT: fiddle updated for three.js r.58

I think the issue is that you're setting 'materials' and not 'material' on your cube.
cube.material = material2;
material.map = texture;
material.needsUpdate = true;

Related

Imported JSON geometry not moving with bones

I have imported a model into my Three.js scene. I am able to move and rotate the bones but the model's geometry does not move with the bones.
Here is the code I have used to import the JSON file and add it to the scene,
/*load JSON file*/
// instantiate a loader
var loader = new THREE.JSONLoader();
loader.load( 'https://cdn.rawgit.com/wpdildine/wpdildine.github.com/master/models/cylinder.json', addModel );
var helpset;
var scaleVal = 3;
function addModel( geometry, materials ){
materials.skinning = true;
var cs = scaleVal * Math.random();
mesh = new THREE.SkinnedMesh( geometry, new THREE.MeshFaceMaterial(materials) );
scene.add(mesh);
helpset = new THREE.SkeletonHelper(mesh);
scene.add(helpset);
}
The JSON file that I have imported includes weights so I did not think I had to add them myself. Would it be anything to do with binding the skeleton to the mesh?
Here is a link to my code - https://jsfiddle.net/joeob61k/1/ (New link with scripts, thanks #Mr. Polywhirl)
As you can see, 'Bone_2' in the GUI controls moves one of the bones but not the mesh.
EDIT: I have tried accessing the bones of the mesh in the render() function. I have done so by using the following line of code,
mesh.skeleton.bones[2].rotation = 0.1;
I get the following error: 'Cannot read property 'skeleton' of undefined(…)' were undefined is the mesh variable. Is there a new way of accessing the bones of a SkinnedMesh that I need to use?
The problem was with the line,
materials.skinning = true;
It needs to be the following to work,
materials[0].skinning = true;

Accessing multiple objs using .getObjectById() with JSONLoader in Three.js

Is it possible to differentiate between the meshes within one .js file exported from blender and animate them separately using Three.js?
The cube I would like to select is named "Cube" loads properly. However, when I try to get it by Name or Id, it doesn't recognize the var item1.
loader = new THREE.JSONLoader();
loader.load('engine.js', function (geometry, materials) {
var mesh, material;
material = new THREE.MeshFaceMaterial(materials);
mesh = new THREE.Mesh(geometry, material);
mesh.scale.set(1, 1, 1);
var item1 = scene.getObjectByName("Cube");
item1.position.x = 15;
scene.add(mesh);
});
I found this post but it seems unresolved: Three.js load multiple separated objects / JSONLoader
What is the best approach to loading multiple meshes via JSONLoader? I'd prefer to load them together as one .js file and just select the ones I would like to animate.
Thanks for your help!
In your blender scene you need to name every mesh you want to access independently in three.js. Then you can use Object3D.getObjectByName() to access your mesh in three.js.
Yes, it is possible to load an entire scene with several meshes from a json file exported from Blender!
You can see the complete process described on my answer of the cited post
So, you can differentiate between the meshes using the getObjectByName method and manipulate them separately. But it is important to know that the loaded object isn't a Geometry anymore. It is labeled with the Scene type by now and it must be handled in a different way.
You must change the loading code for one like this:
loader = new THREE.JSONLoader();
loader.load( "obj/Books.json", function ( loadedObj ) {
var surface = loadedObj.getObjectByName("Surface");
var outline = loadedObj.getObjectByName("Outline");
var mask = loadedObj.getObjectByName("Mask");
mask.scale.set(0.9, 0.9, 0.9);
scene.add(surface);
scene.add(outline);
scene.add(mask);
} );
In the above code we can indeed animate the surface, outline and mask meshes independently.

Three.js texture on material

I'd like to apply a custom image texture (.bmp or .jpg) on a material loaded from Blender and used in my project via the JSONLoader method.
There is no bug but the render of the material with the texture is bad looking.
You can see it here: http://image.noelshack.com/fichiers/2014/18/1399215240-stack.png
I'd like to get rid of these "rays" on my material. Here is the code I use to load my material/texture:
var texture = THREE.ImageUtils.loadTexture('/Game/models/textures/black.jpg');
var currentMaterial = new THREE.MeshBasicMaterial({ map: texture });
var currentModel = new THREE.Mesh(geometry, currentMaterial);
The "geometry" variable is the result of the callback of the JSONLoader.Load method.
I'd like to know if the problem comes from the image texture or from the code. And what is the best way to load a material created in Blender and exported as a JS file and loaded with the JSONLoader. I'm not sure if I use the best method when I use the "THREE.MeshBasicMaterial" constructor.
Thanks

Three.js skinned animation mesh disappears when material skinning is true

I've exported an animated model from Blender which doesn't seem to have any issue instantiating. I'm able to create the THREE.Animation and model, but I was finding there was no animation. I realized I needed to set skinning true on each material, but when I do that the entire mesh goes missing.
Below is my (quick and messy) code trying to get everything to work.
function loadModel() {
var loader = new THREE.JSONLoader();
loader.load('assets/models/Robot.js', function(geom, mat) {
_mesh = new THREE.Object3D();
_scene.add(_mesh);
geom.computeBoundingBox();
ensureLoop(geom.animation);
THREE.AnimationHandler.add(geom.animation);
for (var i = 0; i < mat.length; i++) {
var m = mat[i];
//m.skinning = true; <-- Uncommenting this makes the model disappear
//m.morphTargets = true; <-- This causes all sorts of WebGL warnings
m.wrapAround = true;
}
var mesh = new THREE.SkinnedMesh(geom, new THREE.MeshFaceMaterial(mat));
mesh.scale.set(400, 400, 400);
mesh.position.set(0, -200, 0);
mesh.rotation.set(Utils.toRadians(-90), 0, 0);
_mesh.add(mesh);
_robot = mesh;
Render.startRender(loop);
var animation = new THREE.Animation(mesh, geom.animation.name);
animation.JITCompile = false;
animation.interpolationType = THREE.AnimationHandler.LINEAR;
animation.play();
});
}
I believe I'm updating the AnimationHandler correctly in my loop
function loop() {
_mesh.rotation.y += 0.01;
var delta = 0.75 * _clock.getDelta();
THREE.AnimationHandler.update(delta);
}
In the section metadata of the exported JSON file the number of morphTargets and bones are both greater than 0?
I think that you followed the example here:
http://threejs.org/examples/#webgl_animation_skinning_morph
in which the animated model uses Morph Target and Skeletal Animation (see Wikipedia for the theoretical concepts).
If the animated model uses only Skeletal Animation as in this example http://alteredqualia.com/three/examples/webgl_animation_skinning_tf2.html
you have to instantiate a THREE.SkinnedMesh Object and then set only the m.skinning property to true.
I was having the same problem just now. What worked for me was to remake the model with applied scale and have keyframes for LocRotScale, not just location.
lately, I've encoutered a similar issue of mesh disapearing while exporting blender skinning animation to json. It turned out, the mesh I was using had double vertex (one vertice hidding another). All looks good While creating the vertex groups and the animations in blender, but when I imported the mesh via three.js, it kept disapearing as soon as the animation started. In other words, If 1 vertice from your mesh is omitted from the vertex groups, you will experience this disapearing behavior. To prevent this issue, I now use the "remove doubles" function from blender to validate the mesh integrity before exporting it to json. You might have encountered the same issue and redoing your mesh work fix it... Anyways, the question is pretty old, but the topic is still valid as of today, so I hope this fresh info will help someone out there...
Peace INF1

Is it a Three.js bug with collada loader?

There is a three.js demo here: http://mrdoob.github.com/three.js/examples/webgl_loader_collada.html
It works perfectly, but if I want to use canvas renderer instead of webgl, it's buggy.
renderer = new THREE.CanvasRenderer();
I can't see the texture (the object is white), and the animation also doesn't works. Is it a bug in three.js, or I have to modify more in the code?
Thanks in advance
CanvasRenderer has several limitations. See Issue 1026.
Default skin material is an instance of THREE.MeshLambertMaterial, but you can do a quick overwrite with a THREE.MeshBasicMaterial instance with the original texture map:
...
skin = collada.skins[ 0 ];
skin.material = new THREE.MeshBasicMaterial({map: skin.material.map});
...
And AFAIK CanvasRenderer doesn't support morph targets (animation).

Categories

Resources