I have a loop where I create a multiple Mesh with different geometry, because each mesh has one texture:
var geoCube = new THREE.CubeGeometry(voxelSize, voxelSize, voxelSize);
var geometry = new THREE.Geometry();
for( var i = 0; i < voxels.length; i++ ){
var voxel = voxels[i];
var object;
color = voxel.color;
texture = almacen.textPlaneTexture(voxel.texto,color,voxelSize);
//Return the texture with a color and a text for each face of the geometry
material = new THREE.MeshBasicMaterial({ map: texture });
object = new THREE.Mesh(geoCube, material);
THREE.GeometryUtils.merge( geometry, object );
}
//Add geometry merged at scene
mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial() );
mesh.geometry.computeFaceNormals();
mesh.geometry.computeVertexNormals();
mesh.geometry.computeTangents();
scene.add( mesh );
But now I have this error in the javascript code Three.js
Uncaught TypeError: Cannot read property 'map' of undefined
In the function:
function bufferGuessUVType ( material ) {
}
Update:
Finally I have removed the merged solution and I can use an unique geometry for the all voxels. Altough I think that If I use merge meshes the app would have a better performance.
For r53+ the code should be something like this:
var geoCube = new THREE.CubeGeometry(voxelSize, voxelSize, voxelSize);
var geometry = new THREE.Geometry();
var materials = [];
for( var i = 0; i < voxels.length; i++ ){
for ( var j = 0; j < geoCube.faces.length; j ++ ) {
geoCube.faces[ j ].materialIndex = i;
}
var object = new THREE.Mesh( geoCube );
// here I assume you'll me positioning the object.
THREE.GeometryUtils.merge( geometry, object );
var voxel = voxels[i];
var texture = almacen.textPlaneTexture(voxel.texto,voxel.color,voxelSize);
materials.push( new THREE.MeshBasicMaterial( { map: texture } ) );
}
// Add geometry to scene
var mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ) );
mesh.geometry.computeFaceNormals();
mesh.geometry.computeVertexNormals();
scene.add( mesh );
Some methods are expecting the materials array to be in the mesh face material. For example:
function getBufferMaterial( object, geometryGroup ) {
return object.material instanceof THREE.MeshFaceMaterial
? object.material.materials[ geometryGroup.materialIndex ]
: object.material;
};
Its possible to handle this by referencing the materials array both in the geometry and in the mesh face material. So the line where the mesh is created would look something like:
mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial(geometry.materials) );
and in the loop processing the voxels:
geometry.materials.push( new THREE.MeshBasicMaterial({ map: texture }));
Each face in the geometry also needs to have a materialIndex assigned or there will be an error. Looping through geometry.faces[] and assigning a materialIndex might be a good way if you know how many faces each of the voxels has.
Related
I would to apply a transparent material on front-side faces of a geometry. It's quite easy:
var normal = new THREE.MeshNormalMaterial();
normal.side = THREE.BackSide;
var materials = [
normal,
new THREE.MeshBasicMaterial( { transparent: true, opacity: 0 } )
];
for( var i = 0; i < geometry.faces.length; i++ ) {
geometry.faces[ i ].materialIndex = 0;
}
//a 'hole' to look inside
geometry.faces[ 0 ].materialIndex = 1;
geometry.faces[ 1 ].materialIndex = 1;
mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ) );
Codepen to example above: http://codepen.io/pyort/pen/egqbLY
But there is a catch: when looking on a front-side of a face, I would like to show what's underneath this geometry, not back-side.
I'm not sure how to explain that in easy language, here is visual explanation
What is my goal is this kind of 'portal' thing, so when you look from one side, it appears to have depth, but from other angles it's look super thin. How to achieve such an effect? Use some kind of shader? Use mirror techniques?
Thanks.
Try something like this:
// the inside of the hole
let geometry1 = new THREE.CubeGeometry(2,2,2);
let material1 = new THREE.MeshLambertMaterial({
transparent : true,
color: 0xff0000,
side: THREE.BackSide
});
mesh1 = new THREE.Mesh( geometry1, material1 );
scene.add( mesh1 );
// the invisibility cloak (box with a hole)
let geometry0 = new THREE.BoxGeometry(2,2,2);
geometry0.faces.splice(4, 2); // make hole by removing top two triangles
let material0 = new THREE.MeshBasicMaterial({
colorWrite: false
});
let mesh0 = new THREE.Mesh( geometry0, material0 );
mesh0.scale.set(1,1,1).multiplyScalar(1.01); // slightly larger than inside cube
scene.add(mesh0);
Live examples are at https://stemkoski.github.io/AR-Examples/
A path is changed dynamically. So,
previous render function was,
(LENGTH, getPosition(), RADIUS, MATERIAL, SCENE are already set)
var prevPosition = getPosition();
for(var i =0; i < LENGTH; i++) {
drawPath(getPosition());
}
function drawPath(currentPosition) {
var spline = new THREE.CatmullRomCurve3([prevPosition, currentPosition]);
var geometry = new THREE.TubeGeometry(spline, 1, RADIUS);
var mesh = new THREE.Mesh(geometry, MATERIAL);
SCENE.add(mesh);
}
previous render method works very well.
I changed this for performance.
modified render function is,
var mergedGeometry = new THREE.Geometry();
function drawPath(currentPosition) {
var spline = new THREE.CatmullRomCurve3([prevPosition, currentPosition]);
var geometry = new THREE.TubeGeometry(spline, 1, RADIUS);
mergedGeometry.merge(geometry);
var mesh = new THREE.Mesh(mergedGeometry, MATERIAL);
SCENE.add(mesh);
}
mesh is not displayed.
I don't know why.
Do you know why does not this work?
Please help me.
I believe you've confused geometry for a mesh. Geometry is a component of a mesh. You want to add to your geometry, cast it into a new mesh object, and add that new mesh to the scene.
Try:
var mergedGeometry = new THREE.Geometry();
var prevPosition = getPosition();
for(var i =0; i < LENGTH; i++) {
drawPath(getPosition());
}
var mesh = new THREE.Mesh(mergedGeometry, MATERIAL);
SCENE.add(mesh);
function drawPath(currentPosition) {
var spline = new THREE.CatmullRomCurve3([prevPosition, currentPosition]);
var geometry = new THREE.TubeGeometry(spline, 1, RADIUS);
mergedGeometry.merge(geometry);
}
If you get stuck, there is a functioning mesh merge fiddle here: http://jsfiddle.net/mt2zbb9k/
Trying to add a simple object to a three.js scene. I'm getting the error Uncaught ReferenceError: Cube is not defined, but it seems to be defined to me. What am I doing wrong here?
Here's a plunker
Here's the relevant js:
// Cube
Cube = function(){
var geometry = new THREE.BoxGeometry( 50, 50, 50 );
for ( var i = 0; i < geometry.faces.length; i += 2 ) {
var hex = Math.random() * 0xffffff;
geometry.faces[ i ].color.setHex( hex );
geometry.faces[ i + 1 ].color.setHex( hex );
}
var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, overdraw: 0.5 } );
box = new THREE.Mesh( geometry, material );
box.position.y = 25;
}
function createCube(){
cube = new Cube();
scene.add(cube);
}
Two things are wrong.
You should be adding the cube mesh to the scene. So instead of box = new THREE.Mesh( geometry, material ); put return box = new THREE.Mesh( geometry, material );
call createCube() after you have defined the function
In a three.js scene, I would like to have an object that's not visible, but still occludes other objects in the scene as if it was visible.
Is this possible with the three.js library? Here is an example:
Suppose I have a three.js scene that contains 3 objects: object a, object b and object c and a camera. I would like object c to be invisible to the camera, but still occlude object b... Scenario 1:
In scenario 1, here is what I would like the camera to see:
Scenario 2:
In scenario 2, here is what I would like the camera to see:
Can anyone tell suggest a technique use to achieve such an effect?
Yes, in three.js you can create an object that is invisible, but still occludes other objects as if it were visible.
To do that, you need to use two features available in three.js: Object3D.renderOrder and Material.colorWrite.
You need to make sure the invisible object is rendered prior to the object(s) it must occlude.
You control the rendering order with the renderOrder property.
You make the occluding object invisible by setting its material's colorWrite property to false.
// material
var material = new THREE.MeshPhongMaterial();
// mesh a
var geometry = new THREE.PlaneGeometry( 10, 10, 4, 4 );
mesh = new THREE.Mesh( geometry, material.clone() );
mesh.material.color.set( 0xff0000 );
mesh.renderOrder = 0; // <===================
mesh.position.z = - 10;
scene.add( mesh );
// mesh b
var geometry = new THREE.BoxGeometry( 2, 2, 2 );
mesh = new THREE.Mesh( geometry, material.clone() );
mesh.material.color.set( 0x606060 );
mesh.renderOrder = 3;
mesh.position.z = 0;
scene.add( mesh );
// mesh c
var geometry = new THREE.BoxGeometry( 3, 3, 3 );
mesh = new THREE.Mesh( geometry, material.clone() );
mesh.material.color.set( 0x0000ff );
mesh.material.colorWrite = false; // <=================
mesh.renderOrder = 2;
mesh.position.z = 10;
scene.add( mesh );
three.js r.143
I have the latest threecsg.js library and my use of it has been okay, except when I try to use the subdivision modifier after a CSG operation. Here is example code, modified from the example.html file that comes with the library from github:
var start_time = (new Date()).getTime();
var cube_geometry = new THREE.CubeGeometry( 3, 3, 3 );
var cube_mesh = new THREE.Mesh( cube_geometry );
cube_mesh.position.x = -6;
var cube_bsp = new ThreeBSP( cube_mesh );
var sphere_geometry = new THREE.SphereGeometry( 1.8, 12, 12 );
var sphere_mesh = new THREE.Mesh( sphere_geometry );
sphere_mesh.position.x = -7;
sphere_mesh.position.y -= 0;
var sphere_bsp = new ThreeBSP( sphere_mesh );
var subtract_bsp = cube_bsp.union( sphere_bsp );
var result = subtract_bsp.toMesh( new THREE.MeshLambertMaterial({ shading: THREE.SmoothShading, map: THREE.ImageUtils.loadTexture('texture.png') }) );
result.geometry.computeVertexNormals();
var smooth = result.geometry.clone() ;
smooth.mergeVertices();
var modifier = new THREE.SubdivisionModifier(0.1);
modifier.modify( smooth );
var mesh = new THREE.Mesh( smooth, new THREE.MeshPhongMaterial( { wireframe:true, color: 0xffffff } ) );
mesh.geometry.computeFaceNormals();
scene.add( mesh );
The above code unites a sphere and a cube. After this, it runs the resulting geometry through the subdivision modifier. The final output that is added to the scene has faces that are protruding from the object, other than that, the object does look smooth. Can anyone please help in solving this issue, that is, removing the protruding faces?