254 lines
8.1 KiB
C#
254 lines
8.1 KiB
C#
#pragma warning disable 0414, 0649
|
|
using System;
|
|
using System.Linq;
|
|
using System.Collections.Generic;
|
|
using UniGLTF;
|
|
using UnityEngine;
|
|
|
|
|
|
namespace VRM
|
|
{
|
|
[Obsolete("Use VRMLookAtHead")]
|
|
public class VRMLookAt : MonoBehaviour
|
|
{
|
|
public bool DrawGizmo = true;
|
|
|
|
[SerializeField]
|
|
public bool UseUpdate = true;
|
|
|
|
[SerializeField]
|
|
public Transform Target;
|
|
|
|
[SerializeField]
|
|
public OffsetOnTransform LeftEye;
|
|
|
|
[SerializeField]
|
|
public OffsetOnTransform RightEye;
|
|
|
|
[SerializeField]
|
|
public OffsetOnTransform Head;
|
|
|
|
[SerializeField, Header("Degree Mapping")]
|
|
public CurveMapper HorizontalOuter = new CurveMapper(90.0f, 10.0f);
|
|
|
|
[SerializeField]
|
|
public CurveMapper HorizontalInner = new CurveMapper(90.0f, 10.0f);
|
|
|
|
[SerializeField]
|
|
public CurveMapper VerticalDown = new CurveMapper(90.0f, 10.0f);
|
|
|
|
[SerializeField]
|
|
public CurveMapper VerticalUp = new CurveMapper(90.0f, 10.0f);
|
|
|
|
public Texture2D CreateThumbnail()
|
|
{
|
|
var texture = new Texture2D(2048, 2048);
|
|
{
|
|
var go = new GameObject("ThumbCamera");
|
|
var camera = go.AddComponent<Camera>();
|
|
CreateThumbnail(camera, texture);
|
|
if (Application.isPlaying) { GameObject.Destroy(go); } else { GameObject.DestroyImmediate(go); }
|
|
}
|
|
return texture;
|
|
}
|
|
void CreateThumbnail(Camera camera, Texture2D dst)
|
|
{
|
|
RenderTexture currentRT = RenderTexture.active;
|
|
{
|
|
var renderTexture = new RenderTexture(dst.width, dst.height, 24);
|
|
camera.targetTexture = renderTexture;
|
|
RenderTexture.active = renderTexture;
|
|
LookFace(camera.transform);
|
|
camera.Render();
|
|
dst.ReadPixels(new Rect(0, 0, dst.width, dst.height), 0, 0);
|
|
|
|
RenderTexture.active = currentRT;
|
|
camera.targetTexture = null;
|
|
if (Application.isPlaying)
|
|
{
|
|
UnityEngine.Object.Destroy(renderTexture);
|
|
}
|
|
else
|
|
{
|
|
UnityEngine.Object.DestroyImmediate(renderTexture);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void LookFace(Transform t)
|
|
{
|
|
if (Head.Transform == null) return;
|
|
var head = Head.Transform;
|
|
var headPosition = head.position + new Vector3(0, 0.05f, 0);
|
|
t.position = headPosition + Head.WorldMatrix.ExtractRotation() * new Vector3(0, 0, 0.7f);
|
|
t.LookAt(headPosition);
|
|
}
|
|
|
|
public void CopyTo(GameObject _dst, Dictionary<Transform, Transform> map)
|
|
{
|
|
var dst = _dst.AddComponent<VRMLookAt>();
|
|
dst.Target = Target;
|
|
dst.Head = OffsetOnTransform.Create(map[Head.Transform]);
|
|
dst.RightEye = OffsetOnTransform.Create(map[RightEye.Transform]);
|
|
dst.LeftEye = OffsetOnTransform.Create(map[LeftEye.Transform]);
|
|
|
|
dst.HorizontalOuter = HorizontalOuter;
|
|
dst.HorizontalInner = HorizontalInner;
|
|
dst.VerticalDown = VerticalDown;
|
|
dst.VerticalUp = VerticalUp;
|
|
}
|
|
|
|
private void Reset()
|
|
{
|
|
Target = Camera.main.transform;
|
|
|
|
GetBones();
|
|
}
|
|
|
|
private void OnValidate()
|
|
{
|
|
HorizontalInner.OnValidate();
|
|
HorizontalOuter.OnValidate();
|
|
VerticalUp.OnValidate();
|
|
VerticalDown.OnValidate();
|
|
}
|
|
|
|
public void GetBones()
|
|
{
|
|
var animator = GetComponent<Animator>();
|
|
if (animator != null)
|
|
{
|
|
LeftEye = OffsetOnTransform.Create(animator.GetBoneTransform(HumanBodyBones.LeftEye));
|
|
RightEye = OffsetOnTransform.Create(animator.GetBoneTransform(HumanBodyBones.RightEye));
|
|
Head = OffsetOnTransform.Create(animator.GetBoneTransform(HumanBodyBones.Head));
|
|
}
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
Head.Setup();
|
|
LeftEye.Setup();
|
|
RightEye.Setup();
|
|
}
|
|
|
|
#region Gizmo
|
|
static void DrawMatrix(Matrix4x4 m, float size)
|
|
{
|
|
Gizmos.matrix = m;
|
|
Gizmos.color = Color.red;
|
|
Gizmos.DrawLine(Vector3.zero, Vector3.right * size);
|
|
Gizmos.color = Color.green;
|
|
Gizmos.DrawLine(Vector3.zero, Vector3.up * size);
|
|
Gizmos.color = Color.blue;
|
|
Gizmos.DrawLine(Vector3.zero, Vector3.forward * size);
|
|
}
|
|
|
|
const float SIZE = 0.5f;
|
|
|
|
private void OnDrawGizmos()
|
|
{
|
|
if (!DrawGizmo) return;
|
|
|
|
if (LeftEye.Transform != null & RightEye.Transform != null)
|
|
{
|
|
DrawMatrix(LeftEye.WorldMatrix, SIZE);
|
|
DrawMatrix(RightEye.WorldMatrix, SIZE);
|
|
|
|
}
|
|
else
|
|
{
|
|
DrawMatrix(Head.WorldMatrix, SIZE);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
static Matrix4x4 LookAtMatrixFromWorld(Vector3 from, Vector3 target)
|
|
{
|
|
var pos = new Vector4(from.x, from.y, from.z, 1);
|
|
return LookAtMatrix(UnityExtensions.Matrix4x4FromColumns(Vector3.right, Vector3.up, Vector3.forward, pos), target);
|
|
}
|
|
|
|
static Matrix4x4 LookAtMatrix(Vector3 up_vector, Vector3 localPosition)
|
|
{
|
|
var z_axis = localPosition.normalized;
|
|
var x_axis = Vector3.Cross(up_vector, z_axis).normalized;
|
|
var y_axis = Vector3.Cross(z_axis, x_axis).normalized;
|
|
return UnityExtensions.Matrix4x4FromColumns(x_axis, y_axis, z_axis, new Vector4(0, 0, 0, 1));
|
|
}
|
|
|
|
static Matrix4x4 LookAtMatrix(Matrix4x4 m, Vector3 target)
|
|
{
|
|
return LookAtMatrix(Vector3.up, m.inverse.MultiplyPoint(target));
|
|
}
|
|
|
|
public Matrix4x4 YawMatrix
|
|
{
|
|
get
|
|
{
|
|
var yaw = Quaternion.AngleAxis(Yaw, Head.OffsetRotation.GetColumn(1));
|
|
var m = default(Matrix4x4);
|
|
m.SetTRS(Vector3.zero, yaw, Vector3.one);
|
|
return m;
|
|
}
|
|
}
|
|
|
|
[SerializeField, Header("Debug")]
|
|
public float Yaw;
|
|
public float Pitch;
|
|
private void LateUpdate()
|
|
{
|
|
if (!UseUpdate) return;
|
|
if (Target == null) return;
|
|
|
|
LookWorldPosition(Target.position);
|
|
}
|
|
|
|
public void LookWorldPosition(Vector3 targetPosition)
|
|
{
|
|
var localPosition = Head.InitialWorldMatrix.inverse.MultiplyPoint(targetPosition);
|
|
Head.OffsetRotation.CalcYawPitch(localPosition, out Yaw, out Pitch);
|
|
|
|
ApplyRotations(Yaw, Pitch);
|
|
}
|
|
|
|
void ApplyRotations(float yaw, float pitch)
|
|
{
|
|
// horizontal
|
|
float leftYaw, rightYaw;
|
|
if (yaw < 0)
|
|
{
|
|
leftYaw = -HorizontalOuter.Map(-yaw);
|
|
rightYaw = -HorizontalInner.Map(-yaw);
|
|
}
|
|
else
|
|
{
|
|
rightYaw = HorizontalOuter.Map(yaw);
|
|
leftYaw = HorizontalInner.Map(yaw);
|
|
}
|
|
|
|
// vertical
|
|
if (pitch < 0)
|
|
{
|
|
pitch = -VerticalDown.Map(-pitch);
|
|
}
|
|
else
|
|
{
|
|
pitch = VerticalUp.Map(pitch);
|
|
}
|
|
|
|
// Apply
|
|
if (LeftEye.Transform != null && RightEye.Transform != null)
|
|
{
|
|
// 目に値を適用する
|
|
LeftEye.Transform.rotation = LeftEye.InitialWorldMatrix.ExtractRotation() * Head.OffsetRotation.YawPitchRotation(leftYaw, pitch);
|
|
RightEye.Transform.rotation = RightEye.InitialWorldMatrix.ExtractRotation() * Head.OffsetRotation.YawPitchRotation(rightYaw, pitch);
|
|
}
|
|
else if (Head.Transform != null)
|
|
{
|
|
// 頭に値を適用する
|
|
Head.Transform.rotation = Head.InitialWorldMatrix.ExtractRotation() * Head.OffsetRotation.YawPitchRotation(yaw, pitch);
|
|
}
|
|
}
|
|
}
|
|
}
|