How do you calculate the volume of a dynamic blendshape 3D mesh in runtime?

Hi all. First time posting

I’m currently creating a game where the player character changes body size based on how the player interact with the world.

I’m looking for a new way to get the character weight and came across mesh volume calculation. Right now, it’s measured in Blender and then defined in a script in Unity.

The player character uses blendshapes for body dimensions that updates each frame during gameplay.

The code I’m using is this.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MeshVolume : MonoBehaviour
{
    [SerializeField] private float totalMeshVolume;
    private Mesh mesh;

    // Start is called before the first frame update
    void Start()
    {
        mesh = GetComponent<MeshFilter>().sharedMesh; 
    }

    // Update is called once per frame
    void Update()
    {
        mesh = GetComponent<MeshFilter>().sharedMesh;
        string msg = "The volume of the mesh is " + totalMeshVolume + " units.";
        Debug.Log(msg);

        VolumeOfMesh();
    }

    public float CalculateVolumeOfTriangle(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 void VolumeOfMesh()
    {
        float volume = 0;

        Vector3[] vertices = mesh.vertices;
        int[] triangles = mesh.triangles;

        for (int i = 0; i < triangles.Length; i += 3)
        {
            Vector3 p1 = vertices[triangles[i + 0]];
            Vector3 p2 = vertices[triangles[i + 1]];
            Vector3 p3 = vertices[triangles[i + 2]];
            volume += CalculateVolumeOfTriangle(p1, p2, p3);
        }
        totalMeshVolume = volume*1000000f;
    }
}

It’s a modified version of this:
Found here: How would one calculate a 3d Mesh volume in Unity? - Questions & Answers - Unity Discussions

I’m using this MeshVolume script on an ‘Empty’ named ‘Player’ containing player model and other files and resources.

The script gets the mesh info from Mesh Filter.

The code gets a very small volume from the mesh but multiplying it by 1,000,000 it’s correct in cubic meters, guessing it’s something about unit conversion.

So as the headline says:
How do you calculate the volume of a ever changing blendshaped 3D mesh in runtime?

I haven’t been able to find much info about measure 3D mesh use cases. I have also looked at Unity’s Mesh Filter documentation and wasn’t able to find any info when using it in this way.

For most typical use-cases (rather, barring only the most extreme examples, such as having all vertices swap sides of a mesh between two blendshapes), the volume conversions should functionally be just as linear as the blendshape morphing itself. While that’s not 100% accurate, it probably should be good enough for any common situation, rather than calculating the raw volume based on the interpolated position of every vertex.

If you’re having to scale volume up by 1,000,000 times, I’m assuming that either the mesh or its root container (common enough on imported meshes) claims to be scaling your mesh up by 100x per axis to reach its base size (Vector3(100, 100, 100)). On that basis, you could factor in a default scale fixup to the base algorithm:

Vector3 scaleFixup = transform.root.localScale;
// ...
Vector3 p1 = Vector3.Scale(vertices[triangles[i + 0]], scaleFixup);
// etc.
// or...
Vector3 p1 = transform.TransformPoint(vertices[triangles[i + 0]]);

Then, any further fixups can be handled after the fact.

Anyway, if you precompute the volume of each blendshape, then you can add the ratios of each as necessary. The simple example for any pair is:

float currentVolume = Mathf.Lerp(currentShapeVolume, newShapeVolume, morphProgress);
// or, the more-expandable variant:
// Example: currentShapeVolume * 0.72 + newShapeVolume * 0.28
float currentVolume = currentShapeVolume * csRatio + newShapeVolume * nsRatio;


Now for the pedantic angle:

What exactly does volume have to do with mass? If your character’s changing size, would it inherently gain or lose weight in the process? For example, if it’s transforming from a balloon into a brick, it would lose volume, but gain a huge amount of mass. If density is always going to be the same, then measuring mass based on volume makes sense in that respect.

This isn’t a line of questioning to take to heart, necessarily. It’s more of the matter of having something to consider.