Merge pull request #1984 from Santarh/refactorLookAt

Refactoring about Vrm10 LookAtRuntime
This commit is contained in:
Masataka SUMI 2023-02-15 01:07:57 +09:00 committed by GitHub
commit fcdab51dfe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 184 additions and 138 deletions

View File

@ -69,24 +69,24 @@ namespace UniVRM10
{
EditorGUI.BeginChangeCheck();
var worldOffset = head.localToWorldMatrix.MultiplyPoint(root.Vrm.LookAt.OffsetFromHead);
worldOffset = Handles.PositionHandle(worldOffset, head.rotation);
var eyeWorldPosition = head.localToWorldMatrix.MultiplyPoint(root.Vrm.LookAt.OffsetFromHead);
eyeWorldPosition = Handles.PositionHandle(eyeWorldPosition, head.rotation);
Handles.DrawDottedLine(head.position, worldOffset, 5);
Handles.DrawDottedLine(head.position, eyeWorldPosition, 5);
Handles.SphereHandleCap(0, head.position, Quaternion.identity, 0.02f, Event.current.type);
Handles.SphereHandleCap(0, worldOffset, Quaternion.identity, 0.02f, Event.current.type);
Handles.SphereHandleCap(0, eyeWorldPosition, Quaternion.identity, 0.02f, Event.current.type);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(root.Vrm, "LookAt.OffsetFromHead");
root.Vrm.LookAt.OffsetFromHead = head.worldToLocalMatrix.MultiplyPoint(worldOffset);
root.Vrm.LookAt.OffsetFromHead = head.worldToLocalMatrix.MultiplyPoint(eyeWorldPosition);
}
}
if (Application.isPlaying)
{
OnSceneGUILookAt(root.Vrm.LookAt, root.Runtime.LookAt, head, root.LookAtTargetType, root.Gaze);
OnSceneGUILookAt(root.Vrm.LookAt, root.Runtime.LookAt, root.LookAtTargetType, root.LookAtTarget);
}
else
{
@ -125,28 +125,27 @@ namespace UniVRM10
const float RADIUS = 0.5f;
static void OnSceneGUILookAt(VRM10ObjectLookAt lookAt, Vrm10RuntimeLookAt runtime, Transform head, VRM10ObjectLookAt.LookAtTargetTypes lookAtTargetType, Transform gaze)
static void OnSceneGUILookAt(VRM10ObjectLookAt lookAt, Vrm10RuntimeLookAt runtime, VRM10ObjectLookAt.LookAtTargetTypes lookAtTargetType, Transform lookAtTarget)
{
if (head == null) return;
if (gaze != null)
if (lookAtTargetType == VRM10ObjectLookAt.LookAtTargetTypes.SpecifiedTransform && lookAtTarget != null)
{
{
EditorGUI.BeginChangeCheck();
var newTargetPosition = Handles.PositionHandle(gaze.position, Quaternion.identity);
var newTargetPosition = Handles.PositionHandle(lookAtTarget.position, Quaternion.identity);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(gaze, "Change Look At Target Position");
gaze.position = newTargetPosition;
Undo.RecordObject(lookAtTarget, "Change Look At Target Position");
lookAtTarget.position = newTargetPosition;
}
}
Handles.color = new Color(1, 1, 1, 0.6f);
Handles.DrawDottedLine(runtime.GetLookAtOrigin(head).position, gaze.position, 4.0f);
Handles.DrawDottedLine(runtime.LookAtOriginTransform.position, lookAtTarget.position, 4.0f);
}
var (yaw, pitch) = runtime.GetLookAtYawPitch(head, lookAtTargetType, gaze);
var lookAtOriginMatrix = runtime.GetLookAtOrigin(head).localToWorldMatrix;
var yaw = runtime.Yaw;
var pitch = runtime.Pitch;
var lookAtOriginMatrix = runtime.LookAtOriginTransform.localToWorldMatrix;
Handles.matrix = lookAtOriginMatrix;
var p = lookAt.OffsetFromHead;
Handles.Label(Vector3.zero,

View File

@ -0,0 +1,5 @@
#if UNITY_EDITOR
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("VRM10.Tests")]
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c0bb9ff90c68a3f4bb86b5fed930f30e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -13,11 +13,13 @@
public float LeftPitch { get; }
/// <summary>
/// NOTE: 何故か使われていない
/// Yaw of RightEye
/// </summary>
public float RightYaw { get; }
/// <summary>
/// NOTE: 何故か使われていない
/// Pitch of RightEye
/// </summary>
public float RightPitch { get; }

View File

@ -1,9 +1,6 @@
using System;
using UnityEngine;
using UniGLTF.Extensions.VRMC_vrm;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace UniVRM10
{
@ -12,8 +9,17 @@ namespace UniVRM10
{
public enum LookAtTargetTypes
{
CalcYawPitchToGaze,
SetYawPitch,
/// <summary>
/// Vrm10Instance に設定した Transform を見ます.
/// </summary>
SpecifiedTransform = 0,
/// <summary>
/// Vrm10RuntimeLookAt に設定した Yaw/Pitch 値に従います.
/// </summary>
YawPitchValue = 1,
[Obsolete] CalcYawPitchToGaze = 0,
[Obsolete] SetYawPitch = 1,
}
[SerializeField]

View File

@ -1,5 +1,7 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
namespace UniVRM10
@ -43,11 +45,20 @@ namespace UniVRM10
public bool DrawLookAtGizmo = true;
/// <summay>
/// LookAtTargetTypes.CalcYawPitchToGaze時の注視点
/// The model looks at position of the Transform specified in this field.
/// That behaviour is available only when LookAtTargetType is SpecifiedTransform.
///
/// モデルはここで指定した Transform の位置の方向に目を向けます。
/// LookAtTargetType を SpecifiedTransform に設定したときのみ有効です。
/// </summary>
[SerializeField]
public Transform Gaze;
[SerializeField, FormerlySerializedAs("Gaze")]
public Transform LookAtTarget;
/// <summary>
/// Specify "LookAt" behaviour at runtime.
///
/// 実行時の目の動かし方を指定します。
/// </summary>
[SerializeField]
public VRM10ObjectLookAt.LookAtTargetTypes LookAtTargetType;
@ -110,15 +121,7 @@ namespace UniVRM10
// cause new Vrm10Runtime.
// init LookAt init rotation.
var runtime = Runtime;
if (LookAtTargetType == VRM10ObjectLookAt.LookAtTargetTypes.CalcYawPitchToGaze)
{
if (Gaze == null)
{
LookAtTargetType = VRM10ObjectLookAt.LookAtTargetTypes.SetYawPitch;
}
}
var _ = Runtime;
}
private void Update()
@ -165,6 +168,15 @@ namespace UniVRM10
return true;
}
#region Obsolete
[Obsolete]
public Transform Gaze
{
get => LookAtTarget;
set => LookAtTarget = value;
}
#endregion
}
}

