Art: ArtStaging overhaul - game-cam POV system + Bathynaut character (no longer reads as a lamp)

Camera: runtime POV switcher (StagingCameraSwitcher; V/]/[ cycle, 1-4 jump) with POV_1_Game matching
the in-game rig (Pitch45/Dist13/FOV55) as the default + hero/front/close-up; deep-water SolidColor
clear kills the no-skybox corner bleed at the wide game framing.

Character (the 'reads like a lamp' fix, operator-directed): darkened the helmet to dark gunmetal with
a dim lit porthole and moved the warm beacon to the shoulder lamp (light is carried, not the head);
color-blocked the body into a brass-and-teal deep-sea-diver palette (brass armour / dark-teal
undersuit / dark-metal kit) for value contrast + identity at game scale; bulked the back tank-rig
silhouette. Master .blend keeps rig+pose+materials re-editable; posed static GLB reimported into the
connected prefab instance with instance material overrides reset to the GLB's diver materials.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 20:34:36 -07:00
parent 5e0044b492
commit 8b50753f93
6 changed files with 632 additions and 6 deletions
@@ -0,0 +1,63 @@
#if UNITY_EDITOR
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
namespace ProjectM.Client
{
/// <summary>
/// Dev-only ArtStaging POV switcher. Self-wires by name to every camera named "POV_*" (sorted), enables
/// exactly one at a time, and cycles on a keypress so the operator can judge the style-proof from the actual
/// game camera AND from hero/front/close-up angles. Play-mode only; no asset writes. Keys: V or ] = next,
/// [ = previous, 1-9 = jump to that POV. A small label shows the active view.
/// </summary>
[DisallowMultipleComponent]
public sealed class StagingCameraSwitcher : MonoBehaviour
{
readonly List<Camera> _cams = new();
int _idx;
void Start()
{
foreach (var c in Object.FindObjectsByType<Camera>(FindObjectsSortMode.None))
if (c.gameObject.name.StartsWith("POV_")) _cams.Add(c);
_cams.Sort((a, b) => string.CompareOrdinal(a.gameObject.name, b.gameObject.name));
// default to the game camera (POV_1_Game) if present
for (int i = 0; i < _cams.Count; i++) if (_cams[i].gameObject.name.Contains("Game")) { _idx = i; break; }
Activate(_idx);
}
void Update()
{
var kb = Keyboard.current;
if (kb == null || _cams.Count == 0) return;
if (kb.vKey.wasPressedThisFrame || kb.rightBracketKey.wasPressedThisFrame) Activate((_idx + 1) % _cams.Count);
else if (kb.leftBracketKey.wasPressedThisFrame) Activate((_idx - 1 + _cams.Count) % _cams.Count);
else
{
for (int n = 0; n < _cams.Count && n < 9; n++)
if (kb[(Key)((int)Key.Digit1 + n)].wasPressedThisFrame) { Activate(n); break; }
}
}
void Activate(int i)
{
_idx = Mathf.Clamp(i, 0, _cams.Count - 1);
for (int k = 0; k < _cams.Count; k++)
{
bool on = k == _idx;
_cams[k].enabled = on;
_cams[k].tag = on ? "MainCamera" : "Untagged";
}
}
void OnGUI()
{
if (_cams.Count == 0) return;
var s = new GUIStyle(GUI.skin.box) { fontSize = 13, alignment = TextAnchor.MiddleLeft };
GUI.Box(new Rect(10, 10, 320, 26),
$"POV [{_idx + 1}/{_cams.Count}] {_cams[_idx].gameObject.name} (V/]=next [=prev 1-{_cams.Count}=jump)", s);
}
}
}
#endif
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 50b5e3a95050f634bb73d3a20a0dd9ad