144 lines
11 KiB
C#
144 lines
11 KiB
C#
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 이동 방향 기반 카메라 리드/피치 수치의 단일 출처(SOT · 조직 C45).
|
|||
|
|
/// 전진(카메라에서 멀어짐) = 궤도 중심·주시점을 진행 방향으로 밀어 앞을 더 보여준다.
|
|||
|
|
/// 후진(카메라 쪽으로 옴) = 궤도 피치를 올려 더 내려다보게 하고, 주시점을 카메라 쪽으로 당겨
|
|||
|
|
/// 캐릭터가 화면에서 위로 올라가게 한다.
|
|||
|
|
///
|
|||
|
|
/// 에셋 경로(고정): Assets/WL/Settings/Resources/WL/CameraLeadSettings.asset
|
|||
|
|
/// → CameraMoveLead 가 Resources.Load<CameraLeadSettings>("WL/CameraLeadSettings") 로 1회 로드한다.
|
|||
|
|
/// 에셋이 없거나 enabled = false 면 RealCamera 는 100% 기존 동작을 한다.
|
|||
|
|
///
|
|||
|
|
/// 【힘민지 RealCamera 실측 기준값 · 2026-09-06 · Assets/ResWork/Prefabs/Ingame/Main Camera.prefab】
|
|||
|
|
/// arr_cCamData[0](일반) minDistance 3 · maxDistance 3 · DistanceUp 2 · cameraHeight 78
|
|||
|
|
/// m_LookAt (0, 1.06, 0) · smooth 4 · FOV 60 · rotateAround = 맵별 MapZoneData.CamRot_Portal(27~270)
|
|||
|
|
/// → 궤도 중심 = 발밑 + up*2 · 반지름 = √3 × 3 = 5.196 m
|
|||
|
|
/// → 카메라 = 발밑 +4.311 m / 수평 4.654 m · 주시점까지 5.677 m · 실제 내림각 34.93°
|
|||
|
|
///
|
|||
|
|
/// 【구 WL FollowCameraSettings 실측값 → 이 에셋 기본값의 근거】
|
|||
|
|
/// lookAheadMaxDistance 1.5 m(모드2 distance 15) · lookAheadSmoothTime 0.7 · lookAheadDirSmoothTime 0.35
|
|||
|
|
/// lookAheadSpeedReference 3.85 · followMoveSpeedThreshold 0.15 · pitchBlendSmoothTime 0.4
|
|||
|
|
/// screenAnchorY 0.3 ↔ screenAnchorYTowardCamera 0.5 · anchorSmoothTime 0.4
|
|||
|
|
/// usePitchMoving = false ← PD #719 ④ "세로 출렁임" 으로 이동 중 피치 변경을 껐던 이력 (아래 backwardPitchAdd 주의)
|
|||
|
|
///
|
|||
|
|
/// 【2026-09-06 PM 결정(PD 지시 #755 2단계) — 아래 기본값의 확정 근거】
|
|||
|
|
/// ① 후진 = 절충안 C : backwardPitchAdd 6° + backwardLeadDistance −0.4 m (피치 주 · 앵커 보조)
|
|||
|
|
/// ② leadPerpendicularBlend = 1 (구 WL 앵커 방식 동등 · 깊이 변화 0)
|
|||
|
|
/// ③ leadDistance = 1.5 m ④ leadSmoothTime = 0.45 (RealCamera 자체 Lerp τ≈0.25 s 보정)
|
|||
|
|
/// </summary>
|
|||
|
|
[CreateAssetMenu(fileName = "CameraLeadSettings", menuName = "WL/Camera Lead Settings")]
|
|||
|
|
public class CameraLeadSettings : ScriptableObject
|
|||
|
|
{
|
|||
|
|
[Header("전체 스위치")]
|
|||
|
|
[Tooltip("끄면 리드·피치 가산이 전부 0 이 되어 RealCamera 가 100% 기존 동작을 한다. 롤백 1순위 스위치.")]
|
|||
|
|
public bool enabled = true;
|
|||
|
|
|
|||
|
|
// ─────────────────────────────────────────── 전진 리드
|
|||
|
|
|
|||
|
|
[Header("전진 리드 — 궤도 중심 + 주시점을 진행 방향으로 밀기")]
|
|||
|
|
[Tooltip("전진 성분이 최대일 때 궤도 중심과 주시점을 진행 방향(수평)으로 미는 거리(m).\n" +
|
|||
|
|
"궤도 중심과 주시점을 같은 값으로 함께 밀기 때문에 카메라는 회전 없이 통째로 평행 이동한다.\n" +
|
|||
|
|
"【환산】 화면 세로 이동 비율 = lead × sin(내림각) / (2 × 주시거리 × tan(FOV/2))\n" +
|
|||
|
|
" 힘민지 실측(내림각 34.93° · 주시거리 5.677 m · FOV 60) → 화면 세로의 8.73 %/m\n" +
|
|||
|
|
" 0.6 m = 구 WL 룩어헤드만 거리비 환산 · 2.9 m = 룩어헤드+앵커 총합 환산(과함)\n" +
|
|||
|
|
" 1.5 m(기본 · PM 결정 ③) = PD 가 '카메라가 앞으로 이동' 을 체감하도록 1.2 보다 크게\n" +
|
|||
|
|
" → 화면 세로 13.1 % · 캐릭터 화면 y 0.50 → 0.37 【추정】")]
|
|||
|
|
[Range(0f, 3f)] public float leadDistance = 1.5f;
|
|||
|
|
|
|||
|
|
[Tooltip("후진 성분이 최대일 때 **카메라 수평 전방(camFwd) 축** 으로 주시점을 미는 거리(m). 부호가 중요하다.\n" +
|
|||
|
|
" 음수(기본 −0.4 · PM 결정 ①) = 주시점이 카메라 쪽으로 당겨진다 → 캐릭터가 화면에서 **위로** 올라간다.\n" +
|
|||
|
|
" 구 WL 의 screenAnchorY 0.3 ↔ screenAnchorYTowardCamera 0.5 앵커 전환과 같은 방향의 효과다.\n" +
|
|||
|
|
" 양수 = 반대(캐릭터가 화면 아래로). 0 = 후진 시 리드 없음(피치 가산만).\n" +
|
|||
|
|
" −0.4 m → 화면 세로 3.5 % 상승 【추정】. 후진 연출의 주역은 backwardPitchAdd 이고 이 값은 보조다.")]
|
|||
|
|
[Range(-2f, 2f)] public float backwardLeadDistance = -0.4f;
|
|||
|
|
|
|||
|
|
[Tooltip("좌/우(측면) 이동 성분이 최대일 때 카메라 수평 우측(camRight) 축으로 주시점을 미는 거리(m) · PD #759 (2026-09-06).\n" +
|
|||
|
|
"이동 방향 쪽 화면이 더 보인다(캐릭터는 반대쪽으로 밀림). 전진 리드와 같은 시선-수직 처리를 받는다.\n" +
|
|||
|
|
"0 = 측면 리드 없음(이전 동작). 기본 1.0 【추정 · 전진 1.5 의 2/3】")]
|
|||
|
|
[Range(0f, 3f)] public float lateralLeadDistance = 1.0f;
|
|||
|
|
|
|||
|
|
[Tooltip("리드를 현재 카메라 거리(DistanceAway)에 비례시킨다. 구 WL lookAheadScaleByDistance = true 와 동일 취지.\n" +
|
|||
|
|
"실내(Set_InsideBuilding · DistanceAway 2)·보스(2~3)에서 리드가 과해지는 것을 자동으로 눌러 준다.\n" +
|
|||
|
|
"전진 리드와 후진 리드에 모두 적용된다.")]
|
|||
|
|
public bool scaleLeadByDistance = true;
|
|||
|
|
|
|||
|
|
[Tooltip("리드 거리비의 기준이 되는 DistanceAway. 0 이면 타겟이 바인드된 시점의 DistanceAway 를 자동으로 쓴다\n" +
|
|||
|
|
"(일반 카메라 실측 3 · 코드에 숫자를 박지 않기 위해 런타임 캡처).\n" +
|
|||
|
|
"실효 리드 = leadDistance × (현재 DistanceAway / 이 값)")]
|
|||
|
|
public float leadReferenceDistance = 0f;
|
|||
|
|
|
|||
|
|
[Tooltip("리드 오프셋의 감쇠 시간(초).\n" +
|
|||
|
|
"구 WL lookAheadSmoothTime 실측은 0.7 이지만, RealCamera 는 그 위에\n" +
|
|||
|
|
"Vector3.Lerp(smooth 4 · 시정수 약 0.25 s)를 또 건다. 두 저역통과가 겹쳐 체감이 늦어지므로\n" +
|
|||
|
|
"PM 결정 ④ 로 0.45 로 낮춘다(합성 90% 도달 약 1.1 s 【추정】).")]
|
|||
|
|
public float leadSmoothTime = 0.45f;
|
|||
|
|
|
|||
|
|
[Tooltip("리드가 향하는 **방향** 자체의 감쇠 시간(초). 급반전 때 오프셋이 화면을 가로질러 휘두르는 것을 막는다.\n" +
|
|||
|
|
"구 WL lookAheadDirSmoothTime 실측 0.35")]
|
|||
|
|
public float leadDirSmoothTime = 0.35f;
|
|||
|
|
|
|||
|
|
[Tooltip("리드에서 **시선 방향 성분을 제거하는 비율**.\n" +
|
|||
|
|
"힘민지 카메라는 34.93° 로 내려다본다 → 수평 리드 1 m 중 0.82 m 가 시선 방향(=줌인), 0.57 m 만 화면 세로로 간다.\n" +
|
|||
|
|
" 0 = 브리프 사양 그대로의 수평 리드. 리드 1.5 m 면 피사체가 1.23 m 가까워진다(깊이 −22 %).\n" +
|
|||
|
|
" 1(기본 · PM 결정 ②) = 시선에 수직인 성분만 남긴다 → 깊이 변화 0 · 줌인 0.\n" +
|
|||
|
|
" 구 WL 의 screenAnchorY 방식(FocusShift)과 동일. 화면 세로 이동량은 0 일 때와 같다.")]
|
|||
|
|
[Range(0f, 1f)] public float leadPerpendicularBlend = 1f;
|
|||
|
|
|
|||
|
|
// ─────────────────────────────────────────── 후진 피치
|
|||
|
|
|
|||
|
|
[Header("후진 피치 — 궤도 각을 올려 더 내려다보기")]
|
|||
|
|
[Tooltip("후진 성분이 최대일 때 RealCamera.cameraHeight 에 더하는 각(도).\n" +
|
|||
|
|
"cameraHeight 는 실제 고도각이 아니라 Quaternion.Euler(h, yaw, 0) * Vector3.one 의 파라미터다.\n" +
|
|||
|
|
"【환산 · 힘민지 실측 78°】 실제 고도각 = asin((sin h − cos h)/√3) → 78° = 26.40°\n" +
|
|||
|
|
" 파라미터 +1° ≈ 실제 고도각 +0.76°\n" +
|
|||
|
|
" +6°(기본 · PM 결정 ① 절충안 C) → 고도각 26.40° → 30.9°, 내림각 34.93° → 39.5°\n" +
|
|||
|
|
" 카메라는 0.35 m 올라가고 수평으로 0.20 m 붙는다(궤도 반지름 5.196 m 는 불변).\n" +
|
|||
|
|
" 구 WL 에 직접 대응하는 실측값이 없다(WL 은 usePitchMoving = false 로 껐다) → 이 값은 【추정】.")]
|
|||
|
|
[Range(0f, 30f)] public float backwardPitchAdd = 6f;
|
|||
|
|
|
|||
|
|
[Tooltip("피치 가산/복귀 감쇠 시간(초). 구 WL pitchBlendSmoothTime 실측 0.4.\n" +
|
|||
|
|
"🔴 WL 은 '이동 중 피치 하향'이 세로 출렁임을 만들어 PD #719 ④ 로 기본 off 했다.\n" +
|
|||
|
|
"여기서는 '후진할 때만' 이라 발생 빈도가 낮지만, 출렁임이 보이면 이 값을 먼저 키운다.")]
|
|||
|
|
public float pitchSmoothTime = 0.4f;
|
|||
|
|
|
|||
|
|
[Tooltip("피치 가산의 각속도 상한(도/초). 0 = 무제한.\n" +
|
|||
|
|
"PD #724 교훈에 따라 속도 제한은 이 한 곳에만 둔다(위치 상한은 두지 않는다).")]
|
|||
|
|
public float pitchMaxSpeed = 0f;
|
|||
|
|
|
|||
|
|
[Tooltip("cameraHeight + 가산의 상한(도). 파라미터가 90° 를 넘으면 궤도 수식이 뒤집히므로 안전 상한을 둔다.")]
|
|||
|
|
[Range(60f, 89f)] public float pitchTotalMax = 89f;
|
|||
|
|
|
|||
|
|
[Tooltip("피치를 올리면 궤도 수식 특성상 카메라의 수평 방위도 함께 돈다(78° 기준 파라미터 +1° 당 +0.32°).\n" +
|
|||
|
|
"켜면 그만큼 rotateAround 가산으로 정확히 상쇄해 카메라가 옆으로 밀리지 않는다.\n" +
|
|||
|
|
"상쇄량 = −(atan2(1, sin(h+add) + cos(h+add)) − atan2(1, sin h + cos h))")]
|
|||
|
|
public bool compensatePitchYawCoupling = true;
|
|||
|
|
|
|||
|
|
// ─────────────────────────────────────────── 판정
|
|||
|
|
|
|||
|
|
[Header("전진/후진 판정")]
|
|||
|
|
[Tooltip("이 속도(m/s) 미만이면 정지로 보고 리드·피치를 0 으로 되돌린다. 구 WL followMoveSpeedThreshold 실측 0.15")]
|
|||
|
|
public float moveSpeedThreshold = 0.15f;
|
|||
|
|
|
|||
|
|
[Tooltip("리드·피치가 최대가 되는 기준 속도(m/s). 0 이면 캐릭터의 Actor.Get_MoveSpeed() 를 매 프레임 그대로 쓴다.\n" +
|
|||
|
|
"0 권장 — 이동속도는 테이블/버프에서 오는 데이터라 코드·에셋에 숫자로 박지 않는다(C45).\n" +
|
|||
|
|
"참고: 구 WL lookAheadSpeedReference 실측 3.85")]
|
|||
|
|
public float speedReference = 0f;
|
|||
|
|
|
|||
|
|
[Tooltip("측면 이동 무반응 반각(도). 속도 방향이 카메라 수평 전방과 이루는 각이\n" +
|
|||
|
|
"(90° − 이 값) 을 넘으면 가중치 0, 0° 면 1 로 선형 보간한다.\n" +
|
|||
|
|
"20 = ±70° 안쪽만 전/후진으로 본다.")]
|
|||
|
|
[Range(0f, 45f)] public float sideDeadAngle = 20f;
|
|||
|
|
|
|||
|
|
[Tooltip("한 프레임 이동 거리가 이 값(m)을 넘으면 순간이동(포탈·맵 이동·리스폰)으로 보고\n" +
|
|||
|
|
"속도 계산을 버리고 리드·피치를 즉시 0 으로 스냅한다.")]
|
|||
|
|
public float teleportDistance = 3f;
|
|||
|
|
|
|||
|
|
// ─────────────────────────────────────────── 진단
|
|||
|
|
|
|||
|
|
[Header("진단")]
|
|||
|
|
[Tooltip("CameraMoveLead.LastSample 을 매 프레임 채운다. 검증용 CSV 를 뽑을 때만 켠다.\n" +
|
|||
|
|
"끄더라도 LeadOffset · PitchAdd 프로퍼티는 항상 읽을 수 있다.")]
|
|||
|
|
public bool recordSample = false;
|
|||
|
|
}
|