Triangulation of 3D points with K vertices per face - javascript

I'm working with Three.js. I have a collection of 3D points (x, y, z) and a collection of faces. One face is composed of K points. It can be as well convex as concave.
I found nothing that could help me in the Three.js documentation. One solution could be to triangulate those shapes, but so far I haven't found any simple 3D triangulation algorithm.
The other solution would be doing something like that :
var pointsGeometry = new THREE.Geometry();
pointsGeometry.vertices.push(new THREE.Vector3(10, 0, 0));
pointsGeometry.vertices.push(new THREE.Vector3(10, 10, 0));
pointsGeometry.vertices.push(new THREE.Vector3(0, 10, 0));
pointsGeometry.vertices.push(new THREE.Vector3(1, 3, 0));
pointsGeometry.vertices.push(new THREE.Vector3(-1, 3, 0));
pointsGeometry.vertices.push(new THREE.Vector3(10, 0, 0));
var material = new THREE.MeshBasicMaterial({color: 0x00ff00});
var mesh = new THREE.Shape/ShapeGeometry/Something(pointsGeometry, material);
group.add(mesh);
scene.add(group);
I have a lot of these shapes that build together a closed surface.
Any suggestion?
Thank you for your attention.
Have a nice day.

As you pointed out, there are 2 ways to achieve that :
use a 3D triangulation algorithm (not provided by Three.js) ;
use the 2D triangulation algorithm normally used for Three.js Shape objects with some transformation applied upon each face of the geometry.
The last one seems cool but unfortunately, as I tried out I realized it's not that trivial. I came up with something similar to what Paul-Jan said :
For each face of your geometry :
Compute the centroid the face ;
Compute the face normal ;
Compute the matrix of the face ;
Project the 3D points onto the 2D plane of the face ;
Create the geometry (triangulated with the Shape triangulation algorithm) ;
Apply the face matrix to the newly created geometry
Create a Mesh and add it to an Object3D (I tried to merged all the geometries into 1, but it fails with the ShapeBufferGeometry)
Check this fiddle.
Be careful to the winding order of your vertices or put the THREE.Material.side to THREE.DoubleSide to prevent faces from being culled.

I think you might want to revisit the Three.js documentation, and the Shape object in particular. The sample code on that page uses bezierCurveTo, but if you use lineTo in stead you can feed it your sequences of points and create concave polygons (including holes).

Related

Three.jsMesh Matrixworld does not update

Good morning, I am trying to orient subpanels on each plane, but seems that using the method that I used to create the mesh(planes) the matrix and matrixWorld does not update. I need to "update" each plane Matrix to be able to translate and rotate the subplanes accordantly. Below I am adding a picture with the steps of geometry generation. I am using BufferGeometry to create the vertices of the panels, and then triangulating them to create the meshes. Below I am including an image with the step-by-step.
Any help would be helpful!
Step by step - geometry generation
In the end, I figured it out. I built the transformation matrix4 directly from corner vectors. Maybe it can be useful for someone (code below):
let vX = new THREE.Vector3(ndes[3][0] - ndes[0][0], ndes[3][1] - ndes[0][1], ndes[3][2] - ndes[0][2]).normalize(),
vY = new THREE.Vector3(ndes[1][0] - ndes[0][0], ndes[1][1] - ndes[0][1], ndes[1][2] - ndes[0][2]).normalize(),
vZ = new THREE.Vector3().crossVectors(vX, vY).normalize();
let matrix = new THREE.Matrix4();
matrix.set( vX.x, vY.x, vZ.x, ndes[0][0],
vX.y, vY.y, vZ.y, ndes[0][1],
vX.z, vY.z, vZ.z, ndes[0][2],
0, 0, 0, 1);
panels.applyMatrix4( matrix );
paneling surfaces

Can I skip the normal syntax and work with geometry buffers in three.js for faster performance?

