Sweep over 48 files (Editor/ excluded): remove comments that restate the code, condense class summaries, fix three stale doc statements (HsvColorPicker alpha bar, PaintHud layoutPrefab, MasterVolume FallbackDefault). Inline two single-use wrappers (IsPointerOverUi, BuildModes), drop an unused using, replace a magic literal with the existing ParallaxBase constant, and convert ~10 UnityEngine.Object null checks to the implicit-bool convention. No serialized fields, signatures, RPC/NetworkVariable names, defaults, or #if blocks touched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
85 lines
3.6 KiB
C#
85 lines
3.6 KiB
C#
using System.Collections.Generic;
|
|
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 bake sits behind its PaintingEnabled gate, so the collider would otherwise freeze in
|
|
/// player-control / insect mode). When present, MeshPainter delegates to it and only borrows
|
|
/// <see cref="BakedMesh"/> for its GPU raster path.
|
|
///
|
|
/// 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 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 readonly List<Vector3> _vbuf = new List<Vector3>(); // reused vertex scratch so the scale fixup allocates nothing per bake
|
|
|
|
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);
|
|
|
|
// BakeMesh freezes the bone deformation — which already carries this transform's world scale —
|
|
// into the mesh, and the MeshCollider below applies the same lossyScale a SECOND time, so a
|
|
// scaled player (see PlayerScaler) would get a collider half/double the visible mesh. Divide the
|
|
// scale back out so the baked mesh is true scale-1 local geometry: the MeshCollider re-applies it
|
|
// exactly once, and MeshPainter / ConcealmentMeter (world via localToWorldMatrix) stay correct at
|
|
// any player scale. No-op at scale 1; the uniform divide is rotation-independent, which the
|
|
// player's uniform scale guarantees.
|
|
GeometryUtil.RescaleToUnitScale(_baked, transform.lossyScale, _vbuf);
|
|
|
|
_collider.sharedMesh = null; // force a physics re-cook of the new geometry
|
|
_collider.sharedMesh = _baked;
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (_baked) Destroy(_baked);
|
|
}
|
|
}
|