Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I find the volume and vertices of the intersection between two axis aligned cubes?

how can I find the volume of the intersection of two cubes aligned to the axis? The cubes can have different sizes and positions. (I add a picture to show a simple example case of two cubes)

After deep research, I am quite sure that does not exist a specific function in Unity to use for this purpose, the only way to work out this problem is mathematical logic. For example, my first idea was:

  1. To find the 8 vertexes of the cube"intersection" (B in image).

  2. Try to build a new cube with this vertex.

  3. Find the size and volume of cube "intersection".

Unity permits to find:

  • the centre of each primary cube (A in the image) with "Bounds.centre";
  • the extents of each primary cube (A in the image) from the centre of the cube (half of the size of the Bounds) with "Bounds.extents".

documentation avaible here:https://docs.unity3d.com/ScriptReference/Bounds.html

However, I can't find a way to have the vertex of each cube. And, secondly, a logical function that can find what 8 of 16 vertexes found are the right vertex to use to build the cube"Intersection".

Have u got any help or suggest?

Image: enter image description here

like image 947
Enrico Gliaschera Avatar asked Oct 19 '25 16:10

Enrico Gliaschera


1 Answers

If as you say the cubes are going to be always axis aligned with the Unity world (=> bounds = collider/renderer volume) you could probably simply do something like

  • take the Bounds of both boxes
  • take the min and max of these
  • => check how much these overlap on each axis individually using the maximum of the mins and the minimum of the maxes

What you get by this are a new min and max point of the overlapping box.

This is enough information

  • to calculate the volume by multiplying the individual components of the vector between these min and max.

  • to get all the vertices by getting all permutations between min and max for each axis.

something like

public class OverlapArea
{
    public readonly Vector3 min;
    public readonly Vector3 max;

    public readonly float volume;
    public Vector3 frontBottomLeft => min;
    public readonly Vector3 frontBottomRight;
    public readonly Vector3 frontTopLeft;
    public readonly Vector3 frontTopRight;
    public readonly Vector3 backBottomLeft;
    public readonly Vector3 backBottomRight;
    public readonly Vector3 backTopLeft;
    public Vector3 backTopRight => max;

    public readonly Bounds bounds;

    public OverlapArea(Bounds a, Bounds b)
    {
        // The min and max points
        var minA = a.min;
        var maxA = a.max;
        var minB = b.min;
        var maxB = b.max;

        min.x = Mathf.Max(minA.x, minB.x);
        min.y = Mathf.Max(minA.y, minB.y);
        min.z = Mathf.Max(minA.z, minB.z);

        max.x = Mathf.Min(maxA.x, maxB.x);
        max.y = Mathf.Min(maxA.y, maxB.y);
        max.z = Mathf.Min(maxA.z, maxB.z);

        frontBottomRight = new Vector3(max.x, min.y, min.z);
        frontTopLeft = new Vector3(min.x, max.y, min.z);
        frontTopRight = new Vector3(max.x, max.y, min.z);
        backBottomLeft = new Vector3(min.x, min.y, max.z);
        backBottomRight = new Vector3(max.x, min.y, max.z);
        backTopLeft = new Vector3(min.x, max.y, max.z);

        // The diagonal of this overlap box itself
        var diagonal = max - min;
        volume = diagonal.x * diagonal.y * diagonal.z;

        bounds.SetMinMax(min, max);
    }

    public static bool GetOverlapArea(Bounds a, Bounds b, out OverlapArea overlapArea)
    {
        overlapArea = default;

        // If they are not intersecting we can stop right away ;)
        if (!a.Intersects(b)) return false;

        overlapArea = new OverlapArea(a, b);

        return true;
    }
}
    
    

And so in order to get the overlap information you would do e.g.

// I intentionally used the Bounds as parameters for the method because you can
// either use the Renderer bounds
var boundsA = cubeA.GetComponent<Renderer>().bounds;
// or use Collider bounds in your case they should be equal
var boundsB = cubeB.GetComponent<Collider>().bounds;