I'm new to the area of geometry generation and manipulation and I'm planning on doing this on an intricate and large scale. I know the basic way of doing this is like it's shown in the answer to this question..
var geom = new THREE.Geometry();
var v1 = new THREE.Vector3(0,0,0);
var v2 = new THREE.Vector3(0,500,0);
var v3 = new THREE.Vector3(0,500,500);
geom.vertices.push(v1);
geom.vertices.push(v2);
geom.vertices.push(v3);
geom.faces.push( new THREE.Face3( 0, 1, 2 ) );
geom.computeFaceNormals();
var object = new THREE.Mesh( geom, new THREE.MeshNormalMaterial() );
object.position.z = -100;//move a bit back - size of 500 is a bit big
object.rotation.y = -Math.PI * .5;//triangle is pointing in depth, rotate it -90 degrees on Y
scene.add(object);
But I do have experience with doing image manipulation working directly with a typed array image buffer on the GPU which is essentially the same thing as manipulating 3D points, since colors are essentially 3D points on a 2D grid (in the case of a buffer, flattened out to a 1D typed array) and I know just how much faster that kind of large scale manipulation is when processed with shaders on the GPU.
So I'm wondering if I can access the geometry in three.js directly as a typed array buffer. If so, I can use gpu.js to manipulate it on the GPU rather than CPU and boost performance exponentially.
Basically I'm asking if there's something like canvas's getImageData method for three.js geometry.
As ThJim01 mentioned in the comment, THREE.BufferGeometry is the way to go, but if you insist on using THREE.Geometry to initialize your list of triangles, you can use the BufferGeometry.fromGeometry function to generate the BufferGeometry from the Geometry you originally made.
var geometry = new THREE.Geometry();
// ... initialize verts and faces ...
// Initialize the BufferGeometry
var buffGeom = new THREE.BufferGeometry();
buffGeom.fromGeometry(geometry);
// Print the typed array for the position of the vertices
console.log(buffGeom.getAttribute('position').array);
Note that the resultant geometry will not have an index array and just be a list of disjointed triangles (as it was represented as in the first place!)
Hope that helps!

Dynamically adding faces to a three.js geometry

I'm working on some webgl software for generating 3D models and am relying on dynamic geometry. I've observed some very bizarre behavior that I've been able to isolate in this jsfiddle.
It seems that any new faces added after a geometry instance has been added to the scene, any new faces added will not be rendered (properly). In wireframe mode (as in the example), the new geometry is not rendered at all. When using textured materials, I also observed that sometimes new geometry is not rendered depending on the angle of the camera.
Here's a video of that in action.
Back to the jsfiddle, I used an existing three.js code sample (misc_exporter_obj.html) as a scaffold but on line 7 I made a generic function to add a triangle to the geometry. The addGeometry function is called on startup, and if you uncomment line 36 you can see what the expected result should have been:
var material = new THREE.MeshBasicMaterial( { wireframe : true} );
geometry = new THREE.Geometry();
addTriangle(-50, -50, 50, -50, 50, 50);
//addTriangle(-50, -50, -50, 50, 50, 50); // UNCOMMENT TO TEST WHAT FINAL OUTPUT SHOULD LOOK LIKE.
scene.add( new THREE.Mesh( geometry, material ) );
And as per the threejs guide on how to update things, lines 43-47 attempt to add a new triangle when you click the "transform triangle" button by setting the verticesNeedUpdate and elementsNeedUpdate flags:
function addTriangleFace(){
addTriangle(-50, -50, -50, 50, 50, 50);
geometry.verticesNeedUpdate = true;
geometry.elementsNeedUpdate = true;
}
Am I doing this wrong? Or should I submit a bug report?
Thanks.
Disappearing Mesh Update:
I may have discovered the cause of the weird behavior that was causing my mesh to be erased based on camera orientation. This answer suggests that Three.js may have thought that the mesh was not inside the camera's frustum.
I'm guessing the new vertices were not being considered when trying to determine whether the object was in the frustum, so I just disabled culling since the object being drawn is the main object in the scene.
You want to add faces to an existing geometry.
Since buffers can't be resized, the best solution is to switch to BufferGeometry, preallocate sufficiently-sized buffers, and set the drawRange. See this SO answer. This answer, too.
If you add vertices, you will need to recompute the bounding sphere for frustum culling to work correctly.
geometry.computeBoundingSphere();
Or, as you said, you can disable frustum culling:
mesh.frustumCulled = false;
three.js.r.91

Putting a particle on the upper side of a mesh at a random point?

