Different customDepthMaterial for every material - javascript

I have a tree model, that consists from only one mesh and has two materials: bark and branch. I export this mesh from Blender to .json and than add it on the scene:
var texture2 = new THREE.TextureLoader().load('models/branch1.png');
var loader = new THREE.JSONLoader();
loader.load("models/treeTest.json", function (geometry, materials) {
materials.forEach(function (material) {
material.alphaTest = 0.5;
});
mesh = new THREE.Mesh( geometry, materials );
mesh.customDepthMaterial = new THREE.MeshDepthMaterial( {
depthPacking: THREE.RGBADepthPacking,
map: texture2,
alphaTest: 0.5
} );
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add(mesh);
});
Result:
As you can see branches and bark use the same customDepthMaterial and because of that they have same shadows. I need to give customDepthMaterial only to branches, trunk must stay not transparent. I have tried to add customDepthMaterial on material with this:
materials.forEach(function (material) {
material.customDepthMaterial = new THREE.MeshDepthMaterial( {
depthPacking: THREE.RGBADepthPacking,
map: texture2,
alphaTest: 0.5
} );
});
but this code doesnt work (no errors in console, shadows just doesnt have transparency).
I know, that I can split my mesh into two parts (branches and trunk) and than use ObjectLoader, but I need the better solution.

Related

ThreeJS new mesh vs clone

I'm wondering which style is more effective creating a new mesh or cloning one.
For example I have a loop that creates multiple times the "same mesh".
But I also noticed that if I have an opacity of the mesh set as 0 and I want to change it later to be visible, this would effect all the meshes that have the same material. Could it be because they have the same uuid.
var material = new THREE.MeshPhongMaterial({
color: 0xff0000,
transparent: true, // Make the material transparent
opacity: 0 // Set material opacity to 0
});
var geometry = new THREE.PlaneGeometry(width, height);
$.each(things, function(i, something) {
var mesh = new THREE.Mesh(geometry, material);
// Mesh positioning
scene.add(mesh);
});
So if I use the same material and geometry multiple times and use the raycaster to change the mesh opacity it would change the opacity of all the meshes.
Should I use the clone inside the each loop or create the material and the geometry of the mesh again and again?
$.each(things, function(i, something) {
var mesh = new THREE.Mesh(geometry.clone(), material.clone());
// Mesh positioning
scene.add(mesh);
});
or
$.each(things, function(i, something) {
var material = new THREE.MeshPhongMaterial({
color: 0xff0000,
transparent: true, // Make the material transparent
opacity: 0 // Set material opacity to 0
});
var geometry = new THREE.PlaneGeometry(width, height);
var mesh = new THREE.Mesh(geometry, material);
// Mesh postioning here
scene.add(mesh);
});
In your first method all the meshes are built up on the SAME GEOMETRY and MATERIAL(As you said they also have the same uuid).
So when you change the properties of the material it will affect all the meshes which are using the same material. But when you clone the material, it will create a NEW MATERIAL WITH THE SAME PROPERTIES, and also changes on the original material will not affect the cloned material. So most probably this method will work for you,
$.each(things, function(i, something) {
var mesh = new THREE.Mesh(geometry, material.clone());
// rest of your code...
});
I tried the following and it worked for me,
var material = new THREE.MeshPhongMaterial({
color: 0xff0000,
transparent: true,
opacity: 0.5
});
var geometry = new THREE.PlaneGeometry(100, 100, 1, 1);
for( var i = 0; i < 5; i++ ){
scene.add( new THREE.Mesh( geometry, material.clone() ) );
}

Plane casts shadows on itself

I created a simple mesh in Blender, which consist only from one textured plane.
Blender screenshot
I import it in three.js with this code:
var texture2 = new THREE.TextureLoader().load('models/TexturesCom_Branches0030_1_S.png');
loader.load("models/plant.json", function (geometry, materials) {
materials.forEach(function (material) {
material.alphaTest = 0.5;
});
mesh = new THREE.Mesh( geometry, materials );
mesh.customDepthMaterial = new THREE.MeshDepthMaterial( {
side: THREE.DoubleSide,
depthPacking: THREE.RGBADepthPacking,
map: texture2,
alphaTest: 0.5
} );
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add(mesh);
});
That's how mesh looks in three.js: #1
#2
As you can see, object casts shadow not only on the ground, but on itself.
I can turn receiveShadow off, but this is not a solution for me. This problem does not disappear, if I create THREE.PlaneGeometry manually.

Three.js: viewangle affects texture strength

