How to two geometries or meshes are merge in three.js? - javascript

I using 2 geometry, one is line based square 2D geometry, the second is icon image. I expect Should center and place the icons inside the 2d rectangle drawn region area. Below my code.
var combined = new THREE.Geometry();
var squareGeometry = new THREE.Geometry();
squareGeometry.vertices.push(
new THREE.Vector3(startX, startY, 0),
new THREE.Vector3(endX, startY, 0),
new THREE.Vector3(endX, endY, 0),
new THREE.Vector3(startX, endY, 0),
new THREE.Vector3(startX, startY, 0)
);
var square = new THREE.Line(squareGeometry, new THREE.LineBasicMaterial({
color: color
}));
var iconGeometry = new THREE.PlaneGeometry(objSize.width, objSize.height);
var iconMaterial = new THREE.MeshBasicMaterial({ map:THREE.ImageUtils.loadTexture('images/plantIcon.png')
});
var icon = new THREE.Mesh(iconGeometry,iconMaterial);
icon.position.x = objPosition.x;
icon.position.y = objPosition.z;
combined.merge(square.geometry, square.matrix);
combined.merge(icon.geometry, icon.matrix);
var display = new THREE.Line(combined, new THREE.MeshBasicMaterial({
color: color,
}));
scene.add(display);

try this. this link have Merging Geometry link

Related

3D Slicing web app Javascript and Three.js

