Rendering single mesh color change - javascript

I have a grid that contains boxes, very similar to http://threejs.org/examples/#canvas_interactive_voxelpainter. Now I initiated a hover state when a box on the scene is mouseover it turns the background gray. Which is great! Except when I multiple "box" on the grid and I go to change the material background color of the hovered item, it renders all of the "box's" with a gray background.
Heres what I am doing:
var voxel = new THREE.Mesh( this.cubeGeometry, this.cubeMaterial );
voxel.position.copy( intersect.point ).add( intersect.face.normal );
voxel.position.divideScalar( 50 ).floor().multiplyScalar( 50 ).addScalar( 25 );
this.scene.add( voxel );
this.blocks.push( voxel );
var domEvents = new THREEx.DomEvents(this.camera, this.renderer.domElement)
// DOM events for inside 3d rendering
domEvents.addEventListener(voxel, 'mouseover', this.onDocumentMouseOverCube.bind(this),false);
domEvents.addEventListener(voxel, 'mouseout', this.onDocumentMouseOutCube.bind(this),false);
Here we create our box - we than give it eventListeners for that specific mesh. Once this mesh is hovered over, our mouseover is executed:
this.mouse.x = ( event.origDomEvent.clientX / this.renderer.domElement.width ) * 2 - 1;
this.mouse.y = - ( event.origDomEvent.clientY / this.renderer.domElement.height ) * 2 + 1;
this.raycaster.setFromCamera( this.mouse, this.camera );
var intersects = this.raycaster.intersectObjects( this.blocks );
if ( intersects.length > 0 ) {
var intersect = intersects[ 0 ];
if ( intersect.object != this.plane ) {
console.log(intersect.object);
// update color on hover
intersect.object.material.color.setHex(this.colorHover);
console.log("hover color");
this.render();
}
}
Now this works great, the only issue is - this.render() is called (this.renderer.render( this.scene, this.camera )) like it should be. But when I have multiple box's on it goes ahead and changes every single background color of each box I have even logged all my objects to confirm object.material.color is the gray hex for only one box and that not all of the box's are being set, which proves to be true. I am sending the correct data over. So I am assuming it has to do with the rendering of the actual engine?
Suggestions?

There is only one instance of the material, which is shared among the meshes. The easy solution is to clone the material for each mesh:
var voxel = new THREE.Mesh( this.cubeGeometry, this.cubeMaterial.clone() );
Now every box accepts its own color.
I dont know if this still applies but thinking about performance you would want to go with a custom shader material, because the attributes and vertex/fragment programs are copied by reference then. See this post Three.js, sharing ShaderMaterial between meshes but with different uniform sets.
Example code:
var phongShader = THREE.ShaderLib.phong;
this.shaderMaterial = new THREE.ShaderMaterial({
uniforms: phongShader.uniforms,
vertexShader: phongShader.vertexShader,
fragmentShader: phongShader.fragmentShader,
lights:true
});
var voxel = new THREE.Mesh( this.cubeGeometry, this.shaderMaterial.clone() );
And then you change the color via uniforms like so:
intersect.object.material.uniforms.diffuse.value.setHex( this.colorHover );
Three.js r.71
PS: cloning the default Phong material in r.71 also shows only one programm in the renderer info for me, so maybe Three.js is optimizing this internally.

Related

How to change the position of a vertex of a given threejs.Box3?

My aim here is to create a box, then change one of its vertex's position through geometry, and then display it.
var anchor = new THREE.Vector3( 300, 300, 3 );
var cursor = new THREE.Vector3( 500, 550, 50 );
var box2 = new THREE.Box3( anchor, cursor );
var box2Helper = new THREE.Box3Helper( box2 );
box2Helper.geometry.vetices[0] = new THREE.Vector3( 20, 20, 20 );
box2Helper.geometry.verticesNeedUpdate = true;
scene.add( box2Helper );
This code works fine without those two geometry lines.
What is the way to change the position of the existing vertexes of the box through geometry class?
I think there may be some confusion here about what the Box3 class is... It's just a 3d boundingbox.. To make a deformable box with vertices, you want a new THREE.Mesh(new THREE.BoxGeometry(1,1,1), new THREE.MeshStandardMaterial() )
then you can modify the mesh.geometry.vertices like you are doing..
THREE.Box3 is more of a utility class used to represent bounding boxes of things.. it's used for frustum culling and stuff.

Three.js - Why shadow only show in a small area

