You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

428 lines
14 KiB

using System;
using System.Collections;
using System.Collections.Generic;
using uc;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
[ExecuteInEditMode]
public class FMCRControl : MonoBehaviour
{
public enum BlendStrategy
{
CutCubic,
Cubic,
Akima
}
[Header("Control")]
public bool autoAddToPriority = true;
public int priority = 0;
[Header("Lens")]
[Range(1, 179)]
public int fieldOfView = 60;
public float nearClipPlane = 0.3f;
public float farClipPlane = 1000;
[Header("FMCR")]
public BlendStrategy blendStrategy = BlendStrategy.CutCubic;
public FreeMotionCameraRig FMCR;
public ComposerSettings composerSettings;
public Transform composerTarget;
public TransposerSettings transposerSettings;
public Transform transposerTarget;
[SerializeField]
public static bool showCameraGuide = false;
public Vector3 vCamPosition { get { return transposerTargetPosition; } }
public Quaternion vCamRotation
{
get
{
float fov = fieldOfView * Mathf.Deg2Rad;
float z = 0.5f / Mathf.Tan(fov / 2);
float v_point = 0.5f;
float h_point = 0.5f;
float dutch = 0;
if (composerSettings != null)
{
v_point = composerSettings.SoftGuideBottom * 0.5f + composerSettings.SoftGuideTop * 0.5f;
h_point = composerSettings.SoftGuideLeft * 0.5f + composerSettings.SoftGuideRight * 0.5f;
dutch = composerSettings.Dutch;
}
float angle_v = Mathf.Atan2(v_point - 0.5f, z) * Mathf.Rad2Deg;
float aspect = 1;
if (FMCR != null && FMCR.FMCRCamera != null)
aspect = FMCR.FMCRCamera.aspect;
float angle_h = -Mathf.Atan2(h_point - 0.5f, z / aspect) * Mathf.Rad2Deg;
Quaternion rotation = Quaternion.identity;
Vector3 lookat = composerTargetPosition - transposerTargetPosition;
if (lookat == Vector3.zero)
rotation *= transposerTarget.rotation;
else
rotation *= Quaternion.LookRotation(lookat);
rotation *= Quaternion.Euler(angle_v, angle_h, dutch);
return rotation;
}
}
public class myReverserClass : IComparer<int>
{
int IComparer<int>.Compare(int x, int y) { return y - x; }
}
static SortedList<int, FMCRControl> priorityList = new SortedList<int, FMCRControl>(new myReverserClass());
static FMCRControl activeControl = null;
static public FMCRControl ActiveControl { get { return activeControl; } }
public Vector3 composerTargetPosition
{
get
{
Vector3 p = Vector3.zero;
Transform target = transform;
if (composerTarget != null)
target = composerTarget;
else if (transposerTarget != null)
target = transposerTarget;
p += target.position;
//screen space??
if (composerSettings != null)
p += target.TransformVector(composerSettings.TrackedObjectOffset);
return p;
}
}
Vector3 transposerTargetPosition
{
get
{
Vector3 position = Vector3.zero;
Transform target = transform;
if (transposerTarget != null)
target = transposerTarget;
position += target.position;
if (transposerSettings != null)
{
switch (transposerSettings.TransposerOffsetMode)
{
case TransposerSettings.TransposerOffsetType.LocalSpaceOnTargetAssignment:
Debug.LogError("transposerTargetPosition for LocalSpaceOnTargetAssignment is not implemeted.");
break;
case TransposerSettings.TransposerOffsetType.LocalSpaceLockedUpVector:
Debug.LogError("transposerTargetPosition for LocalSpaceLockedUpVector is not implemeted.");
break;
case TransposerSettings.TransposerOffsetType.LocalSpaceLockedToTarget:
position += target.TransformVector(transposerSettings.OffsetFromTarget);
break;
case TransposerSettings.TransposerOffsetType.WorldSpace:
position += transposerSettings.OffsetFromTarget;
break;
}
}
return position;
}
}
private void OnEnable()
{
if (priorityList.ContainsKey(priority))
{
priorityList.Remove(priority);
}
if (autoAddToPriority)
priorityList.Add(priority, this);
UpdateActiveControl();
}
private void OnDisable()
{
if (priorityList.ContainsKey(priority) && priorityList[priority] == this)
{
priorityList.Remove(priority);
}
UpdateActiveControl();
}
void UpdateActiveControl()
{
if (priorityList.Count > 0)
{
IEnumerator<KeyValuePair<int, FMCRControl>> it = priorityList.GetEnumerator();
it.MoveNext();
activeControl = it.Current.Value;
}
}
// Update is called once per frame
void Update()
{
if (activeControl != this || Application.isPlaying == false)
return;
if (FMCR != null && FMCR.FMCRCamera != null)
{
FMCR.FMCRCamera.fieldOfView = fieldOfView;
FMCR.FMCRCamera.nearClipPlane = nearClipPlane;
FMCR.FMCRCamera.farClipPlane = farClipPlane;
}
UpdateTransposer();
UpdateComposer();
}
Rect softRect = new Rect(0.5f, 0.5f, 0, 0);
Rect hardRect = new Rect(0,0,1,1);
float fov = 0;
float aspect = 1;
public float CurrentAspect { get { return aspect; } }
float hSpeed = 1;
float vSpeed = 1;
float dSpeed = 1;
float softLeftAngle = 0;
float softRightAngle = 0;
float softTopAngle = 0;
float softBottomAngle = 0;
//float hardLeftAngle = 0;
//float hardRightAngle = 0;
//float hardTopAngle = 0;
//float hardBottomAngle = 0;
float dutch = 0;
void UpdateAngle()
{
bool needUpdate = false;
if (composerSettings != null)
{
if (softRect != composerSettings.SoftGuideRect || hardRect != composerSettings.HardGuideRect)
{
softRect = composerSettings.SoftGuideRect;
hardRect = composerSettings.HardGuideRect;
hSpeed = composerSettings.HorizontalSoftTrackingSpeed;
vSpeed = composerSettings.VerticalSoftTrackingSpeed;
dSpeed = composerSettings.DutchTrackingSpeed;
dutch = composerSettings.Dutch;
needUpdate = true;
}
}
if (FMCR != null && FMCR.FMCRCamera != null)
{
if (fov != FMCR.FMCRCamera.fieldOfView || aspect != FMCR.FMCRCamera.aspect)
{
fov = FMCR.FMCRCamera.fieldOfView;
aspect = FMCR.FMCRCamera.aspect;
needUpdate = true;
}
}
if (needUpdate)
{
float z = 0.5f / Mathf.Tan(fov * Mathf.Deg2Rad / 2);
//hardLeftAngle = -Mathf.Atan2(hardRect.xMin - 0.5f, z / aspect) * Mathf.Rad2Deg;
//hardRightAngle = -Mathf.Atan2(hardRect.xMax - 0.5f, z / aspect) * Mathf.Rad2Deg;
softLeftAngle = -Mathf.Atan2(softRect.xMin - 0.5f, z / aspect) * Mathf.Rad2Deg;
softRightAngle = -Mathf.Atan2(softRect.xMax - 0.5f, z / aspect) * Mathf.Rad2Deg;
softTopAngle = -Mathf.Atan2(softRect.yMin - 0.5f, z) * Mathf.Rad2Deg;
softBottomAngle = -Mathf.Atan2(softRect.yMax - 0.5f, z) * Mathf.Rad2Deg;
//hardTopAngle = -Mathf.Atan2(hardRect.yMin - 0.5f, z) * Mathf.Rad2Deg;
//hardBottomAngle = -Mathf.Atan2(hardRect.yMax - 0.5f, z) * Mathf.Rad2Deg;
}
}
void UpdateComposer()
{
if (FMCR == null || FMCR.FMCRCamera == null)
return;
UpdateAngle();
Vector3 screenPoint = FMCR.FMCRCamera.WorldToViewportPoint(composerTargetPosition);
//is this necessary?
if (screenPoint.z == 0)
return;
float hStep = Mathf.Clamp01(Time.deltaTime / hSpeed);
float vStep = Mathf.Clamp01(Time.deltaTime / vSpeed);
float dStep = Mathf.Clamp01(Time.deltaTime / dSpeed);
{
float sideways = FMCR.sideways;
//float angle_hl = UC.Math.Nearest360(hardLeftAngle, sideways);
//float angle_hr = UC.Math.Nearest360(hardRightAngle, sideways);
float angle_sl = UC.Math.Nearest360(softLeftAngle, sideways);
float angle_sr = UC.Math.Nearest360(softRightAngle, sideways);
//if (horizontal > angle_hl)
// FMCR.sideways = angle_sl;
//else if (horizontal < angle_hr)
// FMCR.sideways = angle_sr;
//else
if (FMCR.sideways > angle_sl)
FMCR.sideways = Mathf.Lerp(sideways, angle_sl, hStep);
else if (FMCR.sideways < angle_sr)
FMCR.sideways = Mathf.Lerp(sideways, angle_sr, hStep);
}
{
float tilt = FMCR.tilt;
//float angle_hb = UC.Math.Nearest360(hardBottomAngle, tilt);
//float angle_ht = UC.Math.Nearest360(hardTopAngle, tilt);
float angle_sb = UC.Math.Nearest360(softBottomAngle, tilt);
float angle_st = UC.Math.Nearest360(softTopAngle, tilt);
//if (vertical > angle_hb)
// FMCR.sideways = angle_sb;
//else if (vertical < angle_ht)
// FMCR.sideways = angle_st;
//else
if (FMCR.tilt > angle_sb)
FMCR.tilt = Mathf.Lerp(tilt, angle_sb, vStep);
else if (FMCR.tilt < angle_st)
FMCR.tilt = Mathf.Lerp(tilt, angle_st, vStep);
}
FMCR.roll = Mathf.Lerp(FMCR.roll, dutch, dStep);
}
void UpdateTransposer()
{
if (FMCR == null)
return;
Vector3 step = Vector3.one;
if (transposerSettings != null)
{
step.x = Mathf.Clamp01(Time.deltaTime / transposerSettings.TrackingSpeeds.x);
step.y = Mathf.Clamp01(Time.deltaTime / transposerSettings.TrackingSpeeds.y);
step.z = Mathf.Clamp01(Time.deltaTime / transposerSettings.TrackingSpeeds.z);
}
Vector3 originTransformPosition = FMCR.NodePosition;
bool isCutCubic = (blendStrategy == BlendStrategy.CutCubic);
FMCR.transform.position = Lerp(FMCR.transform.position, composerTargetPosition, isCutCubic ? Vector3.one : step);
Vector3 a = FMCR.transform.InverseTransformPoint(transposerTargetPosition);
Vector3 b = FMCR.transform.InverseTransformPoint(originTransformPosition);
bool isAkima = (blendStrategy == BlendStrategy.Akima);
Vector3 hvdTarget = FMCR.XYZToHVDNearest(Lerp(b, a, isAkima ? Vector3.one : step));
//TODO
if (transposerTargetPosition == composerTargetPosition && transposerSettings != null && transposerSettings.OffsetFromTarget == Vector3.zero)
{
hvdTarget = FMCR.RotationToHVD(transposerTarget.rotation, 0.1f);
hvdTarget.z = 0;
}
FMCR.horizon = Mathf.Lerp(FMCR.horizon, hvdTarget.x, isAkima ? step.x : 1);
FMCR.vertical = Mathf.Lerp(FMCR.vertical, hvdTarget.y, isAkima ? step.y : 1);
FMCR.distance = Mathf.Lerp(FMCR.distance, hvdTarget.z, isAkima ? step.z : 1);
}
#if UNITY_EDITOR
private void OnGUI()
{
if (activeControl != this || showCameraGuide == false)
return;
if (FMCR == null || FMCR.FMCRCamera == null)
return;
DrawComposerGUI(FMCR.FMCRCamera, FMCR.FMCRCamera.pixelRect);
}
#endif
delegate void DrawRect(float x, float y, float w, float h);
delegate void DrawZone(Rect rect);
public void DrawComposerGUI(Camera cam, Rect screenRect)
{
if (cam == null)
return;
Color hex_color;
Color originalColor = GUI.color;
string hardColorString = "#C9615C";
string softColorString = "#62B9CF";
string targetColorString = "#FFF82A";
float alpha = 0.3f;
DrawRect drawRect = (float x, float y, float w, float h) =>
{
float xx = screenRect.width * x + screenRect.x;
float yy = screenRect.height * (1 - y) + screenRect.y;
Rect r = new Rect(xx, yy, screenRect.width * w, -screenRect.height * h);
GUI.DrawTexture(r, Texture2D.whiteTexture);
};
DrawZone drawZone = (Rect rect) =>
{
drawRect(0, 0, rect.xMin, 1);
drawRect(rect.xMax, 0, 1 - rect.xMax, 1);
drawRect(rect.xMin, 0, rect.xMax - rect.xMin, rect.yMin);
drawRect(rect.xMin, rect.yMax, rect.xMax - rect.xMin, 1 - rect.yMax);
};
if (ColorUtility.TryParseHtmlString(hardColorString, out hex_color))
{
hex_color.a = alpha;
GUI.color = hex_color;
if (composerSettings != null)
drawZone(composerSettings.HardGuideRect);
}
if (ColorUtility.TryParseHtmlString(softColorString, out hex_color))
{
hex_color.a = alpha;
GUI.color = hex_color;
if(composerSettings != null)
drawZone(composerSettings.SoftGuideRect);
}
if (ColorUtility.TryParseHtmlString(targetColorString, out hex_color))
{
Vector3 pt = cam.WorldToViewportPoint(composerTargetPosition);
float hSize = screenRect.height * 0.01f;
float x = pt.x * screenRect.width + screenRect.x - hSize;
float y = (1 - pt.y) * screenRect.height - hSize + screenRect.y;
GUI.color = hex_color;
GUI.DrawTexture(new Rect(x, y, hSize * 2, hSize * 2), Texture2D.whiteTexture);
}
GUI.color = originalColor;
}
static Vector3 Lerp(Vector3 a, Vector3 b, Vector3 t)
{
return new Vector3(Mathf.Lerp(a.x, b.x, t.x), Mathf.Lerp(a.y, b.y, t.y), Mathf.Lerp(a.z, b.z, t.z));
}
[ContextMenu("DrawCameraGuide")]
void DrawCameraGuide()
{
showCameraGuide = true;
}
[ContextMenu("HideCameraGuide")]
void HideCameraGuide()
{
showCameraGuide = false;
}
}