add VRM10Viewer sample

This commit is contained in:
ousttrue 2021-01-29 19:06:04 +09:00
parent f2982e1d50
commit d25a72bf64
17 changed files with 6117 additions and 6 deletions

View File

@ -1,7 +1,5 @@
fileFormatVersion: 2
guid: b62ca4f3096cada41938f18e4a02d8dc
timeCreated: 1517463794
licenseType: Free
guid: e7d971d3cc4439c4ba3f3ae4072cf82d
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -1,8 +1,7 @@
fileFormatVersion: 2
guid: c04054aea7a18b642b0a4905e808604e
timeCreated: 1524045545
licenseType: Free
guid: 93a55f745733f794b963f9eb00d0c0af
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c5c0de34a00d309409bfc1d534e2610a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a00625daa13c4a34ba99d9e0c80c0ad6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,73 @@
using System.Collections;
using UnityEngine;
namespace UniVRM10.Samples
{
public class AIUEO : MonoBehaviour
{
[SerializeField]
public VRM10Controller VRM;
private void Reset()
{
VRM = GetComponent<VRM10Controller>();
}
Coroutine m_coroutine;
[SerializeField]
float m_wait = 0.5f;
private void Awake()
{
if (VRM == null)
{
VRM = GetComponent<VRM10Controller>();
}
}
IEnumerator RoutineNest(VrmLib.ExpressionPreset preset, float velocity, float wait)
{
for (var value = 0.0f; value <= 1.0f; value += velocity)
{
VRM.Expression.Accumulator.SetPresetValue(preset, value);
yield return null;
}
VRM.Expression.Accumulator.SetPresetValue(preset, 1.0f);
yield return new WaitForSeconds(wait);
for (var value = 1.0f; value >= 0; value -= velocity)
{
VRM.Expression.Accumulator.SetPresetValue(preset, value);
yield return null;
}
VRM.Expression.Accumulator.SetPresetValue(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(VrmLib.ExpressionPreset.Aa, velocity, m_wait);
yield return RoutineNest(VrmLib.ExpressionPreset.Ih, velocity, m_wait);
yield return RoutineNest(VrmLib.ExpressionPreset.Ou, velocity, m_wait);
yield return RoutineNest(VrmLib.ExpressionPreset.Ee, velocity, m_wait);
yield return RoutineNest(VrmLib.ExpressionPreset.Oh, velocity, m_wait);
}
}
private void OnEnable()
{
m_coroutine = StartCoroutine(Routine());
}
private void OnDisable()
{
StopCoroutine(m_coroutine);
}
}
}

View File

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: b62ca4f3096cada41938f18e4a02d8dc
timeCreated: 1517463794
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,116 @@
using System.Collections;
using UnityEngine;
using UnityEngine.Serialization;
namespace UniVRM10.Samples
{
/// <summary>
/// VRMBlendShapeProxy によるランダムに瞬きするサンプル。
/// VRMBlendShapeProxy のある GameObject にアタッチする。
/// </summary>
public class Blinker : MonoBehaviour
{
VRM10Controller 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.Expression.Accumulator.SetPresetValue(VrmLib.ExpressionPreset.Blink, value);
yield return null;
}
m_controller.Expression.Accumulator.SetPresetValue(VrmLib.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.Expression.Accumulator.SetPresetValue(VrmLib.ExpressionPreset.Blink, value);
yield return null;
}
m_controller.Expression.Accumulator.SetPresetValue(VrmLib.ExpressionPreset.Blink, 0);
}
}
private void OnEnable()
{
m_controller = GetComponent<VRM10Controller>();
m_coroutine = StartCoroutine(BlinkRoutine());
}
private void OnDisable()
{
if (m_coroutine != null)
{
StopCoroutine(m_coroutine);
m_coroutine = null;
}
}
}
}

View File

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

View File

@ -0,0 +1,118 @@
#if UNITY_STANDALONE_WIN
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
#endif
namespace UniVRM10.Samples
{
public static class FileDialogForWindows
{
#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
}
}

View File

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

View File