My mesh has a baked shadow texture.
Unfortunately I got a weird result If I move the camera to a steeper viewangle.
What can I do to prevent this ?
loader.load( "mesh.js", function(geometry){
var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial( {
map: THREE.ImageUtils.loadTexture( "texture.png" ),
}));
scene.add(mesh);
});
Look at the example: http://threejs.org/examples/#webgl_materials_texture_anisotropy
Use:
var maxAnisotropy = renderer.getMaxAnisotropy();
texture.anisotropy = maxAnisotropy;
If you would like to learn more, you can look up Anisotropic Filtering.

adding external texture to three.js scene object

just getting my hands dirty with three.js and im curious on something that may be relatively simpleā€¦
I built a scene in the three.js editor and have figured out how to load the scene. In the editor, I added an image as a map texture but I realize it wont know where it is loaded externally on my server. So I've loaded the scene and objects and lights, but how can I map my textures to the objects?
// MATERIALS
var wireframe = THREE.ImageUtils.loadTexture( 'textures/wireframe.jpg' );
wireframe.wrapS = wireframe.wrapT = THREE.RepeatWrapping;
wireframe.repeat.set( 4, 4 );
var wireframeMaterial = new THREE.MeshLambertMaterial({
map : wireframe,
side : THREE.DoubleSide
});
// LOAD SCENE
var loader = new THREE.ObjectLoader();
loader.load( 'js/scene.js', function ( obj ) {
obj.traverse( function( node ) {
if ( node instanceof THREE.Mesh ) {
node.castShadow = true;
node.receiveShadow = true;
var plane = scene.getObjectByName( "plane", true );
plane.material = wireframeMaterial;
}
});
scene.add( obj );
render();
});
When adding plane.material = wireframeMaterial; into the loader, all my objects just disappearā€¦ How can I properly map the wireframeMaterial the plane object?
working example with var plane and plane.material commented out:
http://goo.gl/czSg7P
Scene:
http://goo.gl/BAVgVS
To map the texture you have to create a material using your texture and apply it to your plane.
If necessary you can set repetition of your texture with:
wireframe.wrapS = THREE.RepeatWrapping;
wireframe.wrapT = THREE.RepeatWrapping;
wireframe.repeat.set( 4, 4 );
And then you need to do something like this:
material = new THREE.MeshLambertMaterial({ map : wireframe, side : THREE.DoubleSide });
plane.material = material;
EDIT
You create a scene inside a scene. Since the loader returns a scene and then you add it again to a scene. This will give issues for sure.
Try to replace scene.add( obj ); with this in your loader:
for( var i = 0; i < obj.children.length; i++ ){
scene.add( obj.children[i] );
}
Not sure if that causes the problem, but I made a fiddle and it all seems to work fine for me. The problem is that I can't load external sources in my fiddle so instead I had to use your image as base64 string and the code becomes a bit different.
This means you have to change it a bit to make it work again with an image from your local folder.
If you exchange the Whole //TEXTURE part of the code with the following it should work:
var texture = new THREE.ImageUtils.loadTexture( 'img/wireframe.jpg' );
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 1, 1 );
var textureMaterial = new THREE.MeshLambertMaterial({ map: texture, side : THREE.DoubleSide });

using a texture mesh and wireframe mesh in threejs

I'm trying to draw a wireframe mesh and a textured mesh in threeJS but when I have both added to my scene the textured mesh doesn't display. Code below:
I'm having trouble creating two meshes that share the same geometry where one of the materials is wireframe and the other is a texture. If one of the materials is wireframe and the other is just a color fill it works fine- but as soon as I make the second material a texture it stops working.
If I comment out scene.add( wireMesh ); then the textured mesh shows up.
var wireMat = new THREE.MeshBasicMaterial( { color:0x00FFFF, wireframe: true, transparent: true, overdraw:true } );
var wireMesh = new THREE.Mesh(geometry, wireMat);
scene.add( wireMesh );
var texture = texture = THREE.ImageUtils.loadTexture( 'textures/world.jpg' );
var imageMat = new THREE.MeshBasicMaterial( {color:0xffffff, map: texture } );
var fillMesh = new THREE.Mesh(geometry, imageMat);
scene.add( fillMesh );
Under SceneUtils there is a createMultiMaterialObject(geometry, materials). It essentially creates multiple meshes that all share the same geometry all in a group.
Example:
var mesh = THREE.SceneUtils.createMultiMaterialObject( geometry, [
new THREE.MeshLambertMaterial( { color: 0xffffff} ),
new THREE.MeshBasicMaterial( { color: 0x222222, wireframe: true} )
]);
THREE.SceneUtils source code
Unfortunately it is not possible to share geometry between an object using wireframe and another one not using it. You'd need to clone that geometry. Which reminds me that we haven't done .clone() for Geometry yet.

Categories

Resources