As per this answer, I read this research paper (very brief). To quote the answer:
This all boils down to the following simple function:
public float SignedVolumeOfTriangle(Vector p1, Vector p2, Vector p3) {
var v321 = p3.X*p2.Y*p1.Z;
var v231 = p2.X*p3.Y*p1.Z;
var v312 = p3.X*p1.Y*p2.Z;
var v132 = p1.X*p3.Y*p2.Z;
var v213 = p2.X*p1.Y*p3.Z;
var v123 = p1.X*p2.Y*p3.Z;
return (1.0f/6.0f)*(-v321 + v231 + v312 - v132 - v213 + v123);
}
and then a driver to calculate the volume of the mesh:
public float VolumeOfMesh(Mesh mesh) {
var vols = from t in mesh.Triangles
select SignedVolumeOfTriangle(t.P1, t.P2, t.P3);
return Math.Abs(vols.Sum());
}
This seems much better than the voxel based approach for determining volume of an advanced 3D object, however, in the models I currently have available to me:
Many of the surfaces are not complete 3D voluminous shapes, but rather hollow 2D meshes wrapped into a 3-D looking shape where the ends don't actually meet up to form a complete surface of a true 3D object.
Some surfaces are outright flat 2D shapes.
Are just plain messy internally.
And I'm unsure about how the algorithm will handle imperfect 3D models.
Do I need to produce models which are made up only of true, complete, voluminous 3D objects for this method to work, or will it work on common 3D models as shown above?
The method you've found works by iterating over all triangles, for each triangle it connects its corners with (0,0,0) point making a tetrahedron. Then it computes its volume and sum up all the results. The signed word used here means that some tetrahedrons will have negative volume, based on triangle facing. Thanks to this trick overlapping tetrahedrons will cancel out each other.
If you have correct mesh it just works, but your imperfect mesh is basically a perfect one but with few triangles missing, so you'll miss some of your tetrahedrons in your final sum. Statistically some of them are positive volumes and some are negative ones, so this will also cancel out to some extent.
The more triangles you lack and/or the bigger they get then the more error you'll get in computed volume value, but the algorithm won't break or explode, just loose precision.
There's also another problem with this approach:
When you have two perfectly closed cube meshes that are overlapping each other this algorithm will compute the sum of their volumes, not the volume of the shape they've created. We don't know much about your models but I'd consider it a bigger problem than non-closed mesh.
To solve this you'd need to do CSG Union operation, but it works only for closed meshes :/.
I am attempting to use Three.js to morph one geometry into another. Here's what I've done so far (see http://stemkoski.github.io/Three.js/Morph-Geometries.html for a live example).
I am attempting to morph from a small polyhedron to a larger cube (both triangulated and centered at the origin). The animating is done via shaders. Each vertex on the smaller polyhedron has two associated attributes, its final position and its final UV coordinate. To calculate the final position of each vertex, I raycasted from the origin through each vertex of the smaller polyhedron and found the point of intersection with the larger cube. To calculate the final UV value, I used barycentric coordinates and the UV values at the vertices of the intersected face of the larger cube.
That led to a not awful but not great first attempt. Since (usually) none of the vertices of the larger cube were the final position of any of the vertices of the smaller polyhedron, big chunks of the surface of the cube were missing. So next I refined the smaller polyhedron by adding more vertices as follows: for each vertex of the larger cube, I raycasted toward the origin, and where each ray intersected a face of the smaller polyhedron, I removed that triangular face and added the point of intersection and three smaller faces to replace it. Now the morph is better (this is the live example linked to above), but the morph still does not fill out the entire volume of the cube.
My best guess is that in addition to projecting the vertices of the larger cube onto the smaller polyhedron, I also need to project the edges -- if A and B are vertices connected by an edge on the larger cube, then the projections of these vertices on the smaller polyhedron should also be connected by an edge. But then, of course it is possible that the projected edge will cross over multiple pre-existing triangles in the mesh of the smaller polyhedron, requiring multiple new vertices be added, retriangularization, etc. It seems that what I actually need is an algorithm to calculate a common refinement of two triangular meshes. Does anyone know of such an algorithm and/or examples (with code) of morphing (between two meshes with different triangularizations) as described above?
As it turns out, this is an intricate question. In the technical literature, the algorithm I am interested in is sometimes called the "map overlay algorithm"; the mesh I am constructing is sometimes called the "supermesh".
Some useful works I have been reading about this problem include:
Morphing of Meshes: The State of the Art and Concept.
PhD. Thesis by Jindrich Parus
http://herakles.zcu.cz/~skala/MSc/Diploma_Data/REP_2005_Parus_Jindrich.pdf
(chapter 4 especially helpful)
Computational Geometry: Algorithms and Applications (book)
Mark de Berg et al
(chapter 2 especially helpful)
Shape Transformation for Polyhedral Objects (article)
Computer Graphics, 26, 2, July 1992
by James R. Kent et al
http://www.cs.uoi.gr/~fudos/morphing/structural-morphing.pdf
I have started writing a series of demos to build up the machinery needed to implement the algorithms discussed in the literature referenced above to solve my original question. So far, these include:
Spherical projection of a mesh # http://stemkoski.github.io/Three.js/Sphere-Project.html
Topological data structure of a THREE.Geometry # http://stemkoski.github.io/Three.js/Topology-Data.html
There is still more work to be done; I will update this answer periodically as I make additional progress, and still hope that others have information to contribute!
Normal marching cubes finds 12 edges per cube, but you can do 3 edges per cube, save the edges inside an array, and then go through the cubes again, referencing the edges from the cubes adjacent rather than calculating them.
The process to reference adjacent cubes isn't clearly discussed on the Internet so anyone using marching cubes would be welcome to help find the details of the solution. do you know an implementation already?
here is a picture showing the 3 edges in yellow that you need for each cube, instead of 12.
EDIT- I just found this solution, although it's just a part of it:
Imagine 3 edges coming from the corner of the cube with lowerest coordinates. Then all other edges just belong to other cubes. If our cube has coordinates (x,y,z), the neiboring cubes have coordinates (x+1,y,z), (x,y+1,z), (x,y,z+1), (x+1,y+1,z), (x+1,y,z+1), (x,y+1,z+1). You can imagine the edge as a vector. Then the corner of the cube have edges (1,0,0), (0,1,0), (0,0,1). The cube with coordinates (x+1,y,z) have edges (0,1,0) and (0,0,1) that belong to our cube. The cube (x+1,y+1,z) has only one edge (0,0,1) that belongs to our cube. So if you store 4 elements for the cube you can access them like that:
edge1 = cube[x][y][z][0];
edge2 = cube[x][y][z][1];
edge3 = cube[x][y][z][2];
edge4 = cube[x+1][y][z][1];
edge5 = cube[x+1][y][z][2];
edge6 = cube[x][y+1][z][0];
edge7 = cube[x][y+1][z][2];
edge8 = cube[x][y][z+1][0];
edge9 = cube[x][y][z+1][1];
edge10 = cube[x+1][y+1][z][2];
edge11 = cube[x+1][y][z+1][1];
edge12 = cube[x][y+1][z+1][0];
Now which points edge7 connect? The answer is (x,y+1,z) and (x,y+1,z)+(0,0,1)=(x,y+1,z+1).
Now which cubes edge7 connect? It is more harder. We see that coordinate z is changes along the edge this means that neibour cube has the same z coordinate. Now all others coordinates change. Where we have +1, the cube has large coordinate. Where we have +0, the cube has smaller coordinates. So the edge connects cubes (x,y,z) and (x-1,y+1,z). Other 2 cubes that has the same edge are (x,y+1,z) and (x-1,y,z).
-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=--=-=
EDIT2-
So I am doing this, and it isn't so simple. I have a loop which simultaneously calculate 8 points, 12 edges, the interpolation of edges, the bit values and a vertex the values for the edges, all in one loop.
so I am doing a new loop previous to it to calculate as much as possible and place it in arrays to used in the complicated loop.
I can recycle the interpolated values of the intersection points along edges, in an array, although I will have to recalculate all the points again in the complicated loop, because the values of the points I used to decide bit numbers that reference values in the vertex table. That confuses me! I thought that once I have the edge intersection values, I could use those directly to get the triangle tables, without having to calculate the points all over again!
in fact no.
anyway, here is another bit of information with someone that already did it, if only it was readable!
http://www.new-npac.org/projects/sv2all/sv2/vtk/patented/vtkImageMarchingCubes.cxx
scroll to this line: Cubes are responsible for edges on their min faces.
A simple way to reduce edge calculations in the way you are suggesting is to compute cubes one axis aligned plane at a time.
If you kept all of the cubes, with their edges, in memory, it would be easy to compute each edge only once and to find adjacent edges by indexing. However, you usually don't want to keep all the cubes in memory at once because of the space requirements.
A solution to this is to compute one plane of cubes at a time. i.e. an axis aligned cross-section, starting from one side and progressing to the opposite side. You then only need to keep at most two full planes of cubes in memory at a time. As you move through each plane you can reference shared edges in the previous plane and previously computed cubes in the current plane. As you move to the next plane you can deallocate the plane you will no longer need.
Edit: This article discusses doing just what I suggest:
http://alphanew.net/index.php?section=articles&site=marchoptim&lang=eng
Funny, because when I implemented my own MCs I came up with similar solution.
When you start working with MCs you treat them as a distinct cubes but if you want to go for high performance you'll need to create entire mesh as a whole, and creating vertex indices etc. is not so easy here. It gets even more interesting when you want to add smooth per-vertex normals :).
To solve this I created a simple index cache mechanism to store vertex indices for each edge.
Then, for each computed edge I have cube position x,y,z and edge index and I do as follows:
For each axis:
if the edge is on '+' side of axis:
replace edge index with its '-' side sibling
increment cube position along axis
This simple operation gives me the correct cube position, and edge index of 0,1,2. Then I compute a total cache index from x,y,z,edgeIndex values with simple bit rotations.
When I have cache index I check if it's bigger than -1. If it is then there was an already computed vertex at this edge and I can reuse it. If it's -1 I need to create a new vertex and store its index in the cache. This way you'll compute each vertex only once, and you can even add a normal value shared between every triangle containing your vertex.
Yes, I think I do it similar to kolenda. I have a struct with 5 ints: (cube)index and 4 vertexindices (A, B, C, D).
for the most inner loop (x), I have just lastXCache and nextXCache. On the 4 edges pointing in the -x direction, i ask if lastXCache.A != -1 and if so, assign the previously calculated value, etc.
In the +x direction I store calculated vertices in nextXCache. when cube is done: lastXCache = nextXCache;
For y and z direction it needs to be a list (unity term for mutable array), next y is next row (so sizex) and next z is the next plane (so sizex * sizey)
only diadvantage is that this way it has to run cube after cube, so serially. But you can calculate different chunks in parallel.
Another way I thought of that could be more parallel would need 2 passes: 1. calculate 3 edges every cube, when 1 is done -> 2. draw the triangles.
Don't really know what is better, but the way it actually works seems to be fast enough. even better with unity jobs. Create one IJob for 1 chunk/mesh.
I am looking for a method / algorithm that will allow me to merge several adjacent coplanar faces on a 3d mesh into a single face. I am hoping that this will optimize my mesh generation program, because right now it generates many 'little' triangles. When I look at the final 3d object on the screen, I can see that they all are oriented in the same direction and they could be replaced with one bigger triangle that encompasses the whole lot! I hope that is clear what I am trying to do. Thanks for your help.
I would suggest you project the faces in a single plane and than apply an algorithm for polygon uninon a plane. After that "unproject" and that's it. Always try to reduce dimensions when possible.
Your task is a special case of mesh simplification (or decimation), where the algorithm is only allowed to reduce some mesh elements without introducing any error in object's shape. And probably the most famous algorithm here is Surface Simplification Using Quadric Error Metrics.
It searches for edges in the mesh that can be contracted in a single vertex (which position is automatically selected for each edge) so that it minimizes quadratic error associated with that contraction (in your case the error is zero).
Let us consider a simple example of cube's face subdivided in 8 triangles:
Left: magenta edge is selected for contraction, remaining vertex will be located in the bottom point of the edge.
Center: after the first contraction, next magenta edge is selected, after contraction it will become a vertex in cube's corner.
Right: the final result of simplification (after contractions on other cube's faces as well), where no more coplanar triangles can be merged (at least in larger triangles).
The illustration above was prepared in MeshInspector application.
What is a fast algorithm for determining whether or not a point is inside a 3D mesh? For simplicity you can assume the mesh is all triangles and has no holes.
What I know so far is that one popular way of determining whether or not a ray has crossed a mesh is to count the number of ray/triangle intersections. It has to be fast because I am using it for a haptic medical simulation. So I cannot test all of the triangles for ray intersection. I need some kind of hashing or tree data structure to store the triangles in to help determine which triangle are relevant.
Also, I know that if I have any arbitrary 2D projection of the vertices, a simple point/triangle intersection test is all necessary. However, I'd still need to know which triangles are relevant and, in addition, which triangles lie in front of a the point and only test those triangles.
I solved my own problem. Basically, I take an arbitrary 2D projection (throw out one of the coordinates), and hash the AABBs (Axis Aligned Bounding Boxes) of the triangles to a 2D array. (A set of 3D cubes as mentioned by titus is overkill, as it only gives you a constant factor speedup.) Use the 2D array and the 2D projection of the point you are testing to get a small set of triangles, which you do a 3D ray/triangle intersection test on (see Intersections of Rays, Segments, Planes and Triangles in 3D) and count the number of triangles the ray intersection where the z-coordinate (the coordinate thrown out) is greater than the z-coordinate of the point. An even number of intersections means it is outside the mesh. An odd number of intersections means it is inside the mesh. This method is not only fast, but very easy to implement (which is exactly what I was looking for).
This is algorithm is efficient only if you have many queries to justify the time for constructing the data structure.
Divide the space into cubes of equal size (we'll figure out the size later). For each cube know which triangles has at least a point in it. Discard the cubes that don't contain anything. Do a ray casting algorithm as presented on wikipedia, but instead o testing if the line intersects each triangle, get all the cubes that intersect with the line, and then do ray casting only with the triangles in these cubes. Watch out not to test the same triangle more than one time because it is present in two cubes.
Finding the proper cube size is tricky, it shouldn't be neither to big or too small. It can only be found by trial and error.
Let's say number of cubes is c and number of triangles is t.
The mean number of triangles in a cube is t/c
k is mean number of cubes that intersect the ray
line-cube intersections + line-triangle intersection in those cubes has to be minimal
c+k*t/c=minimal => c=sqrt(t*k)
You'll have to test out values for the size of the cubes until c=sqrt(t*k) is true
A good starting guess for the size of the cube would be sqrt(mesh width)
To have some perspective, for 1M triangles you'll test on the order of 1k intersections
Ray Triangle Intersection appears to be a good algorithm when it comes to accuracy. The Wiki has some more algorithms. I am linking it here, but you might have seen this already.
Can you, perhaps improvise by, maintaining a matrix of relationship between the points and the plane to which they make the vertices? This subject appears to be a topic of investigation in the academia. Not sure how to access more discussions related to this.