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/
Related
I would like to place an image in a part of the object, i have tried to do:
var geometry = new THREE.BoxBufferGeometry(10, 10, 0);
var material = new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load('models/packagin/place.png')});
var mesh = new THREE.Mesh(geometry, material);
mesh.position.set(10, 5, 0);
material.map.needsUpdate = true; //ADDED
OBJ.traverse(function (child) {
if (child.name !== '') {
OBJ.add(mesh)
}
});
The new object is placed over the primary object but is a flat rectangle
How can I put it so that it is part of the other object?
I have a scene which contains multiple meshes, each of varying shapes and sizes.
I have looped through each Mesh and using geometry.merge() I have been able to create a new mesh from the geometries in the scene.
I want to mask the entire mesh with an alphaMask, however, each geometry has the material applied to it separately.
An example of this can be seen here - https://codepen.io/danlong/pen/KXOObr
function addObjects(scene) {
// merged geomoetry & material
var mergedGeometry = new THREE.Geometry();
var mergedMaterial = new THREE.MeshStandardMaterial({ color: "#444", transparent: true, side: THREE.DoubleSide, alphaTest: 0.5, opacity: 1, roughness: 1 });
// multiple meshes
var geometry = new THREE.IcosahedronGeometry(30, 5);
var material = new THREE.MeshStandardMaterial({ color: "#444" });
var geo1 = new THREE.IcosahedronGeometry(30, 5);
var mesh1 = new THREE.Mesh( geo1, material );
mesh1.position.x = 10;
mesh1.position.y = 10;
mesh1.position.z = 0;
var geo2 = new THREE.IcosahedronGeometry(30, 5);
var mesh2 = new THREE.Mesh( geo2, material );
mesh2.position.x = 20;
mesh2.position.y = 20;
mesh2.position.z = 0;
var geo3 = new THREE.IcosahedronGeometry(30, 5);
var mesh3 = new THREE.Mesh( geo3, material );
mesh3.position.x = 30;
mesh3.position.y = 30;
mesh3.position.z = 0;
// scene.add(mesh1, mesh2, mesh3);
mesh1.updateMatrix();
mergedGeometry.merge(mesh1.geometry, mesh1.matrix);
mesh2.updateMatrix();
mergedGeometry.merge(mesh2.geometry, mesh2.matrix);
mesh3.updateMatrix();
mergedGeometry.merge(mesh3.geometry, mesh3.matrix);
// alpha texture
var image = document.createElement('img');
var alphaMap = new THREE.Texture(image);
image.onload = function() {
alphaMap.needsUpdate = true;
};
image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGUlEQVQoU2NkYGD4z4AHMP7//x+/gmFhAgCXphP14bko/wAAAABJRU5ErkJggg==';
mergedMaterial.alphaMap = alphaMap;
mergedMaterial.alphaMap.magFilter = THREE.NearestFilter;
mergedMaterial.alphaMap.wrapT = THREE.RepeatWrapping;
mergedMaterial.alphaMap.repeat.y = 1;
// merged geometry with alpha mask
merge1 = new THREE.Mesh(mergedGeometry, mergedMaterial);
merge1.rotation.z = -Math.PI/4;
// merge geometry without alpha mask
var merge2 = new THREE.Mesh(mergedGeometry, material);
merge2.position.x = -100;
merge2.rotation.z = -Math.PI/4;
scene.add(merge1, merge2);
return mesh;
}
The mesh on the left is the merged geometries which I want to apply the alphaMask to. The mesh on the right is the outcome of this and instead of the map being applied to the mesh as a whole, each of the geometries has the map applied.
Is there a way to mask the entire mesh and not each geometry?
--
three.js r86
EDIT:
I've tried to apply a clipping plane to my mesh but it's not the effect I'm looking for. I want to be able to apply an alphaMask across the whole mesh and reveal it however I make my mask image. Something like this effect - https://codepen.io/supah/pen/zwJxdb
Is it something to do with the UV's being preserved from the original geometries? Do I need to change these in some way?
I think what you really want is an overlaid mask. This can be accomplished by rendering a single plane that has the alpha map applied, on top of the scene rendering. Using an orthographic camera, and controlling certain renderer settings, such as disabling automatic clearing of color.
Is it possible to map multiple different textures to one face of a geometry in three.js?
I don't want to create multiple faces and assign materialIndexes since the number of faces I need for the geometry changes during runtime.
Here is my last unsuccessful attempt (three.js r.71):
//get some materials
var materials = [];
materials.push(loadTextures(1));
materials.push(loadTextures(2));
materials.push(loadTextures(3));
materials.push(loadTextures(4));
var faceMaterial = new THREE.MeshFaceMaterial(materials);
//create objects
var wireframeObj = new THREE.Mesh(geometry.clone(), new THREE.MeshBasicMaterial({
wireframe: true,
color: 'red'
}));
var mainObj = new THREE.Mesh(geometry, faceMaterial);
scene.add(wireframeObj);
scene.add(mainObj);
camera.position.z = 100;
renderer.render(scene, camera);
function loadTextures(i) {
var texture = new THREE.Texture();
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(2, 2);
var image = new Image();
image.onload = function () {
texture.image = this;
texture.needsUpdate = true;
};
image.src = 'images/crate' + i + '.gif';
return new THREE.MeshBasicMaterial({ map: texture });
}
This produces the following:
while I want to see also crate2 to the right, crate3 above crate1 etc.
I'm trying to create multiple meshes, and then merge them into one (with Three.js r.71). Each mesh can have different materials on different faces. I need to get all the materials appear correctly on the resulting mesh.
I found a way to achieve the desired result, but my code looks pretty awful now. Are the developers of three.js really kept in mind this method?
I could not find a suitable example. Can anyone show a better way to do this?
var totalGeom = new THREE.Geometry();
var meshes = [getBlock(), getBlock()];
meshes[0].position.x = 1;
for (var i = 0; i < meshes.length; i++) {
var mesh = meshes[i];
totalGeom.mergeMesh(mesh);
for (var j = mesh.geometry.faces.length-1; j <= 0; j--) {
totalGeom.faces[j].materialIndex = mesh.geometry.faces[j].materialIndex;
}
}
var materials = meshes[0].material.materials.concat(meshes[1].material.materials);
var totalMesh = new THREE.Mesh(totalGeom, new THREE.MeshFaceMaterial(materials));
scene.add(totalMesh);
function getBlock() {
var geometry = new THREE.BoxGeometry(1, 1, 1, 1, 1, 1);
var material = new THREE.MeshFaceMaterial([
new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture('sides/2.png')}),
new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture('sides/2.png')}),
new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture('sides/1.png')}),
new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture('sides/3.png')}),
new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture('sides/2.png')}),
new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture('sides/2.png')})
]);
return new THREE.Mesh(geometry, material);
}
I would suggest you that instead of mixing all the meshes inside one, you create a group containing all the different meshes. If you do that, you don't need to mix all the materials and you avoid a lot of problems there. And, of course, you get all the advantges of having all the meshes on the same object.
As an example, to do so, follow this procedure:
var scene = new THREE.Scene();
var group = new THREE.Object3D();
var numObjects = 5; //As an example
for(var i=0;i<numObjects;i++){
var cubeGeometry = new THREE.BoxGeometry(100, 100, 100);
var material = new THREE.MeshPhongMaterial();
var mesh = new THREE.Mesh(cubeGeometry, material);
group.add(mesh);
}
scene.add(group);
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.