UniVRM/Scripts/LookAt/VRMLookAtHead.cs
2018-03-27 19:46:11 +09:00

162 lines
5.0 KiB
C#

#pragma warning disable 0414, 0649
using System;
using UniGLTF;
using UnityEngine;
namespace VRM
{
public class VRMLookAtHead : MonoBehaviour
{
public bool DrawGizmo = true;
[SerializeField]
public bool UseUpdate = true;
[SerializeField]
public Transform Target;
[SerializeField]
public OffsetOnTransform Head;
#region Thumbnail
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);
}
#endregion
private void Reset()
{
Target = Camera.main.transform;
var animator = GetComponent<Animator>();
if (animator != null)
{
Head = OffsetOnTransform.Create(animator.GetBoneTransform(HumanBodyBones.Head));
}
}
private void Awake()
{
Head.Setup();
}
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(m_yaw, Head.OffsetRotation.GetColumn(1));
var m = default(Matrix4x4);
m.SetTRS(Vector3.zero, yaw, Vector3.one);
return m;
}
}
[SerializeField, Header("Debug")]
float m_yaw;
public float Yaw
{
get { return m_yaw; }
}
[SerializeField]
float m_pitch;
public float Pitch
{
get { return m_pitch; }
}
public event Action<float, float> YawPitchChanged;
void RaiseYawPitchChanged(float yaw, float pitch)
{
if (m_yaw == yaw && m_pitch == pitch) return;
m_yaw = yaw;
m_pitch = pitch;
var handle = YawPitchChanged;
if (handle != null)
{
handle(yaw, pitch);
}
}
private void Update()
{
if (!UseUpdate) return;
if (Target == null) return;
LookWorldPosition();
}
public void LookWorldPosition()
{
float yaw;
float pitch;
LookWorldPosition(Target.position, out yaw, out pitch);
}
public void LookWorldPosition(Vector3 targetPosition, out float yaw, out float pitch)
{
var localPosition = Head.InitialWorldMatrix.inverse.MultiplyPoint(targetPosition);
Head.OffsetRotation.CalcYawPitch(localPosition, out yaw, out pitch);
RaiseYawPitchChanged(yaw, pitch);
}
}
}