I am developing a web application to estimate the cost of a 3D printing model with three.js and also do other stuff.
I have easily calculate bounding box and volume of object and I am now approaching slices.
Following this question I have managed to get intersections with a plane: Three JS - Find all points where a mesh intersects a plane and I put the function inside a for loop that appends to a three.js group.
// Slices
function drawIntersectionPoints() {
var contours = new THREE.Group();
for(i=0;i<10;i++){
a = new THREE.Vector3(),
b = new THREE.Vector3(),
c = new THREE.Vector3();
planePointA = new THREE.Vector3(),
planePointB = new THREE.Vector3(),
planePointC = new THREE.Vector3();
lineAB = new THREE.Line3(),
lineBC = new THREE.Line3(),
lineCA = new THREE.Line3();
var planeGeom = new THREE.PlaneGeometry(50,50);
planeGeom.rotateX(-Math.PI / 2);
var plane = new THREE.Mesh(planeGeom, new THREE.MeshBasicMaterial({
color: "lightgray",
transparent: true,
opacity: 0.75,
side: THREE.DoubleSide
}));
plane.position.y = i;
scene.add(plane);
var mathPlane = new THREE.Plane();
plane.localToWorld(planePointA.copy(plane.geometry.vertices[plane.geometry.faces[0].a]));
plane.localToWorld(planePointB.copy(plane.geometry.vertices[plane.geometry.faces[0].b]));
plane.localToWorld(planePointC.copy(plane.geometry.vertices[plane.geometry.faces[0].c]));
mathPlane.setFromCoplanarPoints(planePointA, planePointB, planePointC);
meshGeometry.faces.forEach(function(face) {
mesh.localToWorld(a.copy(meshGeometry.vertices[face.a]));
mesh.localToWorld(b.copy(meshGeometry.vertices[face.b]));
mesh.localToWorld(c.copy(meshGeometry.vertices[face.c]));
lineAB = new THREE.Line3(a, b);
lineBC = new THREE.Line3(b, c);
lineCA = new THREE.Line3(c, a);
setPointOfIntersection(lineAB, mathPlane);
setPointOfIntersection(lineBC, mathPlane);
setPointOfIntersection(lineCA, mathPlane);
});
var lines = new THREE.LineSegments(pointsOfIntersection, new THREE.LineBasicMaterial({
color: 0xbc4e9c,
lineWidth: 2,
}));
contours.add(lines);
function setPointOfIntersection(line, plane) {
pointOfIntersection = plane.intersectLine(line);
if (pointOfIntersection) {
pointsOfIntersection.vertices.push(pointOfIntersection.clone());
};
};
};
console.log(contours);
scene.add(contours);
And this is what I see:
The for loop works and I visualise all the planes and also the lines inside the group but only the first intersection is showing in the canvas (pink).
screenshot
Many thanks.
You have to call .updateMatrixWorld(true) on your plane object after you set its y-coordinate in the loop:
plane.position.y = i;
plane.updateMatrixWorld(true);
scene.add(plane);
jsfiddle example.

Merging geometries in three.js

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 there a way to add different textures to an object with TextureLoader.load

I would like to add different textures to each face of a box but I am not sure if loader.load is the way to do it, right now I have:
loader.load('img/brick.jpg', function ( texture ){
var boxGeometry = new THREE.BoxGeometry( 3, 3, 3 );
var boxMaterial = new THREE.MeshLambertMaterial({
map: texture,
overdraw: 10
});
var box = new THREE.Mesh( boxGeometry, boxMaterial );
box.castShadow = true;
scene.add(box);
}
Is it possible to add more images in the loader.load or do I have to use a different method?
You can just load an image with loader.load, and store it in a variable:
var loader = new THREE.TextureLoader();
var brick = loader.load('img/brick.jpg');
var occlusion = loader.load('img/ao.jpg'); //Example texture
//More textures here
You can then apply it like so:
var boxGeometry = new THREE.BoxGeometry( 3, 3, 3 );
var boxMaterial = new THREE.MeshLambertMaterial({
map: brick,
aoMap: occlusion, //An example use
overdraw: 10
});
var box = new THREE.Mesh( boxGeometry, boxMaterial );
box.castShadow = true;
scene.add(box);
Instead of loading the texture and using an anonymous callback, just load the texture, store it in a variable, then apply where needed.

How to set correct direction for a decal using THREE.DecalGeometry

I am trying to understand how to add decals to a mesh using THREE.DecalGeometry
I am adding decals to the vertex on each face - face.a, I've tried using the face normal and arbitrary Vector3 to define the direction for the decal.
I cannot understand why all the decals are not being created correctly. Where am I go wrong with the direction? Is the face normal not correct?
function addObjects(){
var geometry = new THREE.BoxGeometry(200, 200, 200, 8, 8, 8);
var material = new THREE.MeshLambertMaterial({color: 0xff0000});
cube = new THREE.Mesh(geometry, material);
// addWireframeHelper(cube, 0xffffff, 1);
scene.add(cube);
THREE.ImageUtils.crossOrigin = 'Anonymous';
var texture = THREE.ImageUtils.loadTexture( 'http://i.imgur.com/RNb17q7.png' );
geometry.faces.forEach(function(face){
var index = face.a;
var vertex = geometry.vertices[index];
var direction = new THREE.Vector3(0,1,0);
addDecal(cube, vertex, direction, texture);
})
}
function addDecal(mesh, position, direction, texture){
var size = 16;
var decalGeometry = new THREE.DecalGeometry(
mesh,
position,
direction,
new THREE.Vector3(size,size,size),
new THREE.Vector3(1,1,1)
);
var decalMaterial = new THREE.MeshLambertMaterial( {
map: texture,
transparent: true,
depthTest: true,
depthWrite: false,
polygonOffset: true,
polygonOffsetFactor: -4,
});
var m = new THREE.Mesh( decalGeometry, decalMaterial );
mesh.add(m);
}
This is the hotspot 64px x 64px
This is how they are getting mapped...
Why are some decals stretched?
I have setup a JSFIDDLE
EDIT:
Using SphereBufferGeometry suggested by WestLangley, I am now happy that this solution will work for me.
Rather than using THREE.DecalGeometry, for your use case a sector of a SphereGeometry will be sufficient, and computationally less-expensive.
var geometry = new THREE.SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength );
three.js r.143

Load image as texture

I can load a image as texture when i create the 3d Object Three.js provides.
var handGeo = new THREE.CubeGeometry( 100, 100, 15 );
var texture = THREE.ImageUtils.loadTexture('../images/floor.jpg');
var handMat = new THREE.MeshBasicMaterial( {map: texture, color: 0x000000} );
var handMesh = new THREE.Mesh( handGeo, handMat );
But when i create the object(Cube) adding all the vertices and faces and merging the vertices in the end:
var vertices = [
new THREE.Vector3(p2.x,p2.y,p1.z), //C
new THREE.Vector3(p2.x,p2.y,p2.z), //G
new THREE.Vector3(p2.x,p1.y,p1.z), //D
new THREE.Vector3(p2.x,p1.y,p2.z), //H
new THREE.Vector3(p1.x,p2.y,p2.z), //F
new THREE.Vector3(p1.x,p2.y,p1.z), //B
new THREE.Vector3(p1.x,p1.y,p2.z), //E
new THREE.Vector3(p1.x,p1.y,p1.z) //A
];
var faces = [
new THREE.Face3(0,2,1),
new THREE.Face3(2,3,1),
new THREE.Face3(4,6,5),
new THREE.Face3(6,7,5),
new THREE.Face3(4,5,1),
new THREE.Face3(5,0,1),
new THREE.Face3(7,6,2),
new THREE.Face3(6,3,2),
new THREE.Face3(5,7,0),
new THREE.Face3(7,2,0),
new THREE.Face3(1,3,4),
new THREE.Face3(3,6,4)
];
var geometry = new THREE.Geometry();
geometry.vertices = vertices;
geometry.faces = faces;
geometry.computeCentroids();
geometry.mergeVertices();
var texture = THREE.ImageUtils.loadTexture('../images/floor.jpg');
var material = new THREE.MeshBasicMaterial( {map: texture, color: 0x000000} );
mesh = new THREE.Mesh(geometry, material);
I get this error:
[.WebGLRenderingContext]GL ERROR :GL_INVALID_OPERATION : glDrawElements: attempt to access out of range vertices in attribute 1

Categories

Resources