if(GetOverlapArea(boundsA, boundsB, out var overlap))
{
    // Now in overlap you have all the information you wanted
}

Now in order to actually get the overlap mesh ( if that is where you are going) you have two options

Either use the given edge points and actually create a mesh yourself (note the vertices are in world space so the object should have no scaling itself or on any parent)

...

var mesh = new Mesh
{
    vertices = new[]
    {
        overlapArea.frontBottomLeft,
        overlapArea.frontBottomRight,
        overlapArea.frontTopLeft,
        overlapArea.frontTopRight,

        overlapArea.backBottomLeft,
        overlapArea.backBottomRight,
        overlapArea.backTopLeft,
        overlapArea.backTopRight
    },
    triangles = new[]
    {
        // Front
        0, 2, 1,
        1, 2, 3,
        // Back
        5, 7, 4,
        4, 7, 6,
        // Left
        4, 6, 2,
        4, 2, 0,
        // Right
        1, 7, 5,
        1, 3, 7,
        // Top
        2, 7, 3,
        2, 6, 7,
        // Bottom
        0, 4, 1,
        1, 4, 5
    }
}

as a little demo

public class Example : MonoBehaviour
{
    public Renderer CubeA;
    public Renderer CubeB;

    public Material overlapMaterial;

    private MeshFilter overlap;
    private readonly Vector3[] overlapVertices = new Vector3[8];

    public void Awake()
    {
        overlap = new GameObject("Overlap", typeof(MeshRenderer)).AddComponent<MeshFilter>();

        var overlapMesh = new Mesh
        {
            vertices = overlapVertices,
            triangles = new[]
            {
                // Front
                0, 2, 1,
                1, 2, 3,

                // Back
                5, 7, 4,
                4, 7, 6,

                // Left
                4, 6, 2,
                4, 2, 0,

                // Right
                1, 7, 5,
                1, 3, 7,

                // Top
                2, 7, 3,
                2, 6, 7,

                // Bottom
                0, 4, 1,
                1, 4, 5
            }
        };

        overlap.mesh = overlapMesh;
        overlap.GetComponent<Renderer>().material = overlapMaterial;
    }
    
    public void Update()
    {
        if (OverlapArea.GetOverlapArea(CubeA.bounds, CubeB.bounds, out var overlapArea))
        {
            overlap.gameObject.SetActive(true);

            overlap.mesh.vertices = new[]
            {
                overlapArea.frontBottomLeft,
                overlapArea.frontBottomRight,
                overlapArea.frontTopLeft,
                overlapArea.frontTopRight,

                overlapArea.backBottomLeft,
                overlapArea.backBottomRight,
                overlapArea.backTopLeft,
                overlapArea.backTopRight
            };

            overlap.mesh.RecalculateBounds();
        }
        else
        {
            overlap.gameObject.SetActive(false);
        }
    }
}

enter image description here

or you could instead use an already existing primitive cube (the default Unity cube) and just set it to the correct coordinates and scale it like

overlapVisualizer.transform.position = overlap.bounds.center;
// note we set the local scale so there should be no parent scaling
overlapVisualizer.transform.localScale = overlap.bounds.size;

again a little demo of that

public class Example : MonoBehaviour
{
    public Renderer CubeA;
    public Renderer CubeB;

    public Transform overlap;

    public void Update()
    {
        if (OverlapArea.GetOverlapArea(CubeA.bounds, CubeB.bounds, out var overlapArea))
        {
            overlap.gameObject.SetActive(true);

            overlap.position = overlapArea.bounds.center;
            overlap.localScale = overlapArea.bounds.size;
        }
        else
        {
            overlap.gameObject.SetActive(false);
        }
    }
}

enter image description here

like image 131
derHugo Avatar answered Oct 21 '25 04:10

derHugo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!