Misc Utilities

BakeAndAttachCollider

public void BakeAndAttachCollider(bool convex)
{
    if (!m_SkinnedMeshRenderer) return;
    Mesh baked = new Mesh { name = "Baked_SkinnedMesh", hideFlags = HideFlags.HideAndDontSave };
    m_SkinnedMeshRenderer.BakeMesh(baked, true);
    if (!m_MeshCollider) CacheComponents();
    m_MeshCollider.sharedMesh = baked;
    m_MeshCollider.convex     = convex;
}

Purpose: Bake a SkinnedMeshRenderer to a static Mesh and assign it to the MeshCollider. Parameters: convex — whether to set MeshCollider.convex. Returns: void Notes: Useful for dynamic characters when you need a quick collision shell.


SetMaskBox

public void SetMaskBox(Vector3 centerWs, Vector2 sizeWs)
{
    center = transform.InverseTransformPoint(centerWs);
    size   = sizeWs;
    ForceRebuild(true);
}

Purpose: Update center and size of the mask in one call, then rebuild. Parameters: centerWs (world), sizeWs Returns: void


GetProjectionBounds

public Bounds GetProjectionBounds()
    => new(transform.TransformPoint(center),
           Vector3.Scale(new Vector3(size.x, size.y, maxDistance), transform.lossyScale));

Purpose: Get current projection Bounds in world space. Returns: Bounds


GetSubdivisionSettings

public Vector2Int GetSubdivisionSettings()
    => new(meshSubdivisions, colliderSubdivisions);

Purpose: Return current (mesh, collider) subdivision counts. Returns: Vector2Int


EstimateMemoryFootprint

public int EstimateMemoryFootprint(int overrideSubDiv = -1)
{
    int sub = overrideSubDiv > 2 ? overrideSubDiv : meshSubdivisions;
    int verts = (sub + 1) * (sub + 1);
    int tris  = sub * sub * 2;
    const int vertSize = 12 * 2 + 8; // pos+normal+uv
    return (verts * vertSize + tris * 4 * 3) / 1024; // KB
}

Purpose: Rough memory estimate (KB) for a given subdivision level. Parameters: overrideSubDiv — if <= 2, uses current meshSubdivisions. Returns: int (KB) Notes: Helpful when building quality profiles.


PredictRebuildTimeMS

public float PredictRebuildTimeMS(int futureSubDiv)
{
    if (m_LastStats.TrianglesVisual == 0) return 0f;
    float ratio = Mathf.Pow((float)futureSubDiv / meshSubdivisions, 2f);
    return m_LastRebuildTimeMS * ratio;
}

Purpose: Predict rebuild time (ms) for a future subdivision, based on last measurement. Parameters: futureSubDiv Returns: float (ms) Notes: Assumes triangle count ~ subdiv².


SetAdaptiveSubdivisions

public void SetAdaptiveSubdivisions(float targetAvgTriAreaCm2)
{
    if (targetAvgTriAreaCm2 <= 0) return;
    float current = GetAverageTriArea(false);
    if (current <= 0) return;

    float ratio = current / targetAvgTriAreaCm2;
    int newSub = Mathf.Clamp(
        Mathf.RoundToInt(meshSubdivisions * Mathf.Sqrt(ratio)), 3, 64);
    if (newSub == meshSubdivisions) return;

    meshSubdivisions     = newSub;
    colliderSubdivisions = Mathf.Clamp(newSub / 4, 3, 64);
    ForceRebuild(true);
}

Purpose: Automatically tune subdivisions to reach a target average triangle area (cm²). Parameters: targetAvgTriAreaCm2 Returns: void Notes: Collider subdivisions are auto-derived as ~¼ of visual for efficiency.


Last updated