View File

@ -63,7 +63,7 @@ namespace UniVRM10
ControlRig = new Vrm10RuntimeControlRig(target.Humanoid, m_target.transform, controlRigInitialRotations);
}
Constraints = target.GetComponentsInChildren<IVrm10Constraint>();
LookAt = new Vrm10RuntimeLookAt(target.Vrm.LookAt, target.Humanoid, m_head, target.LookAtTargetType, target.Gaze);
LookAt = new Vrm10RuntimeLookAt(target.Vrm.LookAt, target.Humanoid, m_head);
Expression = new Vrm10RuntimeExpression(target, LookAt, LookAt.EyeDirectionApplicable);
var instance = target.GetComponent<RuntimeGltfInstance>();
@ -191,7 +191,7 @@ namespace UniVRM10
}
// 3. Gaze control
LookAt.Process(m_target.LookAtTargetType, m_target.Gaze);
LookAt.Process(m_target.LookAtTargetType, m_target.LookAtTarget);
// 4. Expression
Expression.Process();

View File

@ -1,128 +1,139 @@
using System;
using UniGLTF.Extensions.VRMC_vrm;
using UnityEditor;
using UnityEngine;
namespace UniVRM10
{
public sealed class Vrm10RuntimeLookAt : ILookAtEyeDirectionProvider
{
VRM10ObjectLookAt m_lookat;
private readonly VRM10ObjectLookAt _lookAt;
private readonly Transform _head;
private readonly Vector3 _lookAtOriginTransformLocalPosition;
private readonly Quaternion _lookAtOriginTransformLocalRotation;
private Transform m_head;
private Transform m_leftEye;
private Transform m_rightEye;
private ILookAtEyeDirectionApplicable _eyeDirectionApplicable;
internal ILookAtEyeDirectionApplicable EyeDirectionApplicable => _eyeDirectionApplicable;
internal ILookAtEyeDirectionApplicable EyeDirectionApplicable { get; }
public float Yaw { get; private set; }
public float Pitch { get; private set; }
public LookAtEyeDirection EyeDirection { get; private set; }
#region LookAtTargetTypes.CalcYawPitchToGaze
// 座標計算用のempty
Transform m_lookAtSpace;
public Transform GetLookAtOrigin(Transform head)
{
if (!Application.isPlaying)
{
return null;
}
if (m_lookAtSpace == null)
{
m_lookAtSpace = new GameObject("_lookat_origin_").transform;
m_lookAtSpace.SetParent(head);
}
return m_lookAtSpace;
}
/// <summary>
/// Headローカルの注視点からYaw, Pitch角を計算する
/// Transform that indicates the position center of eyes.
/// This only represents the position of center of eyes, not the viewing direction.
/// Local +Z axis represents forward vector of the head.
/// Local +Y axis represents up vector of the head.
///
/// 目の位置を示す Transform。
/// 視線方向は反映されない。
/// ローカル +Z 軸が頭の正面方向を表す。
/// ローカル +Y 軸が頭の上方向を表す。
/// </summary>
(float, float) CalcLookAtYawPitch(Vector3 targetWorldPosition, Transform head)
{
var lookAtSpace = GetLookAtOrigin(head);
lookAtSpace.localPosition = m_lookat.OffsetFromHead;
var localPosition = lookAtSpace.worldToLocalMatrix.MultiplyPoint(targetWorldPosition);
float yaw, pitch;
Matrix4x4.identity.CalcYawPitch(localPosition, out yaw, out pitch);
return (yaw, pitch);
}
#endregion
public Transform LookAtOriginTransform { get; }
#region LookAtTargetTypes.SetYawPitch
float m_yaw;
float m_pitch;
/// <summary>
/// LookAtTargetTypes.SetYawPitch時の視線の角度を指定する
/// </summary>
/// <param name="yaw">Headボーンのforwardに対するyaw角(度)</param>
/// <param name="pitch">Headボーンのforwardに対するpitch角(度)</param>
public void SetLookAtYawPitch(float yaw, float pitch)
internal Vrm10RuntimeLookAt(VRM10ObjectLookAt lookAt, UniHumanoid.Humanoid humanoid, Transform head)
{
m_yaw = yaw;
m_pitch = pitch;
}
#endregion
_lookAt = lookAt;
_head = head;
LookAtOriginTransform = InitializeEyePositionTransform(_head, _lookAt.OffsetFromHead);
_lookAtOriginTransformLocalPosition = LookAtOriginTransform.localPosition;
_lookAtOriginTransformLocalRotation = LookAtOriginTransform.localRotation;
/// <summary>
/// LookAtTargetType に応じた yaw, pitch を得る
/// </summary>
/// <returns>Headボーンのforwardに対するyaw角(度), pitch角(度)</returns>
public (float, float) GetLookAtYawPitch(Transform head, VRM10ObjectLookAt.LookAtTargetTypes lookAtTargetType, Transform gaze)
{
switch (lookAtTargetType)
var leftEyeBone = humanoid.GetBoneTransform(HumanBodyBones.LeftEye);
var rightEyeBone = humanoid.GetBoneTransform(HumanBodyBones.RightEye);
if (_lookAt.LookAtType == LookAtType.bone && leftEyeBone != null && rightEyeBone != null)
{
case VRM10ObjectLookAt.LookAtTargetTypes.CalcYawPitchToGaze:
// Gaze(Transform)のワールド位置に対して計算する
return CalcLookAtYawPitch(gaze.position, head);
case VRM10ObjectLookAt.LookAtTargetTypes.SetYawPitch:
// 事前にSetYawPitchした値を使う
return (m_yaw, m_pitch);
}
throw new NotImplementedException();
}
internal Vrm10RuntimeLookAt(VRM10ObjectLookAt lookat, UniHumanoid.Humanoid humanoid, Transform head, VRM10ObjectLookAt.LookAtTargetTypes lookAtTargetType, Transform gaze)
{
// 初期姿勢で初期化する!
GetLookAtOrigin(head);
m_lookat = lookat;
m_head = head;
m_leftEye = humanoid.GetBoneTransform(HumanBodyBones.LeftEye);
m_rightEye = humanoid.GetBoneTransform(HumanBodyBones.RightEye);
var isRuntimeAsset = true;
#if UNITY_EDITOR
isRuntimeAsset = Application.isPlaying && !PrefabUtility.IsPartOfAnyPrefab(m_head);
#endif
if (isRuntimeAsset && lookAtTargetType == VRM10ObjectLookAt.LookAtTargetTypes.CalcYawPitchToGaze && gaze == null)
{
gaze = new GameObject().transform;
gaze.name = "__LOOKAT_GAZE__";
gaze.SetParent(m_head);
gaze.localPosition = Vector3.forward;
}
// bone が無いときのエラー防止。マイグレーション失敗?
if (m_lookat.LookAtType == LookAtType.bone && m_leftEye != null && m_rightEye != null)
{
_eyeDirectionApplicable = new LookAtEyeDirectionApplicableToBone(m_leftEye, m_rightEye, m_lookat.HorizontalOuter, m_lookat.HorizontalInner, m_lookat.VerticalDown, m_lookat.VerticalUp);
EyeDirectionApplicable = new LookAtEyeDirectionApplicableToBone(leftEyeBone, rightEyeBone, _lookAt.HorizontalOuter, _lookAt.HorizontalInner, _lookAt.VerticalDown, _lookAt.VerticalUp);
}
else
{
_eyeDirectionApplicable = new LookAtEyeDirectionApplicableToExpression(m_lookat.HorizontalOuter, m_lookat.HorizontalInner, m_lookat.VerticalDown, m_lookat.VerticalUp);
EyeDirectionApplicable = new LookAtEyeDirectionApplicableToExpression(_lookAt.HorizontalOuter, _lookAt.HorizontalInner, _lookAt.VerticalDown, _lookAt.VerticalUp);
}
}
internal void Process(VRM10ObjectLookAt.LookAtTargetTypes lookAtTargetType, Transform gaze)
internal void Process(VRM10ObjectLookAt.LookAtTargetTypes lookAtTargetType, Transform lookAtTarget)
{
var (yaw, pitch) = GetLookAtYawPitch(m_head, lookAtTargetType, gaze);
EyeDirection = new LookAtEyeDirection(yaw, pitch, 0, 0);
LookAtOriginTransform.localPosition = _lookAtOriginTransformLocalPosition;
LookAtOriginTransform.localRotation = _lookAtOriginTransformLocalRotation;
switch (lookAtTargetType)
{
case VRM10ObjectLookAt.LookAtTargetTypes.SpecifiedTransform:
// NOTE: 指定された Transform の位置を向くように Yaw/Pitch を計算して適用する
if (lookAtTarget != null)
{
var value = CalculateYawPitchFromLookAtPosition(lookAtTarget.position);
SetYawPitchManually(value.Yaw, value.Pitch);
}
break;
case VRM10ObjectLookAt.LookAtTargetTypes.YawPitchValue:
// NOTE: 直接 Set された Yaw/Pitch を使って計算する
break;
}
EyeDirection = new LookAtEyeDirection(Yaw, Pitch, 0, 0);
}
/// <summary>
/// Yaw/Pitch 値を直接設定します。
/// LookAtTargetTypes が SpecifiedTransform の場合、ここで設定しても値は上書きされます。
/// </summary>
/// <param name="yaw">Headボーンのforwardに対するyaw角(度)</param>
/// <param name="pitch">Headボーンのforwardに対するpitch角(度)</param>
public void SetYawPitchManually(float yaw, float pitch)
{
Yaw = yaw;
Pitch = pitch;
}
public (float Yaw, float Pitch) CalculateYawPitchFromLookAtPosition(Vector3 lookAtWorldPosition)
{
var localPosition = LookAtOriginTransform.worldToLocalMatrix.MultiplyPoint(lookAtWorldPosition);
Matrix4x4.identity.CalcYawPitch(localPosition, out var yaw, out var pitch);
return (yaw, pitch);
}
private static Transform InitializeEyePositionTransform(Transform head, Vector3 eyeOffsetValue)
{
if (!Application.isPlaying) return null;
// NOTE: このメソッドを実行するとき、モデル全体は初期姿勢T-Poseでなければならない。
var eyePositionTransform = new GameObject("_eye_transform_").transform;
eyePositionTransform.SetParent(head);
eyePositionTransform.localPosition = eyeOffsetValue;
eyePositionTransform.rotation = Quaternion.identity;
return eyePositionTransform;
}
#region Obsolete
[Obsolete]
public Transform GetLookAtOrigin(Transform head)
{
return LookAtOriginTransform;
}
[Obsolete]
public void SetLookAtYawPitch(float yaw, float pitch)
{
SetYawPitchManually(yaw, pitch);
}
[Obsolete]
public (float, float) GetLookAtYawPitch(
Transform head,
VRM10ObjectLookAt.LookAtTargetTypes lookAtTargetType,
Transform gaze)
{
switch (lookAtTargetType)
{
case VRM10ObjectLookAt.LookAtTargetTypes.SpecifiedTransform:
return CalculateYawPitchFromLookAtPosition(gaze.position);
case VRM10ObjectLookAt.LookAtTargetTypes.YawPitchValue:
return (Yaw, Pitch);
default:
throw new ArgumentOutOfRangeException(nameof(lookAtTargetType), lookAtTargetType, null);
}
}
#endregion
}
}

View File

@ -69,8 +69,8 @@ namespace UniVRM10.VRM10Viewer
m_blink = instance.gameObject.AddComponent<VRM10Blinker>();
m_autoExpression = instance.gameObject.AddComponent<VRM10AutoExpression>();
m_controller.LookAtTargetType = VRM10ObjectLookAt.LookAtTargetTypes.CalcYawPitchToGaze;
m_controller.Gaze = lookAtTarget;
m_controller.LookAtTargetType = VRM10ObjectLookAt.LookAtTargetTypes.SpecifiedTransform;
m_controller.LookAtTarget = lookAtTarget;
}
}