I imported a model and found that shadow only show in a small area(green area in the picture). What can I do to let all objects show their shadow.
Here is my code.
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 1, 1, 1 );
light.castShadow = true;
light.shadow.camera.near = 0.01; // same as the camera
light.shadow.camera.far = 1000; // same as the camera
light.shadow.camera.fov = 50; // same as the camera
light.shadow.mapSize.width = 2048;
light.shadow.mapSize.height = 2048;
scene.add( light );
Thanks!!
EDIT:
I add gui to change light.shadow.camera.top / light.shadow.camera.bottom / light.shadow.camera.left / light.shadow.camera.right, but nothing happens.
var gui = new dat.GUI();
gui.add( light.shadow.camera, 'top' ).min( 1 ).max( 100000 ).onChange( function ( value ) {
light.shadow.camera.bottom = -value;
light.shadow.camera.left = value;
light.shadow.camera.right = -value;
});
That's happening because directional lights use an OrthographicCamera to draw a shadowmap to cast shadows. If there are objects outside the view of this camera, it won't be able to calculate their shadows, and will have the effect you're seeing outside the green box. If you want to extend the area that this camera covers, you can modify the .left .right .top .bottom properties of this shadow camera to cover your entire scene. I'm using a box of 100 units in the example below;
var side = 100;
light.shadow.camera.top = side;
light.shadow.camera.bottom = -side;
light.shadow.camera.left = side;
light.shadow.camera.right = -side;
... but you can change the dimensions to whatever you need. Keep in mind that .fov does nothing in your example code because ortho cameras don't use the field-of-view property.
All right, it would be great if you could show me a live example of your code as I have fixed this before for a project in boxelizer.com
The issue can be fixed by changing the light.shadow.camera.left, right, bottom and top properties as suggested before, however we might not be able to see what the effective area of our shadow might be and hence we might be really close to fixing it but not at all. My suggestion is using a helper momentarily just to see the effective shadow area of your light with:
var shadowHelper = new THREE.CameraHelper( light.shadow.camera );
scene.add( shadowHelper );
You are also welcome to see all the code I used in the link I referenced to.
Here's a function I use to set the shadowMap dimensions and coverage area:
//sz is the size in world units that the shadow should cover. (area)
// mapSize is the width,height of the texture to be used for shadowmap (resolution)
var setShadowSize=(light1, sz, mapSz)=>{
light1.shadow.camera.left = sz;
light1.shadow.camera.bottom = sz;
light1.shadow.camera.right = -sz;
light1.shadow.camera.top = -sz;
if(mapSz){
light1.shadow.mapSize.set(mapSz,mapSz)
}
}
setShadowSize(myLight,15.0,1024);

Threejs IcosahedronGeometry vertex color

I am trying to change color of a selected vertex dynamically. Referring to https://jsfiddle.net/pmankar/m70cpxes/, I created a IcosahedronGeometry point cloud geometry and on click event I would like to change the color of vertex 100.
document.addEventListener('click', function() {
mesh.geometry.colorsNeedUpdate = true;
mesh.geometry.colors[100] = new THREE.Color("rgb(255,0,0)");
console.log(mesh.geometry);
})
Now, I have two questions:
How to make the vertex 100 change its colors
Why is it showing random color to the point cloud
You declared var material, then created materail = new THREE.PointsMaterial(); and then applied material again to your mesh. There's a typo: material != materail.
Also, to have different colors of vertices you have to set colors of them
geometry = new THREE.IcosahedronGeometry(102, detailsLevel);
var colors = [];
geometry.vertices.forEach(function(){
colors.push(new THREE.Color(0xffffff));
});
geometry.colors = colors;
and then in your material you have to set vertexColors as THREE.VertexColors
material = new THREE.PointsMaterial( { size:4, vertexColors: THREE.VertexColors} );
after all, in your "click" event listener you can do
mesh.geometry.colors[100].set(0xff0000);
mesh.geometry.colorsNeedUpdate = true;
jsfiddle example

Painting only one line in Three.js

I have several lines in an array. When I want to paint just one a certain color, they are all painted that color instead.
What can I can do to make it paint only the lines that I want?
var materialSide = new THREE.LineBasicMaterial( { color: "#000000"} );
line[i] = new THREE.Line( Geometria[i], materialSide);
.
.
.
line[24].material.color=new THREE.Color( 0xffffff );
line[24].material.needsUpdate = true;
You are using the same material for all the lines; that is why you are seeing that effect. Create another material materialPainted that has the different color that you want and then you assign the materialPainted material to your line.
line[24].material = materialPainted;

Three.js - Change Material on Runtime

I have some .js files exported from Blender and load them with THREE.JSONLoader();
my callback:
var callback = function( geometry ) { createMesh(geometry);
my loading:
loader.load( "Models/sculp.js", callback );
my create method:
function createMesh(geometry){
inArr[id] = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: 0xbbbbbb} ) );
inArr[id].scale.set( 100, 100, 100 );
scene.add( inArr[id] );
id++;
}
Now I want to change my material on runtime by using my keyboard (changes color and opacity).
How can I do that?
As you create a new material for each mesh I assume you only want to change the color of one mesh and not of all in the inArr array, and you probably need some sort of select for that. But changing the color of the material alone is quite easy:
var onKeyDown = function(event) {
if (event.keyCode == 67) { // when 'c' is pressed
object.material.color.setHex(0xff0000); // there is also setHSV and setRGB
}
};
document.addEventListener('keydown', onKeyDown, false);
object is the mesh you want to change. Key codes can be found here: http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes

Categories