Comments and answers for "How would one calculate a 3d Mesh volume in Unity?"
http://answers.unity.com/questions/52664/how-would-one-calculate-a-3d-mesh-volume-in-unity.html
The latest comments and answers for the question "How would one calculate a 3d Mesh volume in Unity?"Comment by RobinopdeBeek on RobinopdeBeek's comment
http://answers.unity.com/comments/1637654/view.html
(For the one interested)
Found the answer! Some models had a backface material which resulted in the script calculating every triangle twice. Once positive and once negative, which is why everything was so close to 0.Tue, 04 Jun 2019 10:54:08 GMTRobinopdeBeekComment by RobinopdeBeek on RobinopdeBeek's comment
http://answers.unity.com/comments/1637390/view.html
(I also take into account the lossyscale of the object btw)Mon, 03 Jun 2019 14:55:14 GMTRobinopdeBeekComment by RobinopdeBeek on RobinopdeBeek's answer
http://answers.unity.com/comments/1637381/view.html
Hi,
Thanks for the code, i've done a lot of calculations with it and most of the time it works. The times that it does'nt work are really weird and I hope you could maybe shed some light as to why.
I got a Sketchup from a colleague and it had a lot of objects. Most of them pretty simple like the one in the picture on the right:
![alt text][1]
When I calculate the right one with your code it gives a volume of 0.000488 m3, even though it's a solid in sketchup and clearly states 12371 m3 in the entity info. I recreated the object (shown on the left) and that one does give the right volume when running the script.
In Sketchup everything seems fine (no holes, no internal faces, no reversed face), but when running the code it still gives a really weird result that is close to 0.
Any idea why this would happen?
It happens with a lot of the objects in the sketchup, but no clear reason why some are correctly calculated and others are close to 0.
(Unfortunately I can't use the Rigidbody.SetDensity method, because the object has a donut shape and that doesn't work with convex shapes.)
[1]: /storage/temp/139374-mesh-volume-error.pngMon, 03 Jun 2019 14:45:21 GMTRobinopdeBeekComment by Bunny83 on Bunny83's answer
http://answers.unity.com/comments/1556520/view.html
Note that this is actually called [the tripple product][1] which calculates the volume of a "parallelepiped". This is made up of 6 equal tetrahedra hence we divide by 6. It can be easily envisioned if one remembers that the length of the vector you get from a cross product is equal to the area of the parallelogram the two vectors describe. The volume of a parallelepiped is just the base times it's height. So we need to project the diagonal length onto the normal of the base surface. That's implicitly done by the dot product since the area vector we get from the cross product is the scaled normal of the base.
<br>
To understand why it actually works regardless of the reference point you may have a look at the 2d equivalent which works the same way. I've posted [two comments over here with a gif animation][2]. The second comment shows why the 2d version doesn't work for polygons which intersect itself.
<br>
Note that I think it should actually work for non convex meshes. Of course it only works for meshes which are actually closed and also don't have self intersecting surfaces. Though it's hard to imagine or visualize the 3d case.
<p>
<img src="https://www.dropbox.com/s/sjsug90jumgwjij/PolygonArea.gif?raw=1">
<img src="https://www.dropbox.com/s/30qbl6w370sikkk/PolygonAreaOverlap.gif?raw=1">
</p>
[1]: https://en.wikipedia.org/wiki/Triple_product
[2]: http://answers.unity.com/comments/1429965/view.htmlTue, 25 Sep 2018 13:22:38 GMTBunny83Answer by matteo1000g
http://answers.unity.com/answers/1556445/view.html
To me, it sounds like there is a bit of explanation needed about how and why this formula works since we do have some assumptions. Basically, it is using the vectorial equation for the computation of the volume of a tetrahedron, explained and illustrated here:
https://math.stackexchange.com/questions/1603651/volume-of-tetrahedron-using-cross-and-dot-product
This assumes that the vectors *a, b* and *c* define the edges of the tetrahedron and not the point coordinates of its vertices.
*Note: If you assume that the 4th point of the tetrahedron is on the origin, then you can use a, b and c as the coordinates of the vertices. Otherwise, if you have 4 vertices coordinates (let's call them d,e,f,g), you can use the same equation but you should use: a = e-d; b = f-d; c=g-d. *
Also, please be aware that this equation works only with convex volume. You should envision to use the volume computation through voxelization (explained here: http://blog.wolfire.com/2009/11/Triangle-mesh-voxelization) if you want something more robust to complex shapes (but be aware that it is much slower to compute). However, I did not found an easy to use implementation, all those I found were giving compile errors in complex codes and I did not have time to figure it out.
Note2: @HoverX : Using Unity's RigidBody SetDensity method computes, to my understanding the volume of the Collider's box of your mesh (generally a Capsule). So it is a very coarse approximation.
So, implementing the same volume computation using the 4 vertices of the tetrahedron and defining the fourth vertex of every tetrahedron as the center of mass of the later, one gets the following implementation:
using UnityEngine;
public float SignedVolumeOfTriangle(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 o)
{
Vector3 v1 = p1 - o;
Vector3 v2 = p2 - o;
Vector3 v3 = p3 - o;
return Vector3.Dot(Vector3.Cross(v1, v2), v3) / 6f; ;
}
public float VolumeOfMesh(Mesh mesh)
{
float volume = 0;
Vector3[] vertices = mesh.vertices;
int[] triangles = mesh.triangles;
Vector3 o = new Vector3(0f, 0f, 0f);
// Computing the center mass of the polyhedron as the fourth element of each mesh
for (int i = 0; i < mesh.triangles.Length; i++)
{
o += vertices[triangles[i]];
}
o = o / mesh.triangles.Length;
// Computing the sum of the volumes of all the sub-polyhedrons
for (int i = 0; i < mesh.triangles.Length; i += 3)
{
Vector3 p1 = vertices[triangles[i + 0]];
Vector3 p2 = vertices[triangles[i + 1]];
Vector3 p3 = vertices[triangles[i + 2]];
volume += SignedVolumeOfTriangle(p1, p2, p3, o);
}
return Mathf.Abs(volume);
}Tue, 25 Sep 2018 08:59:07 GMTmatteo1000gComment by HoverX on HoverX's answer
http://answers.unity.com/comments/1489671/view.html
I had been using this method for a long time until it started giving me weird results for some irregular objects. To @unit_nick's point, it seems like it's assuming something that doesn't always hold for me. His comment led me to Unity's RigidBody has a SetDensity method that seems to do this for us but more reliably: https://docs.unity3d.com/ScriptReference/Rigidbody.SetDensity.html. Typical Unity black magic with little documentation ¯\\_(ツ)_/¯Wed, 04 Apr 2018 21:45:58 GMTHoverXComment by unit_nick on unit_nick's answer
http://answers.unity.com/comments/1422821/view.html
This equation always gets me thinking. A tri is a surface element. There is no way of knowing the depth of the triangle. I believe this equation makes assumptions about the the triangle, that the forth point would be relative to the other 3. But there is no way of knowing the real forth point with only 3 points. On a convex mesh you could create the forth point but if the mesh isn't convex then you simply cannot work it out from surface tris even if you had a central point. Perhaps I'm wrong but that's how it appears to me.
So how do you calculate the volume? If you add a RigidBody to the mesh then as long as the density is 1 the mass will equal the volume.Thu, 19 Oct 2017 14:19:26 GMTunit_nickComment by m_atef on m_atef's answer
http://answers.unity.com/comments/1422812/view.html
I'm sorry how the code shall work? just by attaching it to the mesh in the inspector? Because no calculation is done if it is attached.Thu, 19 Oct 2017 14:00:08 GMTm_atefComment by Nanako on Nanako's answer
http://answers.unity.com/comments/845293/view.html
that's not very good code, CoalCzar. doesn't "this" refer to the script itself? how can a script have a transform. In any case your addition assumes the code will be run from within an object, which is very limited. This is the sort of thing that should be put in a static helper class.
I think what's really needed is to pass the MeshFilter, rather than the mesh. extract the mesh within the volume finding function, and also use this
volume *= meshFilter.gameObject.transform.localScale.x * meshFilter.gameObject.transform.localScale.y * meshFilter.gameObject.transform.localScale.z;
and this goes on line 27Tue, 02 Dec 2014 13:27:12 GMTNanakoComment by CoalCzar on CoalCzar's answer
http://answers.unity.com/comments/535045/view.html
This worked for me except that at line 39 I added:
volume *= this.transform.localScale.x * this.transform.localScale.y * this.transform.localScale.z;
so that scaling of the objects was taken into account.Wed, 11 Sep 2013 20:22:32 GMTCoalCzarComment by Grespon on Grespon's answer
http://answers.unity.com/comments/296855/view.html
I think this would help me. Thanks.Sun, 05 Aug 2012 20:08:48 GMTGresponComment by Egons on Egons's answer
http://answers.unity.com/comments/105684/view.html
Flawless, perfect, epic, fantastic, you-name-it! Thanks!Thu, 17 Mar 2011 00:52:06 GMTEgonsComment by Statement
http://answers.unity.com/comments/105683/view.html
I think it has to be convex and it has to have its center (0, 0, 0) inside the volume.Thu, 17 Mar 2011 00:50:48 GMTStatementAnswer by Statement
http://answers.unity.com/answers/52733/view.html
<p>Given your code works as intended, here's how you'd typically use it.</p>
<pre><code>using UnityEngine;
public class MeshVolume : MonoBehaviour
{
void Start()
{
Mesh mesh = GetComponent<MeshFilter>().sharedMesh;
float volume = VolumeOfMesh(mesh);
string msg = "The volume of the mesh is " + volume + " cube units.";
Debug.Log(msg);
}
public float SignedVolumeOfTriangle(Vector3 p1, Vector3 p2, Vector3 p3)
{
float v321 = p3.x * p2.y * p1.z;
float v231 = p2.x * p3.y * p1.z;
float v312 = p3.x * p1.y * p2.z;
float v132 = p1.x * p3.y * p2.z;
float v213 = p2.x * p1.y * p3.z;
float v123 = p1.x * p2.y * p3.z;
return (1.0f / 6.0f) * (-v321 + v231 + v312 - v132 - v213 + v123);
}
public float VolumeOfMesh(Mesh mesh)
{
float volume = 0;
Vector3[] vertices = mesh.vertices;
int[] triangles = mesh.triangles;
for (int i = 0; i < mesh.triangles.Length; i += 3)
{
Vector3 p1 = vertices[triangles[i + 0]];
Vector3 p2 = vertices[triangles[i + 1]];
Vector3 p3 = vertices[triangles[i + 2]];
volume += SignedVolumeOfTriangle(p1, p2, p3);
}
return Mathf.Abs(volume);
}
}
</code></pre>Thu, 17 Mar 2011 00:34:04 GMTStatementComment by Statement on Statement's answer
http://answers.unity.com/comments/105620/view.html
Yeah Egons, the thing I asked this is because I've seen people find a script and try to use it when they think they will solve another problem than it was intended for :)Wed, 16 Mar 2011 20:44:59 GMTStatementComment by yoyo
http://answers.unity.com/comments/105617/view.html
This tetrahedron-based computation assumes the origin is within the object and that all triangles can "see" the origin without looking outside the volume. (I was going to say the object had to be convex, but that's not quite true.)Wed, 16 Mar 2011 20:40:00 GMTyoyoComment by yoyo on yoyo's answer
http://answers.unity.com/comments/105615/view.html
Get point i for triangle j with p = mesh.vertices[mesh.triangles[i + 3 * j]] -- i is 0, 1, 2 for the three corners of the triangle, and j goes from 0 to mesh.triangles.length/3 - 1.Wed, 16 Mar 2011 20:33:16 GMTyoyoComment by yoyo on yoyo's answer
http://answers.unity.com/comments/105614/view.html
Oh well, I tried. ;) Maybe it'll help someone else looking at this later.Wed, 16 Mar 2011 20:28:14 GMTyoyoComment by Egons on Egons's answer
http://answers.unity.com/comments/105613/view.html
Nah, I'm looking for a function to calculate real mesh volume, not boundary box.Wed, 16 Mar 2011 20:21:55 GMTEgonsAnswer by yoyo
http://answers.unity.com/answers/52679/view.html
<p>For a rough (over-)estimate, you can use the bounding volume ...</p>
<pre><code>float volume = mesh.bounds.size.x * mesh.bounds.size.y * mesh.bounds.size.z;
</code></pre>
<p>This won't work for all purposes, but could be useful, depending what you need to do.</p>Wed, 16 Mar 2011 20:16:08 GMTyoyoComment by Egons
http://answers.unity.com/comments/105611/view.html
@flaviusxvii, no I am looking for volume, and that function there is a copy paste from StackOverflow question, about, how to calculate volume. I have no idea how to do that kind of calculation, therefore, I don't actually know what that function is doing... that's why I'm asking here.Wed, 16 Mar 2011 20:03:38 GMTEgonsComment by flaviusxvii
http://answers.unity.com/comments/105609/view.html
Triangles have area, not volume. Are you looking for surface area?Wed, 16 Mar 2011 19:55:05 GMTflaviusxviiComment by Egons on Egons's answer
http://answers.unity.com/comments/105603/view.html
You said "I am not quite sure what you are looking to do", as simple as "calculate the volume of 3D mesh".Wed, 16 Mar 2011 19:43:31 GMTEgonsComment by Egons on Egons's answer
http://answers.unity.com/comments/105601/view.html
Uhm, well, but how can I get the coordinates of points from those triangles? `Mesh.triangles;` returned only one integer, ie: 42.Wed, 16 Mar 2011 19:36:04 GMTEgonsAnswer by Statement
http://answers.unity.com/answers/52666/view.html
<p>Actually, that looks to me as valid C# code. By the looks of it, it should work (Given you have such a Mesh class). You might have to resolve namespaces System and System.Linq though. </p>
<p>I am not quite sure what you are looking to do, this seems to calculate the volume of a mesh (cubic units), was that just what you had in mind? Take a look at the Unity3d <a href="http://unity3d.com/support/documentation/ScriptReference/Mesh.html" rel="nofollow">Mesh</a> reference to see how you could get the triangles.</p>Wed, 16 Mar 2011 19:25:42 GMTStatement