Can this mesh volume calculation algorithm handle imperfect meshes? - algorithm

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 :/.

Related

Minimizing QUAD count of a 3D mesh

Given a disorderly array of miniature quad polygons on a 2D plane, What are some of the best ways of grouping them into larger quads?
Currently i am writing the quads into a boolean array so that i can fast access all neighbor values of a given quad, and construct logical grouped squares and rectangles containing many neighbor squares.
var BoolGrid: new Boolean[100x100];
function CheckNeighbor (x, y){return BoolGrid(x + y*100 );}
Do you have a logical process to group quads? Reverse Octree? Spiral around starting point? flexible conditions to find multiple optimal large squares that contain a starting square?
It's quite a fun and challenging computing challenge similar to rubix, please share any thoughts on the topic. Here's an example where it's been done wrong:
ill add another pic while it's on the pc: free program from thingiverse optimized quads. only other program i know does this is 3dsmax at 1000USD!

Is this Transform possible using a Matrix?

I'm trying to take a static list of vertices and, using a matrix, bend them about a circle as shown in the image below. I can find the new vertices using basic geometry, but I'm unsure how to implement it with a matrix, or if it is even possible. I believe, calling the center of the circle 'C' and calling the distance from the vertex to C 'd', that x' = Cx + d*cos(theta) and y' = Cy + d*sin(theta). (Cx and Cy are components of C). However, I don't think that that, in itself, can be converted to a matrix.
The Transformation
For context, I'm making a 3D Snake game. The Snake is made up of segments, and each segment should connect to the next. I have a direction and position for each connection between the segments, so I figured that I could build the segment by connecting each part as shown. However, it would be inefficient to calculate the vertices for each segment on each frame. If I could have the vertices statically listed and then transform it in the model-world matrix, that would be faster, and fit into the method I'm currently using. I included a simple drawing of the Snake (ignore the head) below.
The Snake
If it's not possible, are there any alternatives that can be done using a matrix while giving a similar result?
Yes, it is possible.
Skeleton Animation:
You can actually add a series of bones to the object and just apply rotation to the bones equally to get a perfect curve. This is the easiest way to achieve this. However, not necessarily the fastest way for your case.
Just Matrix & Weights:
If the bending is always in this proportion, you have to add weight information to each vertex and then multiply with a matrix with transformation/rotation/scale combination. This will give you better performance compared to Skeleton animation, as every vertex is multiplied using only one matrix and there is no hierarchy.

Draw Quadratic Curve on GPU

