mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-03-26 04:15:26 -05:00
ClothViewer
This commit is contained in:
parent
bbcb74c4ed
commit
3936ce5efa
8
Assets/VRM10_Samples/ClothSample/ClothViewer.meta
Normal file
8
Assets/VRM10_Samples/ClothSample/ClothViewer.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: db40660c554df69458e2f1385c6b5b89
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
73
Assets/VRM10_Samples/ClothSample/ClothViewer/ClothAIUEO.cs
Normal file
73
Assets/VRM10_Samples/ClothSample/ClothViewer/ClothAIUEO.cs
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniVRM10.Cloth.Viewer
|
||||
{
|
||||
public class ClothAIUEO : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
public Vrm10Instance Controller;
|
||||
private void Reset()
|
||||
{
|
||||
Controller = GetComponent<Vrm10Instance>();
|
||||
}
|
||||
|
||||
Coroutine m_coroutine;
|
||||
|
||||
[SerializeField]
|
||||
float m_wait = 0.5f;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Controller == null)
|
||||
{
|
||||
Controller = GetComponent<Vrm10Instance>();
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator RoutineNest(ExpressionPreset preset, float velocity, float wait)
|
||||
{
|
||||
for (var value = 0.0f; value <= 1.0f; value += velocity)
|
||||
{
|
||||
Controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), value);
|
||||
yield return null;
|
||||
}
|
||||
Controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), 1.0f);
|
||||
yield return new WaitForSeconds(wait);
|
||||
for (var value = 1.0f; value >= 0; value -= velocity)
|
||||
{
|
||||
Controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), value);
|
||||
yield return null;
|
||||
}
|
||||
Controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), 0);
|
||||
yield return new WaitForSeconds(wait * 2);
|
||||
}
|
||||
|
||||
IEnumerator Routine()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
yield return new WaitForSeconds(1.0f);
|
||||
|
||||
var velocity = 0.1f;
|
||||
|
||||
yield return RoutineNest(ExpressionPreset.aa, velocity, m_wait);
|
||||
yield return RoutineNest(ExpressionPreset.ih, velocity, m_wait);
|
||||
yield return RoutineNest(ExpressionPreset.ou, velocity, m_wait);
|
||||
yield return RoutineNest(ExpressionPreset.ee, velocity, m_wait);
|
||||
yield return RoutineNest(ExpressionPreset.oh, velocity, m_wait);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
m_coroutine = StartCoroutine(Routine());
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
StopCoroutine(m_coroutine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 915733a6f44f9554cae9a093cca75906
|
||||
timeCreated: 1517463794
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniVRM10.Cloth.Viewer
|
||||
{
|
||||
/// <summary>
|
||||
/// 喜怒哀楽驚を循環させる
|
||||
/// </summary>
|
||||
public class ClothAutoExpression : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
public Vrm10Instance Controller;
|
||||
private void Reset()
|
||||
{
|
||||
Controller = GetComponent<Vrm10Instance>();
|
||||
}
|
||||
|
||||
Coroutine m_coroutine;
|
||||
|
||||
[SerializeField]
|
||||
float m_wait = 0.5f;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Controller == null)
|
||||
{
|
||||
Controller = GetComponent<Vrm10Instance>();
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator RoutineNest(ExpressionPreset preset, float velocity, float wait)
|
||||
{
|
||||
for (var value = 0.0f; value <= 1.0f; value += velocity)
|
||||
{
|
||||
Controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), value);
|
||||
yield return null;
|
||||
}
|
||||
Controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), 1.0f);
|
||||
yield return new WaitForSeconds(wait);
|
||||
for (var value = 1.0f; value >= 0; value -= velocity)
|
||||
{
|
||||
Controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), value);
|
||||
yield return null;
|
||||
}
|
||||
Controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(preset), 0);
|
||||
yield return new WaitForSeconds(wait * 2);
|
||||
}
|
||||
|
||||
IEnumerator Routine()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
yield return new WaitForSeconds(1.0f);
|
||||
|
||||
var velocity = 0.01f;
|
||||
|
||||
yield return RoutineNest(ExpressionPreset.happy, velocity, m_wait);
|
||||
yield return RoutineNest(ExpressionPreset.angry, velocity, m_wait);
|
||||
yield return RoutineNest(ExpressionPreset.sad, velocity, m_wait);
|
||||
yield return RoutineNest(ExpressionPreset.relaxed, velocity, m_wait);
|
||||
yield return RoutineNest(ExpressionPreset.surprised, velocity, m_wait);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
m_coroutine = StartCoroutine(Routine());
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
StopCoroutine(m_coroutine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 974382c74d34d85488192569177a07a6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
116
Assets/VRM10_Samples/ClothSample/ClothViewer/ClothBlinker.cs
Normal file
116
Assets/VRM10_Samples/ClothSample/ClothViewer/ClothBlinker.cs
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace UniVRM10.Cloth.Viewer
|
||||
{
|
||||
/// <summary>
|
||||
/// VRMBlendShapeProxy によるランダムに瞬きするサンプル。
|
||||
/// VRMBlendShapeProxy のある GameObject にアタッチする。
|
||||
/// </summary>
|
||||
public class ClothBlinker : MonoBehaviour
|
||||
{
|
||||
Vrm10Instance m_controller;
|
||||
|
||||
[FormerlySerializedAs("m_interVal")]
|
||||
[SerializeField]
|
||||
public float Interval = 5.0f;
|
||||
|
||||
[FormerlySerializedAs("m_closingTime")]
|
||||
[SerializeField]
|
||||
public float ClosingTime = 0.06f;
|
||||
|
||||
[FormerlySerializedAs("m_openingSeconds")]
|
||||
[SerializeField]
|
||||
public float OpeningSeconds = 0.03f;
|
||||
|
||||
[FormerlySerializedAs("m_closeSeconds")]
|
||||
[SerializeField]
|
||||
public float CloseSeconds = 0.1f;
|
||||
|
||||
Coroutine m_coroutine;
|
||||
|
||||
float m_nextRequest;
|
||||
bool m_request;
|
||||
public bool Request
|
||||
{
|
||||
get { return m_request; }
|
||||
set
|
||||
{
|
||||
if (Time.time < m_nextRequest)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_request = value;
|
||||
m_nextRequest = Time.time + 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator BlinkRoutine()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var waitTime = Time.time + Random.value * Interval;
|
||||
while (waitTime > Time.time)
|
||||
{
|
||||
if (Request)
|
||||
{
|
||||
m_request = false;
|
||||
break;
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// close
|
||||
var value = 0.0f;
|
||||
var closeSpeed = 1.0f / CloseSeconds;
|
||||
while (true)
|
||||
{
|
||||
value += Time.deltaTime * closeSpeed;
|
||||
if (value >= 1.0f)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
m_controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(ExpressionPreset.blink), value);
|
||||
yield return null;
|
||||
}
|
||||
m_controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(ExpressionPreset.blink), 1.0f);
|
||||
|
||||
// wait...
|
||||
yield return new WaitForSeconds(ClosingTime);
|
||||
|
||||
// open
|
||||
value = 1.0f;
|
||||
var openSpeed = 1.0f / OpeningSeconds;
|
||||
while (true)
|
||||
{
|
||||
value -= Time.deltaTime * openSpeed;
|
||||
if (value < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
m_controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(ExpressionPreset.blink), value);
|
||||
yield return null;
|
||||
}
|
||||
m_controller.Runtime.Expression.SetWeight(ExpressionKey.CreateFromPreset(ExpressionPreset.blink), 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
m_controller = GetComponent<Vrm10Instance>();
|
||||
m_coroutine = StartCoroutine(BlinkRoutine());
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (m_coroutine != null)
|
||||
{
|
||||
StopCoroutine(m_coroutine);
|
||||
m_coroutine = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: be508240e6f6f57418cca09778dc2546
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
#if UNITY_STANDALONE_WIN
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
#endif
|
||||
|
||||
|
||||
namespace UniVRM10.Cloth.Viewer
|
||||
{
|
||||
public static class ClothFileDialogForWindows
|
||||
{
|
||||
#if UNITY_STANDALONE_WIN
|
||||
#region GetOpenFileName
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
public class OpenFileName
|
||||
{
|
||||
public int structSize = 0;
|
||||
public IntPtr dlgOwner = IntPtr.Zero;
|
||||
public IntPtr instance = IntPtr.Zero;
|
||||
public String filter = null;
|
||||
public String customFilter = null;
|
||||
public int maxCustFilter = 0;
|
||||
public int filterIndex = 0;
|
||||
public String file = null;
|
||||
public int maxFile = 0;
|
||||
public String fileTitle = null;
|
||||
public int maxFileTitle = 0;
|
||||
public String initialDir = null;
|
||||
public String title = null;
|
||||
public int flags = 0;
|
||||
public short fileOffset = 0;
|
||||
public short fileExtension = 0;
|
||||
public String defExt = null;
|
||||
public IntPtr custData = IntPtr.Zero;
|
||||
public IntPtr hook = IntPtr.Zero;
|
||||
public String templateName = null;
|
||||
public IntPtr reservedPtr = IntPtr.Zero;
|
||||
public int reservedInt = 0;
|
||||
public int flagsEx = 0;
|
||||
}
|
||||
|
||||
[DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
|
||||
public static extern bool GetOpenFileName([In, Out] OpenFileName ofn);
|
||||
/*
|
||||
public static bool GetOpenFileName1([In, Out] OpenFileName ofn)
|
||||
{
|
||||
return GetOpenFileName(ofn);
|
||||
}
|
||||
*/
|
||||
|
||||
[DllImport("Comdlg32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
private static extern bool GetSaveFileName([In, Out] OpenFileName ofn);
|
||||
|
||||
static string Filter(params string[] filters)
|
||||
{
|
||||
return string.Join("\0", filters) + "\0";
|
||||
}
|
||||
public static string FileDialog(string title, params string[] extensions)
|
||||
{
|
||||
OpenFileName ofn = new OpenFileName();
|
||||
ofn.structSize = Marshal.SizeOf(ofn);
|
||||
|
||||
var filters = new List<string>();
|
||||
filters.Add("All Files"); filters.Add("*.*");
|
||||
foreach (var ext in extensions)
|
||||
{
|
||||
filters.Add(ext); filters.Add("*" + ext);
|
||||
}
|
||||
ofn.filter = Filter(filters.ToArray());
|
||||
ofn.filterIndex = 2;
|
||||
ofn.file = new string(new char[256]);
|
||||
ofn.maxFile = ofn.file.Length;
|
||||
ofn.fileTitle = new string(new char[64]);
|
||||
ofn.maxFileTitle = ofn.fileTitle.Length;
|
||||
ofn.initialDir = UnityEngine.Application.dataPath;
|
||||
ofn.title = title;
|
||||
//ofn.defExt = "PNG";
|
||||
ofn.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000200 | 0x00000008;//OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST| OFN_ALLOWMULTISELECT|OFN_NOCHANGEDIR
|
||||
if (!GetOpenFileName(ofn))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ofn.file;
|
||||
}
|
||||
public static string SaveDialog(string title, string path)
|
||||
{
|
||||
var extension = Path.GetExtension(path);
|
||||
OpenFileName ofn = new OpenFileName();
|
||||
ofn.structSize = Marshal.SizeOf(ofn);
|
||||
ofn.filter = Filter("All Files", "*.*", extension, "*" + extension);
|
||||
ofn.filterIndex = 2;
|
||||
var chars = new char[256];
|
||||
var it = Path.GetFileName(path).GetEnumerator();
|
||||
for (int i = 0; i < chars.Length && it.MoveNext(); ++i)
|
||||
{
|
||||
chars[i] = it.Current;
|
||||
}
|
||||
ofn.file = new string(chars);
|
||||
ofn.maxFile = ofn.file.Length;
|
||||
ofn.fileTitle = new string(new char[64]);
|
||||
ofn.maxFileTitle = ofn.fileTitle.Length;
|
||||
ofn.initialDir = Path.GetDirectoryName(path);
|
||||
ofn.title = title;
|
||||
//ofn.defExt = "PNG";
|
||||
ofn.flags = 0x00000002 | 0x00000004; // OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
|
||||
if (!GetSaveFileName(ofn))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ofn.file;
|
||||
}
|
||||
#endregion
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: aad95bf34c27466469ba37298cd4028c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
93
Assets/VRM10_Samples/ClothSample/ClothViewer/ClothLoaded.cs
Normal file
93
Assets/VRM10_Samples/ClothSample/ClothViewer/ClothLoaded.cs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
using System;
|
||||
using UniGLTF;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10.Cloth.Viewer
|
||||
{
|
||||
class Loaded : IDisposable
|
||||
{
|
||||
RuntimeGltfInstance m_instance;
|
||||
public RuntimeGltfInstance Instance => m_instance;
|
||||
Vrm10Instance m_controller;
|
||||
public Vrm10RuntimeControlRig ControlRig => m_controller.Runtime.ControlRig;
|
||||
public Vrm10Runtime Runtime => m_controller.Runtime;
|
||||
|
||||
ClothAIUEO m_lipSync;
|
||||
bool m_enableLipSyncValue;
|
||||
public bool EnableLipSyncValue
|
||||
{
|
||||
set
|
||||
{
|
||||
if (m_enableLipSyncValue == value) return;
|
||||
m_enableLipSyncValue = value;
|
||||
if (m_lipSync != null)
|
||||
{
|
||||
m_lipSync.enabled = m_enableLipSyncValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClothAutoExpression m_autoExpression;
|
||||
bool m_enableAutoExpressionValue;
|
||||
public bool EnableAutoExpressionValue
|
||||
{
|
||||
set
|
||||
{
|
||||
if (m_enableAutoExpressionValue == value) return;
|
||||
m_enableAutoExpressionValue = value;
|
||||
if (m_autoExpression != null)
|
||||
{
|
||||
m_autoExpression.enabled = m_enableAutoExpressionValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClothBlinker m_blink;
|
||||
bool m_enableBlinkValue;
|
||||
public bool EnableBlinkValue
|
||||
{
|
||||
set
|
||||
{
|
||||
if (m_blink == value) return;
|
||||
m_enableBlinkValue = value;
|
||||
if (m_blink != null)
|
||||
{
|
||||
m_blink.enabled = m_enableBlinkValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Loaded(RuntimeGltfInstance instance, Transform lookAtTarget)
|
||||
{
|
||||
m_instance = instance;
|
||||
|
||||
m_controller = instance.GetComponent<Vrm10Instance>();
|
||||
if (m_controller != null)
|
||||
{
|
||||
// VRM
|
||||
m_controller.UpdateType = Vrm10Instance.UpdateTypes.LateUpdate; // after HumanPoseTransfer's setPose
|
||||
{
|
||||
m_lipSync = instance.gameObject.AddComponent<ClothAIUEO>();
|
||||
m_blink = instance.gameObject.AddComponent<ClothBlinker>();
|
||||
m_autoExpression = instance.gameObject.AddComponent<ClothAutoExpression>();
|
||||
|
||||
m_controller.LookAtTargetType = VRM10ObjectLookAt.LookAtTargetTypes.SpecifiedTransform;
|
||||
m_controller.LookAtTarget = lookAtTarget;
|
||||
}
|
||||
}
|
||||
|
||||
var animation = instance.GetComponent<Animation>();
|
||||
if (animation && animation.clip != null)
|
||||
{
|
||||
// GLTF animation
|
||||
animation.Play(animation.clip.name);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// destroy GameObject
|
||||
GameObject.Destroy(m_instance.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b68db84044b3ee84aba85929dad95494
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace VRM.VRM10RokuroCamera
|
||||
{
|
||||
public class ClothRokuroCamera : MonoBehaviour
|
||||
{
|
||||
[Range(0.1f, 5.0f)]
|
||||
public float RotateSpeed = 0.7f;
|
||||
|
||||
[Range(0.1f, 5.0f)]
|
||||
public float GrabSpeed = 0.7f;
|
||||
|
||||
[Range(0.1f, 5.0f)]
|
||||
public float DollySpeed = 1.0f;
|
||||
|
||||
struct PosRot
|
||||
{
|
||||
public Vector3 Position;
|
||||
public Quaternion Rotation;
|
||||
}
|
||||
|
||||
class _Rokuro
|
||||
{
|
||||
public float Yaw = 180.0f;
|
||||
public float Pitch;
|
||||
public float ShiftX;
|
||||
public float ShiftY;
|
||||
public float Distance = 2.0f;
|
||||
|
||||
public void Rotate(float x, float y)
|
||||
{
|
||||
Yaw += x;
|
||||
Pitch -= y;
|
||||
Pitch = Mathf.Clamp(Pitch, -90, 90);
|
||||
}
|
||||
|
||||
public void Grab(float x, float y)
|
||||
{
|
||||
ShiftX += x * Distance;
|
||||
ShiftY += y * Distance;
|
||||
}
|
||||
|
||||
public void Dolly(float delta)
|
||||
{
|
||||
if (delta > 0)
|
||||
{
|
||||
Distance *= 0.9f;
|
||||
}
|
||||
else if (delta < 0)
|
||||
{
|
||||
Distance *= 1.1f;
|
||||
}
|
||||
}
|
||||
|
||||
public PosRot Calc()
|
||||
{
|
||||
var r = Quaternion.Euler(Pitch, Yaw, 0);
|
||||
return new PosRot
|
||||
{
|
||||
Position = r * new Vector3(-ShiftX, -ShiftY, -Distance),
|
||||
Rotation = r,
|
||||
};
|
||||
}
|
||||
}
|
||||
private _Rokuro _currentCamera = new _Rokuro();
|
||||
|
||||
private List<Coroutine> _activeCoroutines = new List<Coroutine>();
|
||||
private void OnEnable()
|
||||
{
|
||||
// right mouse drag
|
||||
_activeCoroutines.Add(StartCoroutine(MouseDragOperationCoroutine(1, diff =>
|
||||
{
|
||||
_currentCamera.Rotate(diff.x * RotateSpeed, diff.y * RotateSpeed);
|
||||
})));
|
||||
// middle mouse drag
|
||||
_activeCoroutines.Add(StartCoroutine(MouseDragOperationCoroutine(2, diff =>
|
||||
{
|
||||
_currentCamera.Grab(
|
||||
diff.x * GrabSpeed / Screen.height,
|
||||
diff.y * GrabSpeed / Screen.height
|
||||
);
|
||||
})));
|
||||
// mouse wheel
|
||||
_activeCoroutines.Add(StartCoroutine(MouseScrollOperationCoroutine(diff =>
|
||||
{
|
||||
_currentCamera.Dolly(diff.y * DollySpeed);
|
||||
})));
|
||||
}
|
||||
private void OnDisable()
|
||||
{
|
||||
foreach (var coroutine in _activeCoroutines)
|
||||
{
|
||||
StopCoroutine(coroutine);
|
||||
}
|
||||
_activeCoroutines.Clear();
|
||||
}
|
||||
private void Update()
|
||||
{
|
||||
var posRot = _currentCamera.Calc();
|
||||
|
||||
transform.localRotation = posRot.Rotation;
|
||||
transform.localPosition = posRot.Position;
|
||||
}
|
||||
private IEnumerator MouseDragOperationCoroutine(int buttonIndex, Action<Vector2> dragOperation)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
while (!Input.GetMouseButtonDown(buttonIndex))
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
var prevPos = Input.mousePosition;
|
||||
while (Input.GetMouseButton(buttonIndex))
|
||||
{
|
||||
var currPos = Input.mousePosition;
|
||||
var diff = currPos - prevPos;
|
||||
dragOperation(diff);
|
||||
|
||||
prevPos = currPos;
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
private IEnumerator MouseScrollOperationCoroutine(Action<Vector2> scrollOperation)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
scrollOperation(Input.mouseScrollDelta);
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 93dcf1b2cc4d917489620707e78e9f27
|
||||
timeCreated: 1523878901
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniVRM10.Cloth.Viewer
|
||||
{
|
||||
public class ClothTargetMover : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
float m_radius = 5.0f;
|
||||
|
||||
[SerializeField]
|
||||
float m_angularVelocity = 40.0f;
|
||||
|
||||
[SerializeField]
|
||||
float m_y = 1.5f;
|
||||
|
||||
[SerializeField]
|
||||
float m_height = 3.0f;
|
||||
|
||||
public IEnumerator Start()
|
||||
{
|
||||
var angle = 0.0f;
|
||||
|
||||
while (true)
|
||||
{
|
||||
angle += m_angularVelocity * Time.deltaTime * Mathf.Deg2Rad;
|
||||
|
||||
var x = Mathf.Cos(angle) * m_radius;
|
||||
var z = Mathf.Sin(angle) * m_radius;
|
||||
var y = m_y + m_height * Mathf.Cos(angle / 3);
|
||||
|
||||
transform.localPosition = new Vector3(x, y, z);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0bc0c019f7af45745aa41b25018fd61f
|
||||
timeCreated: 1524045545
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"name": "ClothViewer",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:b7aa47b240b57de44a4b2021c143c9bf",
|
||||
"GUID:8d76e605759c3f64a957d63ef96ada7c",
|
||||
"GUID:1cd941934d098654fa21a13f28346412",
|
||||
"GUID:e47c917724578cc43b5506c17a27e9a0",
|
||||
"GUID:308b348fb80d89d42a9620951b0f60db"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 623c6cdde4acc6641978d011f67c5b87
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8382
Assets/VRM10_Samples/ClothSample/ClothViewer/ClothViewer.unity
Normal file
8382
Assets/VRM10_Samples/ClothSample/ClothViewer/ClothViewer.unity
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bedad7250033c0b49ac1e7db4d7ee63e
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
628
Assets/VRM10_Samples/ClothSample/ClothViewer/ClothViewerUI.cs
Normal file
628
Assets/VRM10_Samples/ClothSample/ClothViewer/ClothViewerUI.cs
Normal file
|
|
@ -0,0 +1,628 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using UniGLTF;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
|
||||
namespace UniVRM10.Cloth.Viewer
|
||||
{
|
||||
public class ClothViewerUI : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
Text m_version = default;
|
||||
|
||||
[Header("UI")]
|
||||
[SerializeField]
|
||||
Button m_openModel = default;
|
||||
|
||||
[SerializeField]
|
||||
Button m_openMotion = default;
|
||||
|
||||
[SerializeField]
|
||||
Button m_pastePose = default;
|
||||
|
||||
[SerializeField]
|
||||
Button m_reconstructSprngBone = default;
|
||||
|
||||
[SerializeField]
|
||||
Button m_resetSpringBone = default;
|
||||
|
||||
[SerializeField]
|
||||
Toggle m_showBoxMan = default;
|
||||
|
||||
[SerializeField]
|
||||
Toggle m_enableLipSync = default;
|
||||
|
||||
[SerializeField]
|
||||
Toggle m_enableAutoBlink = default;
|
||||
|
||||
[SerializeField]
|
||||
Toggle m_enableAutoExpression = default;
|
||||
|
||||
[SerializeField]
|
||||
Toggle m_useAsync = default;
|
||||
|
||||
[SerializeField]
|
||||
GameObject m_target = default;
|
||||
|
||||
[SerializeField]
|
||||
TextAsset m_motion;
|
||||
|
||||
GameObject Root = default;
|
||||
|
||||
IVrm10Animation m_src = default;
|
||||
public IVrm10Animation Motion
|
||||
{
|
||||
get { return m_src; }
|
||||
set
|
||||
{
|
||||
if (m_src != null)
|
||||
{
|
||||
m_src.Dispose();
|
||||
}
|
||||
m_src = value;
|
||||
|
||||
TPose = new Vrm10TPose(m_src.ControlRig.Item1.GetRawHipsPosition());
|
||||
}
|
||||
}
|
||||
|
||||
public IVrm10Animation TPose;
|
||||
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
|
||||
[Serializable]
|
||||
class TextFields
|
||||
{
|
||||
[SerializeField]
|
||||
Text m_textModelTitle = default;
|
||||
[SerializeField]
|
||||
Text m_textModelVersion = default;
|
||||
[SerializeField]
|
||||
Text m_textModelAuthor = default;
|
||||
[SerializeField]
|
||||
Text m_textModelCopyright = default;
|
||||
[SerializeField]
|
||||
Text m_textModelContact = default;
|
||||
[SerializeField]
|
||||
Text m_textModelReference = default;
|
||||
[SerializeField]
|
||||
RawImage m_thumbnail = default;
|
||||
|
||||
[SerializeField, Header("CharacterPermission")]
|
||||
Text m_textPermissionAllowed = default;
|
||||
[SerializeField]
|
||||
Text m_textPermissionViolent = default;
|
||||
[SerializeField]
|
||||
Text m_textPermissionSexual = default;
|
||||
[SerializeField]
|
||||
Text m_textPermissionCommercial = default;
|
||||
[SerializeField]
|
||||
Text m_textPermissionOther = default;
|
||||
|
||||
[SerializeField, Header("DistributionLicense")]
|
||||
Text m_textDistributionLicense = default;
|
||||
[SerializeField]
|
||||
Text m_textDistributionOther = default;
|
||||
|
||||
public void Reset(ObjectMap map)
|
||||
{
|
||||
m_textModelTitle = map.Get<Text>("Title (1)");
|
||||
m_textModelVersion = map.Get<Text>("Version (1)");
|
||||
m_textModelAuthor = map.Get<Text>("Author (1)");
|
||||
m_textModelCopyright = map.Get<Text>("Copyright (1)");
|
||||
m_textModelContact = map.Get<Text>("Contact (1)");
|
||||
m_textModelReference = map.Get<Text>("Reference (1)");
|
||||
m_textPermissionAllowed = map.Get<Text>("AllowedUser (1)");
|
||||
m_textPermissionViolent = map.Get<Text>("Violent (1)");
|
||||
m_textPermissionSexual = map.Get<Text>("Sexual (1)");
|
||||
m_textPermissionCommercial = map.Get<Text>("Commercial (1)");
|
||||
m_textPermissionOther = map.Get<Text>("Other (1)");
|
||||
m_textDistributionLicense = map.Get<Text>("LicenseType (1)");
|
||||
m_textDistributionOther = map.Get<Text>("OtherLicense (1)");
|
||||
m_thumbnail = map.Get<RawImage>("RawImage");
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
m_textModelTitle.text = "";
|
||||
m_textModelVersion.text = "";
|
||||
m_textModelAuthor.text = "";
|
||||
m_textModelCopyright.text = "";
|
||||
m_textModelContact.text = "";
|
||||
m_textModelReference.text = "";
|
||||
|
||||
m_textPermissionAllowed.text = "";
|
||||
m_textPermissionViolent.text = "";
|
||||
m_textPermissionSexual.text = "";
|
||||
m_textPermissionCommercial.text = "";
|
||||
m_textPermissionOther.text = "";
|
||||
|
||||
m_textDistributionLicense.text = "";
|
||||
m_textDistributionOther.text = "";
|
||||
}
|
||||
|
||||
public void UpdateMeta(Texture2D thumbnail, UniGLTF.Extensions.VRMC_vrm.Meta meta, Migration.Vrm0Meta meta0)
|
||||
{
|
||||
m_thumbnail.texture = thumbnail;
|
||||
|
||||
if (meta != null)
|
||||
{
|
||||
m_textModelTitle.text = meta.Name;
|
||||
m_textModelVersion.text = meta.Version;
|
||||
m_textModelAuthor.text = meta.Authors[0];
|
||||
m_textModelCopyright.text = meta.CopyrightInformation;
|
||||
m_textModelContact.text = meta.ContactInformation;
|
||||
if (meta.References != null && meta.References.Count > 0)
|
||||
{
|
||||
m_textModelReference.text = meta.References[0];
|
||||
}
|
||||
m_textPermissionAllowed.text = meta.AvatarPermission.ToString();
|
||||
m_textPermissionViolent.text = meta.AllowExcessivelyViolentUsage.ToString();
|
||||
m_textPermissionSexual.text = meta.AllowExcessivelySexualUsage.ToString();
|
||||
m_textPermissionCommercial.text = meta.CommercialUsage.ToString();
|
||||
// m_textPermissionOther.text = meta.OtherPermissionUrl;
|
||||
|
||||
// m_textDistributionLicense.text = meta.ModificationLicense.ToString();
|
||||
m_textDistributionOther.text = meta.OtherLicenseUrl;
|
||||
}
|
||||
|
||||
if (meta0 != null)
|
||||
{
|
||||
m_textModelTitle.text = meta0.title;
|
||||
m_textModelVersion.text = meta0.version;
|
||||
m_textModelAuthor.text = meta0.author;
|
||||
m_textModelContact.text = meta0.contactInformation;
|
||||
m_textModelReference.text = meta0.reference;
|
||||
m_textPermissionAllowed.text = meta0.allowedUser.ToString();
|
||||
m_textPermissionViolent.text = meta0.violentUsage.ToString();
|
||||
m_textPermissionSexual.text = meta0.sexualUsage.ToString();
|
||||
m_textPermissionCommercial.text = meta0.commercialUsage.ToString();
|
||||
m_textPermissionOther.text = meta0.otherPermissionUrl;
|
||||
// m_textDistributionLicense.text = meta0.ModificationLicense.ToString();
|
||||
m_textDistributionOther.text = meta0.otherLicenseUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
[SerializeField]
|
||||
TextFields m_texts = default;
|
||||
|
||||
[Serializable]
|
||||
class UIFields
|
||||
{
|
||||
[SerializeField]
|
||||
Toggle ToggleMotionTPose = default;
|
||||
|
||||
[SerializeField]
|
||||
Toggle ToggleMotionBVH = default;
|
||||
|
||||
[SerializeField]
|
||||
ToggleGroup ToggleMotion = default;
|
||||
|
||||
public void Reset(ObjectMap map)
|
||||
{
|
||||
ToggleMotionTPose = map.Get<Toggle>("TPose");
|
||||
ToggleMotionBVH = map.Get<Toggle>("BVH");
|
||||
ToggleMotion = map.Get<ToggleGroup>("_Motion_");
|
||||
}
|
||||
|
||||
public bool IsTPose
|
||||
{
|
||||
get => ToggleMotion.ActiveToggles().FirstOrDefault() == ToggleMotionTPose;
|
||||
set
|
||||
{
|
||||
ToggleMotionTPose.isOn = value;
|
||||
ToggleMotionBVH.isOn = !value;
|
||||
}
|
||||
}
|
||||
}
|
||||
[SerializeField]
|
||||
UIFields m_ui = default;
|
||||
|
||||
class ObjectMap
|
||||
{
|
||||
Dictionary<string, GameObject> _map = new();
|
||||
public IReadOnlyDictionary<string, GameObject> Objects => _map;
|
||||
|
||||
public ObjectMap(GameObject root)
|
||||
{
|
||||
foreach (var x in root.GetComponentsInChildren<Transform>())
|
||||
{
|
||||
_map[x.name] = x.gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
public T Get<T>(string name) where T : Component
|
||||
{
|
||||
return _map[name].GetComponent<T>();
|
||||
}
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
var map = new ObjectMap(gameObject);
|
||||
m_openModel = map.Get<Button>("OpenModel");
|
||||
m_openMotion = map.Get<Button>("OpenMotion");
|
||||
m_pastePose = map.Get<Button>("PastePose");
|
||||
m_reconstructSprngBone = map.Get<Button>("ReconstcutSpringBone");
|
||||
m_resetSpringBone = map.Get<Button>("ResetSpringBone");
|
||||
m_showBoxMan = map.Get<Toggle>("ShowBoxMan");
|
||||
m_enableLipSync = map.Get<Toggle>("EnableLipSync");
|
||||
m_enableAutoBlink = map.Get<Toggle>("EnableAutoBlink");
|
||||
m_enableAutoExpression = map.Get<Toggle>("EnableAutoExpression");
|
||||
m_useAsync = map.Get<Toggle>("UseAsync");
|
||||
m_version = map.Get<Text>("VrmVersion");
|
||||
m_texts.Reset(map);
|
||||
m_ui.Reset(map);
|
||||
m_target = GameObject.FindObjectOfType<ClothTargetMover>().gameObject;
|
||||
}
|
||||
|
||||
Loaded m_loaded;
|
||||
RotateParticle.HumanoidPose m_init;
|
||||
int m_springFrame = 0;
|
||||
|
||||
static class ArgumentChecker
|
||||
{
|
||||
static string[] Supported = {
|
||||
".gltf",
|
||||
".glb",
|
||||
".vrm",
|
||||
".zip",
|
||||
};
|
||||
|
||||
static string UnityHubPath => System.Environment.GetEnvironmentVariable("ProgramFiles") + "\\Unity\\Hub";
|
||||
|
||||
public static bool IsLoadable(string path)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
// not exists
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Application.isEditor)
|
||||
{
|
||||
// skip editor argument
|
||||
// {UnityHub_Resources}\PackageManager\ProjectTemplates\com.unity.template.3d-5.0.4.tgz
|
||||
if (path.StartsWith(UnityHubPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
if (!Supported.Contains(ext))
|
||||
{
|
||||
// unknown extension
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool TryGetFirstLoadable(out string cmd)
|
||||
{
|
||||
foreach (var arg in System.Environment.GetCommandLineArgs())
|
||||
{
|
||||
if (ArgumentChecker.IsLoadable(arg))
|
||||
{
|
||||
cmd = arg;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
cmd = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
public int Iteration = 32;
|
||||
|
||||
Action<float> MakeSetPose()
|
||||
{
|
||||
var start = m_init;
|
||||
var animator = m_loaded.Instance.GetComponent<Animator>();
|
||||
var end = new RotateParticle.HumanoidPose(animator);
|
||||
return (float t) =>
|
||||
{
|
||||
RotateParticle.HumanoidPose.ApplyLerp(animator, start, end, t);
|
||||
};
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
m_version.text = string.Format("VRMViewer {0}.{1}",
|
||||
VRM10SpecVersion.MAJOR, VRM10SpecVersion.MINOR);
|
||||
|
||||
m_openModel.onClick.AddListener(OnOpenModelClicked);
|
||||
m_openMotion.onClick.AddListener(OnOpenMotionClicked);
|
||||
m_pastePose.onClick.AddListener(OnPastePoseClicked);
|
||||
m_reconstructSprngBone.onClick.AddListener(OnResetStrandInitClicked);
|
||||
m_resetSpringBone.onClick.AddListener(OnResetStrandPoseClicked);
|
||||
|
||||
// load initial bvh
|
||||
if (m_motion != null)
|
||||
{
|
||||
Motion = BvhMotion.LoadBvhFromText(m_motion.text);
|
||||
}
|
||||
|
||||
if (ArgumentChecker.TryGetFirstLoadable(out var cmd))
|
||||
{
|
||||
LoadModel(cmd);
|
||||
}
|
||||
|
||||
m_texts.Start();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
_cancellationTokenSource?.Dispose();
|
||||
}
|
||||
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.Tab))
|
||||
{
|
||||
if (Root != null) Root.SetActive(!Root.activeSelf);
|
||||
}
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.Escape))
|
||||
{
|
||||
if (_cancellationTokenSource != null)
|
||||
{
|
||||
_cancellationTokenSource.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
if (Motion != null)
|
||||
{
|
||||
Motion.ShowBoxMan(m_showBoxMan.isOn);
|
||||
}
|
||||
|
||||
if (m_loaded != null)
|
||||
{
|
||||
m_loaded.EnableLipSyncValue = m_enableLipSync.isOn;
|
||||
m_loaded.EnableBlinkValue = m_enableAutoBlink.isOn;
|
||||
m_loaded.EnableAutoExpressionValue = m_enableAutoExpression.isOn;
|
||||
}
|
||||
|
||||
if (m_loaded != null)
|
||||
{
|
||||
if (m_ui.IsTPose)
|
||||
{
|
||||
m_loaded.Runtime.VrmAnimation = TPose;
|
||||
}
|
||||
else if (Motion != null)
|
||||
{
|
||||
// Automatically retarget in Vrm10Runtime.Process
|
||||
m_loaded.Runtime.VrmAnimation = Motion;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_loaded != null)
|
||||
{
|
||||
if (m_springFrame++ == 0)
|
||||
{
|
||||
ResetStrandPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnOpenModelClicked()
|
||||
{
|
||||
#if UNITY_STANDALONE_WIN
|
||||
var path = ClothFileDialogForWindows.FileDialog("open VRM", "vrm");
|
||||
#elif UNITY_EDITOR
|
||||
var path = UnityEditor.EditorUtility.OpenFilePanel("Open VRM", "", "vrm");
|
||||
#else
|
||||
var path = Application.dataPath + "/default.vrm";
|
||||
#endif
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
if (ext != ".vrm")
|
||||
{
|
||||
Debug.LogWarning($"{path} is not vrm");
|
||||
return;
|
||||
}
|
||||
|
||||
LoadModel(path);
|
||||
}
|
||||
|
||||
async void OnOpenMotionClicked()
|
||||
{
|
||||
#if UNITY_STANDALONE_WIN
|
||||
var path = ClothFileDialogForWindows.FileDialog("open Motion", "bvh", "gltf", "glb", "vrma");
|
||||
#elif UNITY_EDITOR
|
||||
var path = UnityEditor.EditorUtility.OpenFilePanel("Open Motion", "", "bvh");
|
||||
#else
|
||||
var path = Application.dataPath + "/default.bvh";
|
||||
#endif
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var ext = Path.GetExtension(path).ToLower();
|
||||
if (ext == ".bvh")
|
||||
{
|
||||
Motion = BvhMotion.LoadBvhFromPath(path);
|
||||
return;
|
||||
}
|
||||
|
||||
// gltf, glb etc...
|
||||
using GltfData data = new AutoGltfFileParser(path).Parse();
|
||||
using var loader = new VrmAnimationImporter(data);
|
||||
var instance = await loader.LoadAsync(new ImmediateCaller());
|
||||
Motion = instance.GetComponent<Vrm10AnimationInstance>();
|
||||
instance.GetComponent<Animation>().Play();
|
||||
}
|
||||
|
||||
async void OnPastePoseClicked()
|
||||
{
|
||||
var text = GUIUtility.systemCopyBuffer;
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Motion = await Vrm10PoseLoader.LoadVrmAnimationPose(text);
|
||||
}
|
||||
catch (UniJSON.ParserException)
|
||||
{
|
||||
Debug.LogWarning("UniJSON.ParserException");
|
||||
}
|
||||
catch (UniJSON.DeserializationException)
|
||||
{
|
||||
Debug.LogWarning("UniJSON.DeserializationException");
|
||||
}
|
||||
}
|
||||
|
||||
void OnResetStrandInitClicked()
|
||||
{
|
||||
if (m_loaded == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var system = m_loaded.Instance.GetComponent<RotateParticle.RotateParticleSystem>();
|
||||
system.ResetParticle();
|
||||
}
|
||||
|
||||
void OnResetStrandPoseClicked()
|
||||
{
|
||||
if (m_loaded == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ResetStrandPose();
|
||||
}
|
||||
|
||||
void ResetStrandPose()
|
||||
{
|
||||
ResetStrandPose(MakeSetPose(), 32, 1.0f / 30, 60);
|
||||
}
|
||||
|
||||
void ResetStrandPose(Action<float> setPose, int iteration, float timeDelta, int finish)
|
||||
{
|
||||
var system = m_loaded.Instance.GetComponent<RotateParticle.RotateParticleSystem>();
|
||||
|
||||
// init
|
||||
setPose(0);
|
||||
system.ResetParticle();
|
||||
|
||||
// lerp
|
||||
var t = 0.0f;
|
||||
var d = 1.0f / iteration;
|
||||
for (int i = 0; i < iteration; ++i, t += d)
|
||||
{
|
||||
setPose(t);
|
||||
system.Process(timeDelta);
|
||||
}
|
||||
|
||||
// finish
|
||||
setPose(1.0f);
|
||||
for (int i = 0; i < finish; ++i)
|
||||
{
|
||||
system.Process(timeDelta);
|
||||
}
|
||||
}
|
||||
|
||||
static IMaterialDescriptorGenerator GetVrmMaterialDescriptorGenerator(bool useUrp)
|
||||
{
|
||||
if (useUrp)
|
||||
{
|
||||
return new UrpVrm10MaterialDescriptorGenerator();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new BuiltInVrm10MaterialDescriptorGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
static IMaterialDescriptorGenerator GetMaterialDescriptorGenerator(bool useUrp)
|
||||
{
|
||||
if (useUrp)
|
||||
{
|
||||
return new UrpGltfMaterialDescriptorGenerator();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new BuiltInGltfMaterialDescriptorGenerator();
|
||||
}
|
||||
}
|
||||
|
||||
async void LoadModel(string path)
|
||||
{
|
||||
// cleanup
|
||||
m_loaded?.Dispose();
|
||||
m_loaded = null;
|
||||
_cancellationTokenSource?.Dispose();
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
var cancellationToken = _cancellationTokenSource.Token;
|
||||
|
||||
try
|
||||
{
|
||||
Debug.LogFormat("{0}", path);
|
||||
var vrm10Instance = await Vrm10.LoadPathAsync(path,
|
||||
canLoadVrm0X: true,
|
||||
showMeshes: false,
|
||||
awaitCaller: m_useAsync.enabled ? (IAwaitCaller)new RuntimeOnlyAwaitCaller() : (IAwaitCaller)new ImmediateCaller(),
|
||||
materialGenerator: GetVrmMaterialDescriptorGenerator(true),
|
||||
vrmMetaInformationCallback: m_texts.UpdateMeta);
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
UnityObjectDestroyer.DestroyRuntimeOrEditor(vrm10Instance.gameObject);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
if (vrm10Instance == null)
|
||||
{
|
||||
Debug.LogWarning("LoadPathAsync is null");
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// RotateParticle.HumanoidAutoSetup
|
||||
//
|
||||
|
||||
// clear
|
||||
vrm10Instance.SpringBone = new Vrm10InstanceSpringBone();
|
||||
|
||||
var autoSetup = vrm10Instance.transform.gameObject.AddComponent<RotateParticle.HumanoidAutoSetup>();
|
||||
autoSetup.Reset();
|
||||
var system = vrm10Instance.GetComponent<RotateParticle.RotateParticleSystem>();
|
||||
system.Initialize();
|
||||
|
||||
var instance = vrm10Instance.GetComponent<RuntimeGltfInstance>();
|
||||
instance.ShowMeshes();
|
||||
instance.EnableUpdateWhenOffscreen();
|
||||
m_loaded = new Loaded(instance, m_target.transform);
|
||||
m_init = new RotateParticle.HumanoidPose(vrm10Instance.GetComponent<Animator>());
|
||||
m_springFrame = 0;
|
||||
m_showBoxMan.isOn = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is OperationCanceledException)
|
||||
{
|
||||
Debug.LogWarning($"Canceled to Load: {path}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Failed to Load: {path}");
|
||||
Debug.LogException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 46079dccaf3b7ac4ebbba728f1971ed0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1431334beb4184340955317d5a35a9fe
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UniHumanoid;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10.Cloth.Viewer
|
||||
{
|
||||
public class BvhMotion : IVrm10Animation
|
||||
{
|
||||
UniHumanoid.BvhImporterContext m_context;
|
||||
public Transform Root => m_context?.Root.transform;
|
||||
public SkinnedMeshRenderer m_boxMan;
|
||||
public SkinnedMeshRenderer BoxMan => m_boxMan;
|
||||
(INormalizedPoseProvider, ITPoseProvider) m_controlRig;
|
||||
(INormalizedPoseProvider, ITPoseProvider) IVrm10Animation.ControlRig => m_controlRig;
|
||||
IDictionary<ExpressionKey, Func<float>> _ExpressionMap = new Dictionary<ExpressionKey, Func<float>>();
|
||||
public IReadOnlyDictionary<ExpressionKey, Func<float>> ExpressionMap => (IReadOnlyDictionary<ExpressionKey, Func<float>>)_ExpressionMap;
|
||||
|
||||
public LookAtInput? LookAt { get; set; }
|
||||
|
||||
public BvhMotion(UniHumanoid.BvhImporterContext context)
|
||||
{
|
||||
m_context = context;
|
||||
var provider = new AnimatorPoseProvider(m_context.Root.transform, m_context.Root.GetComponent<Animator>());
|
||||
m_controlRig = (provider, provider);
|
||||
|
||||
// create SkinnedMesh for bone visualize
|
||||
var animator = m_context.Root.GetComponent<Animator>();
|
||||
m_boxMan = SkeletonMeshUtility.CreateRenderer(animator);
|
||||
var shaderName = UnityEngine.Rendering.GraphicsSettings.renderPipelineAsset == null
|
||||
? "Standard"
|
||||
: "Universal Render Pipeline/Lit"
|
||||
;
|
||||
var material = new Material(Shader.Find(shaderName));
|
||||
BoxMan.sharedMaterial = material;
|
||||
var mesh = BoxMan.sharedMesh;
|
||||
mesh.name = "box-man";
|
||||
}
|
||||
|
||||
public static BvhMotion LoadBvhFromText(string source, string path = "tmp.bvh")
|
||||
{
|
||||
var context = new UniHumanoid.BvhImporterContext();
|
||||
context.Parse(path, source);
|
||||
context.Load();
|
||||
return new BvhMotion(context);
|
||||
}
|
||||
public static BvhMotion LoadBvhFromPath(string path)
|
||||
{
|
||||
return LoadBvhFromText(File.ReadAllText(path), path);
|
||||
}
|
||||
|
||||
public void ShowBoxMan(bool enable)
|
||||
{
|
||||
m_boxMan.enabled = enable;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GameObject.Destroy(m_context.Root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3d57facd372741a44a4216655733cdf5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 487929d3039a63544a0825523ac6a8ab
|
||||
timeCreated: 1546851178
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Reference in New Issue
Block a user