I'd like to add outline to meshes. I followed the example which created a new mesh using the same geometry, and scaled the mesh.
var outlineMaterial = new THREE.MeshBasicMaterial({color: 0x00ffff, side: THREE.BackSide});
this.outlineMesh = new THREE.Mesh(target.geometry, outlineMaterial);
this.outlineMesh.quaternion = target.quaternion;
this.outlineMesh.position = target.position;
this.outlineMesh.scale.copy(target.scale);
this.outlineMesh.scale.multiplyScalar(1.05);
this.scene.add(this.outlineMesh);
It works fine, the position of outlineMesh is always same to target mesh. However, when I added the target mesh as child to other mesh, the position of outlineMesh is different to the target mesh. I thought it's because the target position is related to parent's coordinate, but the outlineMesh is still in the world coordinate.
Any idea how to make outline work for child mesh? Thank you very much!
Just add the outlineMesh as a child of the target mesh, like so:
var outlineMaterial = new THREE.MeshBasicMaterial( { color: 0x00ffff, side: THREE.BackSide } );
outlineMesh = new THREE.Mesh( geometry, outlineMaterial );
outlineMesh.scale.multiplyScalar( 1.05 );
mesh.add( outlineMesh );
three.js r.67
Related
I would like to add a mask effect on my scene.
I found this cool jsfiddle : https://jsfiddle.net/f2Lommf5/4703/
I've been wondering if it's possible to set the white part of that texture transparent so I can have my background object cropped depending on the above plane texture.
I tried to play with the alphaTest value but in vain.
Does anyone have any idea on how to reach this result ? Thank you
I'm not 100% sure I understand your intended result but it should be possible to implement the effect via post processing. In the following live demo, MaskPass is used to create a mask where no pixels of the actually beauty pass are rendered. The important code section is:
var clearPass = new ClearPass();
var maskPass = new MaskPass( sceneMask, camera );
maskPass.inverse = true;
var renderPass = new RenderPass( scene, camera );
renderPass.clear = false;
var clearMaskPass = new ClearMaskPass();
var outputPass = new ShaderPass( CopyShader );
var parameters = {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBFormat,
stencilBuffer: true
};
var renderTarget = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, parameters );
composer = new EffectComposer( renderer, renderTarget );
composer.addPass( clearPass );
composer.addPass( maskPass );
composer.addPass( renderPass );
composer.addPass( clearMaskPass );
composer.addPass( outputPass );
Notice that the mask object (the plane) is managed in a separate scene.
Live demo: https://jsfiddle.net/e6p0axb1/5/
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.
I'm creating a parent/child hierarchy between three objects using the ".add()" method in Three.js, (RE: 71). Parenting a two objects poses no problems. However, When I attempt to create a three level hierarchy, the middle child jumps to an offset equivalent to the offset of it's parent from the origin.
This is the hierarchy:
Red Box (parent of Green Box) -> Green Box (parent of Blue Box) -> Blue Box
Below is an image of how the boxes should be positioned before and after the parenting:
This is an Image if how the boxes have been repositioned when parented:
The relevant code looks like this:
var testObject_G1 = new THREE.BoxGeometry(50, 100, 100);
var testObject_G2 = new THREE.BoxGeometry(100, 100, 50);
var testObject_G3 = new THREE.BoxGeometry(50, 100, 100);
var testObject_MR = new THREE.MeshBasicMaterial({ color: 0xff0000 });
var testObject_MG = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
var testObject_MB = new THREE.MeshBasicMaterial({ color: 0x0000ff });
var testObject_Mesh = new THREE.Mesh(testObject_G1, testObject_MR);
testObject_Mesh.position.x = -100;
var testObject_Mesh2 = new THREE.Mesh(testObject_G2, testObject_MG);
testObject_Mesh2.position.x = 0;
var testObject_Mesh3 = new THREE.Mesh(testObject_G3, testObject_MB);
testObject_Mesh3.position.x = 100;
testObject_Mesh2.add( testObject_Mesh3 );
testObject_Mesh.add( testObject_Mesh2 );
scene.add( testObject_Mesh );
There is a JS Fiddle here: jumping second child
Thank you in advance.
what you see is correct. In a hierarchy the child will inherit the parents transform (inherit is simplification; their matrices will be multiplied but you only have translation defined so the values will be added). So testMesh (red) will appear at x=-100, testMesh2 (green) will also appear at x=-100 (since its x transform is 0 and will inherit its parent transform) and testMesh3 (blue) will appear at x=0 (since -100+0+100=0).
Add this to your fiddle to see the relative transformations.
scene.add( new THREE.AxisHelper( 100 ));
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.
I'm trying to apply a THREE.ImageUtils.loadTextureCube() using the real time camera onto a spinning cube.
Until now, I managed to apply a simple texture using my video to a MeshLambertMaterial :
var geometry = new THREE.CubeGeometry(100, 100, 100, 10, 10, 10);
videoTexture = new THREE.Texture( Video ); // var "Video" is my <video> element
var material = new THREE.MeshLambertMaterial({ map: videoTexture });
Cube = new THREE.Mesh(geometry, material);
Scene.add( Cube );
That's OK and you can see the result at http://jmpp.fr/three-camera
Now I'd like to use this Video stream to have a brushed metal texture, so I tried to create another kind of material :
var videoSource = decodeURIComponent(Video.src);
var environment = THREE.ImageUtils.loadTextureCube([videoSource, // left
videoSource, // right
videoSource, // top
videoSource, // bottom
videoSource, // front
videoSource]); // back
var material = new THREE.MeshPhongMaterial({ envMap: environment });
... but it throws the following error :
blob:http://localhost/dad58cd1-1557-41dd-beed-dbfea4c340db 404 (Not Found)
I guess loadTextureCube() is trying to get the 6 array parameters as an image, but doesn't seems to appreciate a videoSource instead.
I'm beginning with three and wondered if there is a way to do that ?
Thx,
jmpp
There are two ways I could see. First, if you just want the same image but with some specular highlights/shininess then just change
var material = new THREE.MeshLambertMaterial({ map:texture});
to
var material = new THREE.MeshPhongMaterial({
map: texture ,
ambient: 0x030303,
specular: 0xffffff,
shininess: 90
});
and play with the ambient, specular, shininess settings to find what you like.
Second, if you really want to add effects to the video image itself, you could draw the image to a canvas, manipulate the pixels, and then set the texture image to that new image. This could also be done with custom shaders, avoiding the canvas step, but there are already libraries for applying image filters to elements, so I'd stick with that. That would work something like this:
You would need a canvas to draw to <canvas id='testCanvas' width=256 height=256></canvas> Then with javascript
var ctx = document.getElementById('testCanvas').getContext('2d');
texture = new THREE.Texture();
// in the render loop
ctx.drawImage(Video,0,0);
var img = ctx.getImageData(0,0,c.width,c.height);
// do something with the img.data pixels, see
// this article http://www.html5rocks.com/en/tutorials/canvas/imagefilters/
// then write it back to the texture
texture.image = img;
texture.needsUpdate = true
Updated!
Actually, you can do it as an envMap, you just need to force the video to be a power of 2 with same width/height. Videos stream in to chrome as 640x480, so you still need to draw a canvas, but only to crop/square the image. So I got this to work:
// In the access camera part
var canvas = document.createElement('canvas')
canvas.width = 512;
canvas.height = 512;
ctx = canvas.getContext('2d');
// In render loop
ctx.drawImage(Video,0,0, 512, 512);
img = ctx.getImageData(0,0,512,512);
// This part is a little different, but env maps have an array
// of images instead of just one
cubeVideo.image = [img,img,img,img,img,img];
if (Video.readyState === Video.HAVE_ENOUGH_DATA)
cubeVideo.needsUpdate = true;
Try this:
var environment = new THREE.Texture( [ Video, Video, Video, Video, Video, Video ] );
var material = new THREE.MeshPhongMaterial({ envMap: environment });
// in animate()
environment.needsUpdate = true;
Okay, now I managed to get a shiny effect on the cube using a Phong material :
videoTexture = new THREE.Texture( Video );
var material = new THREE.MeshPhongMaterial({
map: videoTexture,
ambient: 0x030303,
specular: 0xc0c0c0,
shininess: 25
});
This looks not so bad.
But it seems that a THREE.Texture([Video,Video,Video,Video,Video,Video]); isn't working as an envMap. I still get a black cube.