My task is to render quadratic Bezier curve (path) via Stage3d (Adobe Flash) technology, which have no any extensions for that drawing out-of-the box (while OpenGl have it, as I know). Yea, there is a Starling-Extension-Graphics, but it uses simple method to divide a curve segment to many straight lines, that generates very many triangles for my long curve path.
So.. There is a perfect way for rendering resolution independed shapes for Loop and Blinn. I've read GPUGems3 article (gpugems3_ch25.html)
and ported that fragment shader to AGAL2:
Quadratic Curve Pixel Shader
float4 QuadraticPS(float2 p : TEXCOORD0,
float4 color : COLOR0) : COLOR
{
// Gradients
float2 px = ddx(p);
float2 py = ddy(p);
// Chain rule
float fx = (2*p.x)*px.x - px.y;
float fy = (2*p.x)*py.x - py.y;
// Signed distance
float sd = (p.x*p.x - p.y)/sqrt(fx*fx + fy*fy);
// Linear alpha
float alpha = thickness - abs(sd);
if (alpha > 1) // Inside
color.a = 1;
else if (alpha < 0) // Outside
clip(-1);
else
// Near boundary
color.a = alpha;
return color;
}
It works. But there are two fundamental problems:
I don't understand that algorithm :(. I read about signed distance field, derivates and other... I thought a lot of hours and read again - but no result! My question is: Does anyone help me and explain what happens in that shader (line by line (!), if it possible)?
The second problem is that the curve is clipped at the corner of triangle and has a variable thickness. Please look at the picture:
https://monosnap.com/file/84EBOuQ1czNM5lprQ5VlnRUKP2mKmW
So if I draw a path it looks like this: https://monosnap.com/file/54Zs5Xui6s3BL6lNdZRCx9ibcV2bCF
I like that method by using one triangle per curve segment, because no any geometry needed. And I don't need to have very thick curves (1-2 px is excellent), but a variable thickness is a problem. Can anybody help me?
(Sorry for my English. It is not my native language.)
[edit1 by Spektre] just moved from comment and invalid answer
I plan to use one triangle per one curve segment, something like on the picture
the path consists from many triangles
one per one path segment (quadratic curve)
How to handle issue with this approach if all control points are collinear (lie on the same straight) or nearly collinear?
For 3 control point Bezier curves I would:
use triangles as primitives
enlarge control points to include area around curve to avoid artifacts
This way is fast and there is no problem to compute A',B',C' from A,B,C and vice versa. If the scale is constant (for example scale=1.25) then the max usable curve thickness<=2.0*min(|control_point-M|)*(scale-1.0).
For safer enlargement you can compute exact scale needed (for example in geometry shader) and pass it to vertex and fragment ... All of above can be done by Geometry shader. You should use transparency to correctly join the curves together. The average middle point should stay the same M=A+B+C=A'+B'+C'
if transparency is not an option
Then you need to change the approach so pass control points and position inside textures.
create one 2D float texture with control points
something like float pnt[9][N]
pnt[0,1,2][] is control point A(x,y,z)
pnt[3,4,5][] is control point B(x,y,z)
pnt[6,7,8][] is control point C(x,y,z)
also create 1D color texture
something like rgba col[N]
The x axis resolution of both textures = N is the number of Bezier curves
now draw single Quad covering entire screen
And inside fragment shader check if pixel is inside any of the curve. If yes output its color ...
This can get very slow for high Bezier curve count N
[edit1] almost collinear control points
for those I would use Quads
D,E are mirrored points A,B around C
D=C+C-A
E=C+C-B
C is the middle point M = (A+B+D+E)/4 = C = (A'+B'+C'+D')/4
and A',B',C',D' are enlarged A,B,D,E control points
A'=C+(A -C)*scale
B'=C+(B -C)*scale
A =C+(A'-C)/scale
B =C+(B'-C)/scale
This can be used for any Bezier not just almost colinear but it uses larger polygons so it will be slower on performance (more fragments then really needed)
Here more advanced/optimized GLSL approach with complete implementation of cubic BEZIER curves:
rendering 2D cubic BEZIER with GLSL

Generating points uniformly on a sphere

I'm interested in generating points that are 'uniformly' (and non-randomly) distributed around a sphere, much like the dimples of a golf ball or the vertices of the hexagons on a soccer ball. Are there well defined algorithms to do this?
Note: I know that the points are not really 'uniformly' distributed on a sphere, but they are distributed in a way that the distribution of points looks the same from any direction that looks straight at any of the points - this is what I am interested in.
Subdividing an octahedron and normalizing the vertices afterwards gives very good results. Look here for more details. Paul Bourke has a lot of interesting stuff.
Here's some psuedo C++ code I wrote up in five minutes now:
/* Assume 'data' initially holds vertices for eight triangles (an octahedron) */
void GenerateSphere(float radius, std::vector<Vector3f>& data, int accum=10)
{
assert( !(data.size() % 3) );
std::vector<Vector3f> newData;
for(int i=0; i<data.size(); i+=3){
/* Tesselate each triangle into three new ones */
Vector3f centerPoint = (data[i] + data[i+1] + data[i+2]) / 3.0f;
/* triangle 1*/
newData.push_back(data[i+0]);
newData.push_back(data[i+1]);
newData.push_back(centerPoint);
/* triangle 2*/
newData.push_back(data[i+1]);
newData.push_back(data[i+2]);
newData.push_back(centerPoint);
/* triangle 3*/
newData.push_back(centerPoint);
newData.push_back(data[i+2]);
newData.push_back(data[i+0]);
}
data = newData;
if(!accum){
/* We're done. Normalize the vertices,
multiply by the radius and return. */
for(int i=0; i<data.size(); ++i){
data[i].normalize();
data[i] *= radius;
}
} else {
/* Decrease recursion counter and iterate again */
GenerateSphere(radius, data, accum-1);
}
return;
}
This code will work with any polyhedron made of counter-clockwise triangles, but octahedrons are best.
Choose u,v randomly from [0,1].
2πu is longitude.
asin(2v-1) is latitude.
Only two random variables, and no rejections.
By the way, my link collection has a new address: http://bendwavy.org/sphere.htm
And I've copied it over to http://cgafaq.info/wiki/Evenly_distributed_points_on_sphere
While this article talks about randomly picking points on a sphere, it is also about drawing points from a uniform distribution while at the same time taking the sphere characteristic into consideration. I guess it's still a decent read for your question:
http://mathworld.wolfram.com/SpherePointPicking.html
depending on your needs http://iquilezles.untergrund.net/www/articles/patchedsphere/patchedsphere.htm
may work well too. not exactly uniform, but very fast to compute.
Here's a simple way to do it.
Randomly, sample from the unit cube, [0, 1]^3
Test for inclusion in the sphere. Reject if the sampled point is not in the sphere of diameter 1 that is contained in the unit cube, and go to step 1.
Normalize the point to be on the surface of the sphere, by projecting the point outward from the center of the sphere.
This will typically succeed after a few samples. If you want, you can also reject samples that are near the center of the sphere to minimize rounding errors and help make the distribution closer to uniform.
if you're okay with having only certain allowable numbers of vertices, then the subdivision methods above are definitely the way to go. if you want an arbitrarily-specified number of vertices, then i recommend:
first, distribute points randomly and uniformly over the sphere.
i talk at length about doing this at http://elenzil.com/progs/randompoints .
i believe my method is at least as performant as that at worlfram.
second, "relax" the distribution by treating the points as a particle system where each particle repels every other particle. the difficulty here is making sure the system doesn't become unstable, and deciding when to stop. i have an example of this here: http://elenzil.com/progs/separate unfortunately these were the days before i included source code with my projects, so that code is lost.
I tried once the following algorithm:
start with a regular tetrahedron with the submits on the sphere.
pick one of the triangles with the biggest surface (initially it will be any of the 4 sides)
replace selected face with a 3 sided pyramid where the 4th point is the elevation of the face center to the sphere surface.
repeat until enough points have been created.
This works as long as precision does not ruin uniformity.
The resulting points form figures akin to a geode.
You don't need to compute any surface, since each new triangle is no greater than all previous ones. Simply handle them in FIFO order.

Constructive solid geometry mesh

If I construct a shape using constructive solid geometry techniques, how can I construct a wireframe mesh for rendering?
I'm aware of algorithms for directly rendering CSG shapes, but I want to convert it into a wireframe mesh just once so that I can render it "normally"
To add a little more detail. Given a description of a shape such as "A cube here, intersection with a sphere here, subtract a cylinder here" I want to be able to calculate a polygon mesh.
There are two main approaches. If you have a set of polygonal shapes, it is possible to create a BSP tree for each shape, then the BSP trees can be merged. From Wikipedia,
1990 Naylor, Amanatides, and Thibault
provide an algorithm for merging two
bsp trees to form a new bsp tree from
the two original trees. This provides
many benefits including: combining
moving objects represented by BSP
trees with a static environment (also
represented by a BSP tree), very
efficient CSG operations on polyhedra,
exact collisions detection in O(log n
* log n), and proper ordering of transparent surfaces contained in two
interpenetrating objects (has been
used for an x-ray vision effect).
The paper is found here Merging BSP trees yields polyhedral set operations.
Alternatively, each shape can be represented as a function over space (for example signed distance to the surface). As long as the surface is defined as where the function is equal to zero, the functions can then be combined using (MIN == intersection), (MAX == union), and (NEGATION = not) operators to mimic the set operations. The resulting surface can then be extracted as the positions where the combined function is equal to zero using a technique like Marching Cubes. Better surface extraction methods like Dual Marching Cubes or Dual Contouring can also be used. This will, of course, result in a discrete approximation of the true CSG surface. I suggest using Dual Contouring, because it is able to reconstruct sharp features like the corners of cubes .
These libraries seems to do what you want:
www.solidgraphics.com/SolidKit/
carve-csg.com/
gts.sourceforge.net/
See also "Constructive Solid Geometry for Triangulated Polyhedra" (1990) Philip M. Hubbard doi:10.1.1.34.9374
Here are some Google Scholar links which may be of use.
From what I can tell of the abstracts, the basic idea is to generate a point cloud from the volumetric data available in the CSG model, and then use some more common algorithms to generate a mesh of faces in 3D to fit that point cloud.
Edit: Doing some further research, this kind of operation is called "conversion from CSG to B-Rep (boundary representation)". Searches on that string lead to a useful PDF:
http://www.scielo.br/pdf/jbsmse/v29n4/a01v29n4.pdf
And, for further information, the key algorithm is called the "Marching Cubes Algorithm". Essentially, the CSG model is used to create a volumetric model of the object with voxels, and then the Marching Cubes algorithm is used to create a 3D mesh out of the voxel data.
You could try to triangulate (tetrahedralize) each primitive, then perform the boolean operations on the tetrahedral mesh, which is "easier" since you only need to worry about tetrahedron-tetrahedron operations. Then you can perform boundary extraction to get the B-rep. Since you know the shapes of your primitives analytically, you can construct custom tetrahedralizations of your primitives to suit your needs instead of relying on a mesh generation library.
For example, suppose your object was the union of a cube and a cylinder, and suppose you have a tetrahedralization of both objects. In order to compute the boundary representation of the resulting object, you first label all the boundary facets of the tetrahedra of each primitive object. Then, you perform the union operation: if two tetrahedra are disjoint, then nothing needs to be done; both tetrahedra must exist in the resulting polyhedron. If they intersect, then there are a number of cases (probably on the order of a dozen or so) that need to be handled. In each of these cases, the volume of the two tetrahedra needs to be re-triangulated in a way that respects the surface constraints. This is made somewhat easier by the fact that you only need to worry about tetrahedra, as opposed to more complicated shapes. The boundary facet labels need to be maintained in the process so that in the final collection of tetrahedra, the boundary facets can be extracted to form a triangle mesh of the surface.
I've had some luck with the BRL-CAD application MGED where I can construct a convex polyhedron by intersecting planes using CSG then extract the boundary representation using the command-line g-stl command. Check http://brlcad.org/
Malcolm
If you can convert you input primitives to polyhedral meshes then you could use libigl's C++ mesh boolean routines. The following computes the union of a mesh (VA,FA) and another mesh (VB,FB):
igl::mesh_boolean(VA,FA,VB,FB,"union",VC,FC);
where VA is a #VA by 3 matrix of vertex positions and FA is a #FA by 3 matrix of triangle indices into VA, and so on. The technique used in libigl is different from those two mentioned in Joe's answer. All pairs of triangles are intersected against each other (using spatial acceleration) and then resulting sub-triangles are categorized as belonging to the output surface or not.

Resources