cancel
Showing results for 
Search instead for 
Did you mean: 

MRUK Destructible Mesh Improvement (Fixing inconsistently sized pieces)

Ian0mac5929
Honored Guest

Hey! First time posting here but found something interesting others might want to know. It's an improvement, it seems, but requires modifying library files so I'd love to know if anyone knows where I can go from here.

I've been playing with the MRUK destructible environment stuff. It works great (Nevermind the fact I've spent the last 8 months developing my own version 🙃) but noticed with some oddly shaped rooms that sometimes you may get mesh pieces that are HUGE on one side of the room and then appropriately sized on the other. I mean, to the point where it's unusable. This seems to be because of how they distribute the points in the GeneratePoints() method in the DestructibleGlobalMeshSpawner class. After finding this out, with the help of Copilot (I wouldn't want to take undue credit!), I added this method to `DestructibleGlobalMeshSpawner`:

public static List<Vector3> SamplePointsOnMesh(Mesh mesh, int numPoints)
{
    var points = new List<Vector3>();
    var triangles = mesh.triangles;
    var vertices = mesh.vertices;

    // Calculate area of each triangle
    var areas = new float[triangles.Length / 3];
    float totalArea = 0f;
    for (int i = 0; i < triangles.Length; i += 3)
    {
        var a = vertices[triangles[i]];
        var b = vertices[triangles[i + 1]];
        var c = vertices[triangles[i + 2]];
        float area = Vector3.Cross(b - a, c - a).magnitude * 0.5f;
        areas[i / 3] = area;
        totalArea += area;
    }

    // Sample triangles proportional to their area
    for (int i = 0; i < numPoints; i++)
    {
        float r = UnityEngine.Random.value * totalArea;
        int triIndex = 0;
        float accum = 0f;
        for (; triIndex < areas.Length; triIndex++)
        {
            accum += areas[triIndex];
            if (r <= accum) break;
        }

        // Sample a point in the triangle using barycentric coordinates
        var a = vertices[triangles[triIndex * 3]];
        var b = vertices[triangles[triIndex * 3 + 1]];
        var c = vertices[triangles[triIndex * 3 + 2]];
        float u = UnityEngine.Random.value;
        float v = UnityEngine.Random.value;
        if (u + v > 1)
        {
            u = 1 - u;
            v = 1 - v;
        }
        var point = a + u * (b - a) + v * (c - a);
        points.Add(point);
    }
    return points;
}

and then changed the existing ComputeRoomBoxGrid() method to use it:

private static Vector3[] ComputeRoomBoxGrid(MRUKRoom room, int maxPointsCount, float pointsPerUnitX = 1.0f,
    float pointsPerUnitY = 1.0f)
{
    _points.Clear();

    // Prefer sampling directly from the room's global mesh if available
    if (room.GlobalMeshAnchor != null && room.GlobalMeshAnchor.Mesh != null)
    {
        // Sample points evenly distributed over the mesh surface
        var meshPoints = SamplePointsOnMesh(room.GlobalMeshAnchor.Mesh, maxPointsCount);
        _points.AddRange(meshPoints);
    }
    else
    {
        // Fallback: use the original grid-based approach for walls, ceiling, and floor
        foreach (MRUKAnchor wall in room.WallAnchors)
        {
            GeneratePoints(_points, wall.transform.position, wall.transform.rotation,
                wall.PlaneRect, pointsPerUnitX, pointsPerUnitY);
        }

        var ceilingHeight = room.CeilingAnchor.transform.position.y - room.FloorAnchor.transform.position.y;
        var planesCount = Mathf.Max(Mathf.Ceil(pointsPerUnitY * ceilingHeight), 1);
        var spaceBetweenPlanes = ceilingHeight / planesCount;
        for (var i = 0; i < planesCount; i++)
        {
            var planePosition = new Vector3(room.CeilingAnchor.transform.position.x,
                room.CeilingAnchor.transform.position.y - (spaceBetweenPlanes * i),
                room.CeilingAnchor.transform.position.z);
            GeneratePoints(_points, planePosition, room.CeilingAnchor.transform.rotation,
                room.CeilingAnchor.PlaneRect, pointsPerUnitX, pointsPerUnitY);
        }

        GeneratePoints(_points, room.CeilingAnchor.transform.position,
            room.CeilingAnchor.transform.rotation, room.CeilingAnchor.PlaneRect, pointsPerUnitX, pointsPerUnitY);

        GeneratePoints(_points, room.FloorAnchor.transform.position, room.FloorAnchor.transform.rotation,
            room.FloorAnchor.PlaneRect, pointsPerUnitX, pointsPerUnitY);

        // Optionally limit the number of points and shuffle for randomness
        if (_points.Count > maxPointsCount)
        {
            Shuffle(_points);
            _points.RemoveRange(maxPointsCount, _points.Count - maxPointsCount);
        }
    }
    return _points.ToArray();
}

 

And boom. Seems to give similarly sized pieces. I haven't tested this extensively... but it certainly has improved on the rooms I've been using.

Obviously this modifies the core library... which is just unacceptable. So at this point I'm trying to copy files to my project... but it isn't going so well. Does anyone know a place I can submit input like this to Meta?

Update: Actually pretty easy to get this update into your repo. Copy the DestructibleGlobalMeshSpawner file into your code (updated as described), then replace all occurrences of GlobalMeshAnchor.Mesh with GlobalMeshAnchor.GlobalMesh.

0 REPLIES 0