Add concealment meter and skinned collider baker; reorganize assets
- ConcealmentMeter: standalone component measuring the percentage of the character volume embedded inside environment geometry (bake -> voxelize via column ray-stabbing parity -> classify interior voxels against box/sphere/ capsule/convex colliders and terrain). Always-on, throttled, gizmo debug. - SkinnedColliderBaker: sole per-frame collider bake owner for skinned rigs. MeshPainter now delegates baking and only borrows BakedMesh for the GPU raster and cache refresh, so the collider stays fresh outside paint mode. - Move pose assets to Assets/Poses, retire unused Insect scripts to Assets/Unused, restore Paintman.controller; mode scripts and scene updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
def10541ab
commit
dcfd668422
29 files changed
+2160
-1656
No files matched your search
@@ -0,0 +1,73 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Sole owner of the animated character's collider bake: keeps a non-convex MeshCollider in sync with
|
||||
/// the SkinnedMeshRenderer's current pose every frame, independent of any paint/game mode. MeshPainter's
|
||||
/// own per-frame bake sits behind its PaintingEnabled gate, so the collider would otherwise freeze in
|
||||
/// player-control / insect mode. When this component is present MeshPainter delegates to it (it stops
|
||||
/// baking and only borrows <see cref="BakedMesh"/> for its GPU raster path), so the deformed-pose
|
||||
/// collider stays fresh for everyone - paint raycasts, physics, future seeker / line-of-sight queries.
|
||||
///
|
||||
/// Bakes in the renderer's LOCAL space (BakeMesh, scale = 1) - the same convention MeshPainter and
|
||||
/// ConcealmentMeter use (world = transform.localToWorldMatrix). Runs at a negative execution order so
|
||||
/// the collider is fresh before MeshPainter (and other consumers) read it in the same frame. Owns the
|
||||
/// baked Mesh (creates + destroys it); MeshPainter never destroys a borrowed mesh.
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
[DefaultExecutionOrder(-50)]
|
||||
[RequireComponent(typeof(SkinnedMeshRenderer))]
|
||||
public class SkinnedColliderBaker : MonoBehaviour
|
||||
{
|
||||
[Min(0f)]
|
||||
[Tooltip("Seconds between collider re-bakes. 0 = every frame (matches MeshPainter's per-frame bake). " +
|
||||
"Raise it to trade collider freshness for CPU on a high-poly rig.")]
|
||||
[SerializeField] private float bakeInterval = 0f;
|
||||
|
||||
/// <summary>The mesh baked from the current pose, in local space. Valid after the first bake.</summary>
|
||||
public Mesh BakedMesh => _baked;
|
||||
|
||||
private SkinnedMeshRenderer _skinned;
|
||||
private MeshCollider _collider;
|
||||
private Mesh _baked;
|
||||
private float _timer;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_skinned = GetComponent<SkinnedMeshRenderer>();
|
||||
if (!_skinned)
|
||||
{
|
||||
Debug.LogError("[SkinnedColliderBaker] No SkinnedMeshRenderer on this GameObject.", this);
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_collider = GetComponent<MeshCollider>();
|
||||
if (!_collider) _collider = gameObject.AddComponent<MeshCollider>();
|
||||
_collider.convex = false; // non-convex provides triangleIndex / textureCoord for paint raycasts
|
||||
|
||||
_baked = new Mesh { name = "SkinnedColliderBaker_Baked" };
|
||||
Bake(); // valid collider on frame 0, before any consumer reads it
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (bakeInterval <= 0f) { Bake(); return; }
|
||||
_timer += Time.deltaTime;
|
||||
if (_timer < bakeInterval) return;
|
||||
_timer = 0f;
|
||||
Bake();
|
||||
}
|
||||
|
||||
private void Bake()
|
||||
{
|
||||
if (!_skinned) return;
|
||||
_skinned.BakeMesh(_baked);
|
||||
_collider.sharedMesh = null; // force a physics re-cook of the new geometry
|
||||
_collider.sharedMesh = _baked;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (_baked) Destroy(_baked);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user