@ -0,0 +1,40 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UniVRM10.Samples
{
public class TargetMover : 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;
}
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c04054aea7a18b642b0a4905e808604e
timeCreated: 1524045545
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,410 @@
using System;
using System.IO;
using System.Linq;
using UniHumanoid;
using UnityEngine;
using UnityEngine.UI;
namespace UniVRM10.Samples
{
public class ViewerUI : MonoBehaviour
{
#region UI
[SerializeField]
Text m_version = default;
[SerializeField]
Button m_open = default;
[SerializeField]
Toggle m_enableLipSync = default;
[SerializeField]
Toggle m_enableAutoBlink = default;
#endregion
[SerializeField]
HumanPoseTransfer m_src = default;
[SerializeField]
GameObject m_target = default;
[SerializeField]
GameObject Root = default;
[Serializable]
class TextFields
{
[SerializeField, Header("Info")]
Text m_textModelTitle = default;
[SerializeField]
Text m_textModelVersion = default;
[SerializeField]
Text m_textModelAuthor = 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 Start()
{
m_textModelTitle.text = "";
m_textModelVersion.text = "";
m_textModelAuthor.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(VRM10Controller context)
{
// var meta = context.ReadMeta(true);
var meta = context.Meta;
m_textModelTitle.text = meta.Name;
m_textModelVersion.text = meta.Version;
m_textModelAuthor.text = meta.Authors[0];
m_textModelContact.text = meta.ContactInformation;
m_textModelReference.text = meta.Reference;
m_textPermissionAllowed.text = meta.AllowedUser.ToString();
m_textPermissionViolent.text = meta.ViolentUsage.ToString();
m_textPermissionSexual.text = meta.SexualUsage.ToString();
m_textPermissionCommercial.text = meta.CommercialUsage.ToString();
m_textPermissionOther.text = meta.OtherPermissionUrl;
m_textDistributionLicense.text = meta.ModificationLicense.ToString();
m_textDistributionOther.text = meta.OtherLicenseUrl;
m_thumbnail.texture = meta.Thumbnail;
}
}
[SerializeField]
TextFields m_texts = default;
[Serializable]
class UIFields
{
[SerializeField]
Toggle ToggleMotionTPose = default;
[SerializeField]
Toggle ToggleMotionBVH = default;
[SerializeField]
ToggleGroup ToggleMotion = default;
Toggle m_activeToggleMotion = default;
public void UpdateToggle(Action onBvh, Action onTPose)
{
var value = ToggleMotion.ActiveToggles().FirstOrDefault();
if (value == m_activeToggleMotion)
return;
m_activeToggleMotion = value;
if (value == ToggleMotionTPose)
{
onTPose();
}
else if (value == ToggleMotionBVH)
{
onBvh();
}
else
{
Debug.Log("motion: no toggle");
}
}
}
[SerializeField]
UIFields m_ui = default;
[SerializeField]
HumanPoseClip m_pose = default;
private void Reset()
{
var buttons = GameObject.FindObjectsOfType<Button>();
m_open = buttons.First(x => x.name == "Open");
var toggles = GameObject.FindObjectsOfType<Toggle>();
m_enableLipSync = toggles.First(x => x.name == "EnableLipSync");
m_enableAutoBlink = toggles.First(x => x.name == "EnableAutoBlink");
var texts = GameObject.FindObjectsOfType<Text>();
m_version = texts.First(x => x.name == "Version");
m_src = GameObject.FindObjectOfType<HumanPoseTransfer>();
m_target = GameObject.FindObjectOfType<TargetMover>().gameObject;
}
HumanPoseTransfer m_loaded;
VRM10Controller m_controller;
AIUEO m_lipSync;
bool m_enableLipSyncValue;
bool EnableLipSyncValue
{
set
{
if (m_enableLipSyncValue == value) return;
m_enableLipSyncValue = value;
if (m_lipSync != null)
{
m_lipSync.enabled = m_enableLipSyncValue;
}
}
}
Blinker m_blink;
bool m_enableBlinkValue;
bool EnableBlinkValue
{
set
{
if (m_blink == value) return;
m_enableBlinkValue = value;
if (m_blink != null)
{
m_blink.enabled = m_enableBlinkValue;
}
}
}
private void Start()
{
m_version.text = string.Format("VRMViewer {0}.{1}",
VRMVersion.MAJOR, VRMVersion.MINOR);
m_open.onClick.AddListener(OnOpenClicked);
// load initial bvh
LoadMotion(Application.streamingAssetsPath + "/VRM.Samples/Motions/test.txt");
string[] cmds = System.Environment.GetCommandLineArgs();
if (cmds.Length > 1)
{
LoadModel(cmds[1]);
}
m_texts.Start();
}
private void LoadMotion(string path)
{
var context = new UniHumanoid.BvhImporterContext();
context.Parse(path);
context.Load();
SetMotion(context.Root.GetComponent<HumanPoseTransfer>());
}
private void Update()
{
EnableLipSyncValue = m_enableLipSync.isOn;
EnableBlinkValue = m_enableAutoBlink.isOn;
if (Input.GetKeyDown(KeyCode.Tab))
{
if (Root != null) Root.SetActive(!Root.activeSelf);
}
m_ui.UpdateToggle(EnableBvh, EnableTPose);
// if (m_controller != null)
// {
// m_controller.Expression.Apply();
// }
}
void EnableBvh()
{
if (m_loaded != null)
{
m_loaded.Source = m_src;
m_loaded.SourceType = HumanPoseTransfer.HumanPoseTransferSourceType.HumanPoseTransfer;
}
}
void EnableTPose()
{
if (m_loaded != null)
{
m_loaded.PoseClip = m_pose;
m_loaded.SourceType = HumanPoseTransfer.HumanPoseTransferSourceType.HumanPoseClip;
}
}
void OnOpenClicked()
{
#if UNITY_STANDALONE_WIN
var path = FileDialogForWindows.FileDialog("open VRM", "vrm", "glb", "bvh", "gltf", "zip");
#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();
switch (ext)
{
case ".gltf":
case ".glb":
case ".vrm":
case ".zip":
LoadModel(path);
break;
case ".bvh":
LoadMotion(path);
break;
}
}
void LoadModel(string path)
{
if (!File.Exists(path))
{
return;
}
Debug.LogFormat("{0}", path);
var ext = Path.GetExtension(path).ToLower();
switch (ext)
{
case ".vrm":
{
// var context = new ImporterContext();
var file = File.ReadAllBytes(path);
// context.ParseGlb(file);
// m_texts.UpdateMeta(context);
// context.Load();
// context.ShowMeshes();
// context.EnableUpdateWhenOffscreen();
// context.ShowMeshes();
var model = UniVRM10.VrmLoader.CreateVrmModel(file, new FileInfo(path));
// UniVRM-0.XXのコンポーネントを構築する
var assets = UniVRM10.RuntimeUnityBuilder.ToUnityAsset(model, showMesh: false);
// showRenderer = false のときに後で表示する例
foreach (var renderer in assets.Renderers)
{
renderer.enabled = true;
}
UniVRM10.ComponentBuilder.Build10(model, assets);
SetModel(assets.Root);
break;
}
case ".glb":
{
var context = new UniGLTF.ImporterContext();
var file = File.ReadAllBytes(path);
context.ParseGlb(file);
context.Load();
context.ShowMeshes();
context.EnableUpdateWhenOffscreen();
context.ShowMeshes();
SetModel(context.Root);
break;
}
case ".gltf":
case ".zip":
{
var context = new UniGLTF.ImporterContext();
context.Parse(path);
context.Load();
context.ShowMeshes();
context.EnableUpdateWhenOffscreen();
context.ShowMeshes();
SetModel(context.Root);
break;
}
default:
Debug.LogWarningFormat("unknown file type: {0}", path);
break;
}
}
void SetModel(GameObject go)
{
// cleanup
var loaded = m_loaded;
m_loaded = null;
if (loaded != null)
{
Debug.LogFormat("destroy {0}", loaded);
GameObject.Destroy(loaded.gameObject);
}
if (go != null)
{
m_controller = go.GetComponent<VRM10Controller>();
m_controller.Controller.UpdateType = VRM10Controller.VRM10ControllerImpl.UpdateTypes.LateUpdate; // after HumanPoseTransfer's setPose
{
m_loaded = go.AddComponent<HumanPoseTransfer>();
m_loaded.Source = m_src;
m_loaded.SourceType = HumanPoseTransfer.HumanPoseTransferSourceType.HumanPoseTransfer;
m_lipSync = go.AddComponent<AIUEO>();
m_blink = go.AddComponent<Blinker>();
m_controller.LookAt.Gaze = m_target.transform;
}
var animation = go.GetComponent<Animation>();
if (animation && animation.clip != null)
{
animation.Play(animation.clip.name);
}
}
}
void SetMotion(HumanPoseTransfer src)
{
m_src = src;
src.GetComponent<Renderer>().enabled = false;
EnableBvh();
}
}
}

View File

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

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 258a141ecf4956744876b6b445c2a498
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c91fa5ff7b6696646a8b16d9bf88a5c2
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: