ThreeJS remove texture - three.js

I have a ThreeJS scene and I'd like to provide the option of seeing all models in different modes (with or without textures and/or wireframe).
I'm trying to accomplish this using only one Geometry and one Material for each object.
When I try to remove the texture of an object by setting the map property of its material to null something bizarre happens. The object takes the latest loaded texture, even if it was loaded and applied to another object. Is this somehow an expected behavior? If not, how should I remove the map?

a good approach would be to initialize the materials you will need from the beginning :
var materials = {};
materials['lambert'] = new THREE.MeshLambertMaterial( { color: 0xdddddd, shading: THREE.SmoothShading } );
materials['phong'] = new THREE.MeshPhongMaterial( { color: 0xFF0000, specular: 0x009900, shininess: 30, shading: THREE.FlatShading } );
materials['basic'] = new THREE.MeshBasicMaterial( { color: 0xffaa00, transparent: true, blending: THREE.AdditiveBlending } );
materials['wireframe'] = new THREE.MeshBasicMaterial( { color: 0xffffff, wireframe : true } );
and replace the material of your object when you need to :
function changeMaterial(id){
mesh.material = materials[id];
}
changeMaterial('wireframe');
I did a fiddle that demonstrates that : http://jsfiddle.net/95t964o0/75/
I did not use a material with a texture because it's a bit tricky for jsfiddle.com to load an image.
Note : be carefull when many objects share the same material! If you make changes to the material of an object it affects all the others (obviously because it is shared).

Related

Life like paper in three.js

I am building a game. In my game is a scene where the character is reading a book. I have created pages of that book which should flip around and stuff. Using Three.js It is simple to crate a cube geo with some specs. My problem is that the paper or page representation is like a board. The paper should be floppy and flexible like paper.
That is where I am stuck. I looked into Physi.js but seems to be an overkill. Collision may be something I need in the future so that the pages do not assume the same exact plane, but for now I will settle for life-like. I looked at morphing but am unsure if that is the way to go.
I Have built a fiddle at https://jsfiddle.net/e4hqdjbz/
It is only a single page with orbit controls though.
//PAPER
frontside = new THREE.TextureLoader().load( 'https://images.pexels.com/photos/2837975/pexels-photo-2837975.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260' );
frontside.minFilter = THREE.LinearFilter;
backside = new THREE.TextureLoader().load( 'https://images.pexels.com/photos/1001780/pexels-photo-1001780.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260' );
backside.minFilter = THREE.LinearFilter;
edge = new THREE.TextureLoader().load( );
edge.minFilter = THREE.LinearFilter;
materialArray1= [
new THREE.MeshBasicMaterial( { color: 0xffffff } ), //Right side
new THREE.MeshBasicMaterial( { color: 0xffffff } ), // Left Side
new THREE.MeshBasicMaterial( { color: 0xffffff } ), // Top
new THREE.MeshBasicMaterial( { color: 0xffffff } ), // Bottom
new THREE.MeshBasicMaterial( { map: frontside } ),
new THREE.MeshBasicMaterial( { map: backside } ),
];
var geometry1 = new THREE.BoxGeometry( 23.3, 50, 0.005 );
var paper = new THREE.Mesh( geometry1, materialArray1 );
paper.position.set(0,0,0)
scene.add( paper );
Any thoughts on a direction I should head and why?
When flipping a page or paper, the animation should be more life-like, kinda flexible but not resistant. Adding physics with gravity, density and airflow may be the answer, but not sure.
Create a skinned mesh animation of the exact textured page animation, in Blender, either by you, or a 3d artist... export that animation as (gltf) .glb and load that in your app, and after the load completes, swap out the material.map s to whatever texture you want.

transparent material rendering artifacts

I have a 3d surface which I would like to make it transparent so the map under it is visible.
The problem is that some face hidden are rendered not making the transparency constant (highlighted). Is possible to render the yellow/green of the right image transparent without these artefacts?
Folling #WestLangley comment I was able to fix the issue rendering twice:
once colorWrite = false and then colorWrite = true . The simplest way I found is with a MultiMaterialObject.
let material = new THREE.MeshPhongMaterial(
{ color: 0xffffff88,
side: THREE.DoubleSide,
opacity: 0.4,
transparent: true,
colorWrite : false,
vertexColors: THREE.VertexColors,
shininess: 60
} )
let material_cw = material.clone()
material_cw.colorWrite = true
let mesh = THREE.SceneUtils.createMultiMaterialObject(
geometry,[material,material_cw] )

Three.js - transparent planes hiding sprites

When we add text-spites on scene, we saw that our transparent planes hide sprites, but didn't hide any 3d Objects.
Why is this and how to make sprites visible under transparent planes?
To look PNG example click here
My plane is:
// transparent plane
geometry = new THREE.PlaneGeometry(200, 200, 200);
material = new THREE.MeshBasicMaterial({
color: 0xa6cfe2,
side: THREE.DoubleSide,
transparent: true,
opacity: 0.5,
depthFunc: THREE.LessDepth,
});
But it seems no work good.
So, for that examle i wrote some code on fiddle, to figure out the problem:
look fidddle example
three.js renders opaque objects first, then transparent objects.
You can use this pattern to prevent your transparent objects from writing to the depth buffer:
// transparent plane
geometry = new THREE.PlaneBufferGeometry( 200, 200, 1, 1 );
material = new THREE.MeshBasicMaterial( {
color: 0xa6cfe2,
side: THREE.DoubleSide,
transparent: true,
opacity: 0.5,
depthWrite: false
} );
three.js r.112

Three.js outline mesh

How can I get outline affect the same as in THREE.js editor ?
I've tried this:
// child = child of my object
var outlineMaterial1 = new THREE.MeshBasicMaterial( { color: 0xff0000, side: THREE.BackSide } );
var outlineMesh1 = new THREE.Mesh( child.geometry, outlineMaterial1 );
outlineMesh1.position = child.position;
outlineMesh1.scale.multiplyScalar(1.05);
scene.add( outlineMesh1 );
Trying to do the same as in this example (code). I'm getting completely different effect:
Same questions: #1 and #2.
Did you try wireframe?
var outlineMaterial1 = new THREE.MeshBasicMaterial( { color: 0xff0000, side: THREE.BackSide, wireframe: true } );
Not sure if you would need THREE.BackSide or not.
take a look at the parameters for MeshBasicMaterial here
Have you looked at the code for the editor to see how it does it?
EDIT
I think the editor is using a BoxHelper object which creates the outline
EDIT
HERE is a stack question showing how to have the BoxHelper render on top.
HERE is a fiddle as an example implementing the above.
If you need somethink of this when user tap on mesh you can use this code :
let geo = new THREE.EdgesGeometry(intersects[0].object.geometry);
let mat = new THREE.LineBasicMaterial({ color: "black", linewidth: 10 });
let wireframe = new THREE.LineSegments(geo, mat);
wireframe.renderOrder = 1; // make sure wireframes are rendered 2nd
intersects[0].object.add(wireframe);

Three JS Map Material causes WebGL Warning

I'm trying to define a material to meshes I loaded in from OBJLoader through the following wrapper function:
function applyTexture(src){
var texture = new THREE.Texture();
var loader = new THREE.ImageLoader();
loader.addEventListener( 'load', function ( event ) {
texture.image = event.content;
texture.needsUpdate = true;
// find the meshes from the loaded OBJ and apply the texture to it.
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
if(child.name.indexOf("Lens") < 0){
child.dynamic = true;
child.material = new THREE.MeshLambertMaterial( { color: 0xdddddd, shading: THREE.FlatShading, map : texture } );
// also tried:
//child.material = new THREE.MeshPhongMaterial( { color: 0x000000, specular: 0x666666, emissive: 0x000000, ambient: 0x000000, shininess: 10, shading: THREE.SmoothShading, map : texture} );
// and:
//child.material = new THREE.MeshBasicMaterial({map : texture});
child.material.map = texture; // won't throw the WebGL Warning, but won't show the texture either;
} else {
// works just fine.
child.material = new THREE.MeshPhongMaterial( { color: 0x000000, specular: 0x666666, emissive: 0x000011, ambient: 0x000000, shininess: 10, shading: THREE.SmoothShading, opacity: 0.6, transparent: true } );
}
}
});
});
loader.load( src );
}
When the texture has loaded and it's time to apply the material to the mesh, I start getting the following warning on the console:
.WebGLRenderingContext: GL ERROR :GL_INVALID_OPERATION : glDrawElements: attempt to access out of range vertices in attribute 0
and the mesh itself disappears.
what am I doing wrong here?
UPDATE
As #WestLangley pointed on the comments: Never try to apply texture/materials after things have been rendered. Create the materials before rendering the object to the scene and then change them using:
obj.material.map = texture
With WebGLRenderer, you can't switch from a material without a texture, to a material with a texture, after the mesh has been rendered once. This is because, without an initial texture, the geometry will not have the necessary baked-in WebGL UV buffers.
A work-around is to begin with a material having a simple white texture.
UPDATE: Alternatively, you can begin with a textureless material, and then set the following flags when a texture is added:
material.needsUpdate = true;
geometry.buffersNeedUpdate = true;
geometry.uvsNeedUpdate = true;
three.js r.58
I also got this error while loading a scene from blender. For me the problem was fixed when unwrapping the uv's for each mesh i want to have a texture on.

Resources