I want to put a particle on the upper side of a mesh. I have seen several tutorials to add particles. but in all the tutorials I've seen only it works when they cubes or spheres. in this case I have a custom mesh. and nothing works for me what I do to put even one particle in the geometry of the mesh. How I can do to put a particle on the upper side of a mesh at a random point ?.
var extrusionSettings = {
bevelEnabled: false,
extrudeMaterial: 1, amount:3,
};
var Hexagon=new Array();
Hexagongeometry[0]= new Array();
Hexagongeometry[0].push(new THREE.Vector3(-3, 0.0, 0.0));
Hexagongeometry[0].push(new THREE.Vector3( -3, 3, 0.0));
Hexagongeometry[0].push(new THREE.Vector3( 0, 5, 0.0));
Hexagongeometry[0].push(new THREE.Vector3( 3, 3, 0.0));
Hexagongeometry[0].push(new THREE.Vector3( 3, 0, 0.0));
Hexagongeometry[0].push(new THREE.Vector3( 0, -3, 0.0));
Hexagongeometry[0].push(new THREE.Vector3( -3, 0, 0.0));
var HexagonShape=new Array();
HexagonShape[0] = new THREE.Shape( Hexagongeometry[0] );
var HexagonExtrude=new Array();
HexagonExtrude[0] = new THREE.ExtrudeGeometry( HexagonShape[0], extrusionSettings );
var material=new Array();
material[0] = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
var Hexagon=new Array();
Hexagon[0] = new THREE.Mesh( HexagonExtrude[0],material[0] );
scene.add(Hexagon[0]);
var particleMaterial = new THREE.ParticleBasicMaterial({ size: 2, color: 0xff0000, transparency: true, alphaTest: 0.5 });
var particle = new THREE.ParticleSystem( HexagonExtrude[0], particleMaterial );
scene.add( particle);
It does not work I put the particle in any part of my mesh. in this example I would put in hexagon [0] which is a mesh. I have tried many ways, and I've seen several tutorials but as I said before, it only works if I apply to a cube or sphere. if I can help get the particle at a point of serious mesh helpful. then you need to know how to achieve various particles in locating random points in my mesh.
I am new to Three.js, and I do not speak good English. I hope you understand.
http://jsfiddle.net/6z8f3eq3/
Let's divide the problem a bit to find a solution.
For an arbitrary mesh, you will need to select a random polygon, a point on that polygon, and one that will be "above" that polygon, which means that you will need to have a sense of which way the polygon is facing. There is more than one way to do each of these steps, and which is "best" will depend somewhat on the nature of your mesh and the nature of your purpose.
Consider the first part: selecting a polygon. You could select polygon [n] by just using the list. But what if your mesh has a mix of huge and tiny polygons? You might want to prefer the big ones. So: one set of choices.
Consider next the second part: a random point on the polygon. This is probably easiest if you have only triangles, Try using barycentric coordinates as a start. They are very easy to apply and give good distributions (there are others possible, of course!).
Finally, the last part: if your mesh has surface normals, just add some fraction of the surface normal to the point you found in the previous step. If you have face normals this will give a different distribution than smooth normals. You may also, as a later refinement, want to use raycasts to avoid intersecting your offsets with other neighboring polygons (depending on the shape of your mesh).
When in doubt, just try the simplest version of these three steps, and use them as points of departure for greater refinement.
Sorry I can't just hand you code, but a verbal description is best for this sort of question. Good luck!

Three.js - ExtrudeGeometry using depth and a direction vector

I want to extrude a shape and create an ExtrudeGeometry, but the shape has to be extruded into a certain direction. I have a direction in a Vector3
The shape is drawn in in the x, y plane and normally the z is the extrude direction (extrusion depth). So a direction vector (0,0,1) would result in the default extrusion. But for example a (0,0,-1) would extrude the shape in the other direction.
I first tried to use an extrude path to achieve this, but when using a path the shape is allowed to "spin" freely and the initial orientation is arbitrary. This is not what I need, the shape must stay oriented as is. You can read details on this here in my previous question.
I already came up with the idea of applying a matrix to the second half of the vertices of the resulting ExtrudedGeometry, but I cannot seem to get the geometry I want. Maybe it is my clumsy use of matrices, but I think that the face normals are pointing inside out after this trick.
Note The direction vector will never be orthogonal to the z axis since this would give invalid shapes
So the question:
How do I get a reliable solution to extrude my shape into the given direction. Here an example. The shape is a square in the x,y plane (width and length 2000) the extrusion depth is also 2000 and three different vectors with a drawing of the expected result seen in 2D (front view) and 3D.
Extrude your geometry in the usual way by specifying an extrusion depth, and then apply a shear matrix to your geometry.
Here is how to specify a shear matrix that will tilt a geometry.
var matrix = new THREE.Matrix4();
var dir = new THREE.Vector3( 0.25, 1, 0.25 ); // you set this. a unit-length vector is not required.
var Syx = dir.x / dir.y,
Syz = dir.z / dir.y;
matrix.set( 1, Syx, 0, 0,
0, 1, 0, 0,
0, Syz, 1, 0,
0, 0, 0, 1 );
geometry.applyMatrix4( matrix );
(The three.js coordinate system has the y-axis up -- unlike in your illustration. You will have to accommodate.)
three.js r.113

Categories

Resources