Add Cinemachine third-person orbit camera and fix paint raycast

- Install Cinemachine 3.1.7 and set up an orbital third-person camera rig
  (CinemachineBrain, OrbitalFollow, RotationComposer, Deoccluder).
- Add ThirdPersonOrbitInput: mouse-driven orbit and wheel zoom with a Tab
  toggle that unlocks the cursor and pauses rotation.
- Fix MeshPainter so the paint ray skips the player's CharacterController
  capsule (and any other collider) and always targets the mesh collider,
  so painting works from every camera angle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 4.8 committed 2026-06-22 14:31:45 +02:00
1 parent 792c8c964f
commit 6e8ab4bc6d
6 files changed
+545 -10

No files matched your search

+22 -2
View File
@@ -89,6 +89,7 @@ public class MeshPainter : MonoBehaviour
private int[] _fillStamp; // transient marker for padding texels per dilation call
private int _dilateStamp; // incremented per call -> padding from previous frames does not count as a source
private readonly List<int> _dilateScratch = new List<int>(512);
private readonly RaycastHit[] _rayHits = new RaycastHit[32]; // buffer so other colliders (player capsule, etc.) cannot block painting
private int _dx0, _dy0, _dx1, _dy1; // dirty rectangle (CPU upload)
// --- GPU backend ---
@@ -480,8 +481,27 @@ public class MeshPainter : MonoBehaviour
private void PaintAtScreen(Vector2 screenPos)
{
Ray ray = paintCamera.ScreenPointToRay(screenPos);
if (!(Physics.Raycast(ray, out RaycastHit hit, 1000f) && hit.collider == _collider))
return;
// Collect all hits and pick the nearest one that belongs to the paint mesh.
// A plain Physics.Raycast returns only the closest collider, so anything in
// front of the mesh (the player's CharacterController capsule, future props,
// the camera-collision proxy) would block painting. Filtering by collider
// keeps painting working from every camera angle.
int hitCount = Physics.RaycastNonAlloc(ray, _rayHits, 1000f, ~0, QueryTriggerInteraction.Ignore);
RaycastHit hit = default;
float nearest = float.MaxValue;
bool found = false;
for (int i = 0; i < hitCount; i++)
{
if (_rayHits[i].collider != _collider) continue;
if (_rayHits[i].distance < nearest)
{
nearest = _rayHits[i].distance;
hit = _rayHits[i];
found = true;
}
}
if (!found) return;
if (_verts == null || hit.triangleIndex < 0) return;
// Bring the hit point into local mesh space (= collider/vertex space).