mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-08-24 19:45:37 -05:00
Merge pull request #1504 from Santarh/fixHlapi
Refactor High-level VRM-1.0 Loading API.
This commit is contained in:
200
Assets/VRM10/Runtime/IO/Vrm10.cs
Normal file
200
Assets/VRM10/Runtime/IO/Vrm10.cs
Normal file
@@ -0,0 +1,200 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using UniGLTF;
|
||||
using UnityEngine;
|
||||
using VRMShaders;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
/// <summary>
|
||||
/// High-level VRM-1.0 loading API.
|
||||
/// </summary>
|
||||
public static class Vrm10
|
||||
{
|
||||
/// <summary>
|
||||
/// You can receive the thumbnail texture and the meta information.
|
||||
/// `vrm10Meta` will be available if the model was vrm-1.0.
|
||||
/// `vrm0Meta` will be available if the model was vrm-0.x.
|
||||
/// </summary>
|
||||
public delegate void VrmMetaInformationCallback(Texture2D thumbnail, UniGLTF.Extensions.VRMC_vrm.Meta vrm10Meta, Migration.Vrm0Meta vrm0Meta);
|
||||
|
||||
/// <summary>
|
||||
/// Load the VRM file from the path.
|
||||
/// </summary>
|
||||
/// <param name="path">vrm file path</param>
|
||||
/// <param name="canLoadVrm0X">if true, this loader can load the vrm-0.x model as vrm-1.0 model with migration.</param>
|
||||
/// <param name="normalizeTransform">if true, vrm-1.0 models' transforms are normalized. (e.g. rotation, scaling)</param>
|
||||
/// <param name="showMeshes">if true, show meshes when loaded.</param>
|
||||
/// <param name="awaitCaller">this loader use specified await strategy.</param>
|
||||
/// <param name="materialGenerator">this loader use specified material generation strategy.</param>
|
||||
/// <param name="vrmMetaInformationCallback">return callback that notify meta information before loading.</param>
|
||||
/// <param name="ct">CancellationToken</param>
|
||||
/// <returns>vrm-1.0 instance</returns>
|
||||
public static async Task<Vrm10Instance> LoadPathAsync(
|
||||
string path,
|
||||
bool canLoadVrm0X = true,
|
||||
bool normalizeTransform = true,
|
||||
bool showMeshes = true,
|
||||
IAwaitCaller awaitCaller = null,
|
||||
IMaterialDescriptorGenerator materialGenerator = null,
|
||||
VrmMetaInformationCallback vrmMetaInformationCallback = null,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
return await LoadAsync(
|
||||
path,
|
||||
System.IO.File.ReadAllBytes(path),
|
||||
canLoadVrm0X,
|
||||
normalizeTransform,
|
||||
showMeshes,
|
||||
awaitCaller,
|
||||
materialGenerator,
|
||||
vrmMetaInformationCallback,
|
||||
ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load the VRM file from the binary.
|
||||
/// </summary>
|
||||
/// <param name="bytes">vrm file data</param>
|
||||
/// <param name="canLoadVrm0X">if true, this loader can load the vrm-0.x model as vrm-1.0 model with migration.</param>
|
||||
/// <param name="normalizeTransform">if true, vrm-1.0 models' transforms are normalized. (e.g. rotation, scaling)</param>
|
||||
/// <param name="showMeshes">if true, show meshes when loaded.</param>
|
||||
/// <param name="awaitCaller">this loader use specified await strategy.</param>
|
||||
/// <param name="materialGenerator">this loader use specified material generation strategy.</param>
|
||||
/// <param name="vrmMetaInformationCallback">return callback that notify meta information before loading.</param>
|
||||
/// <param name="ct">CancellationToken</param>
|
||||
/// <returns>vrm-1.0 instance</returns>
|
||||
public static async Task<Vrm10Instance> LoadBytesAsync(
|
||||
byte[] bytes,
|
||||
bool canLoadVrm0X = true,
|
||||
bool normalizeTransform = true,
|
||||
bool showMeshes = true,
|
||||
IAwaitCaller awaitCaller = null,
|
||||
IMaterialDescriptorGenerator materialGenerator = null,
|
||||
VrmMetaInformationCallback vrmMetaInformationCallback = null,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
return await LoadAsync(
|
||||
string.Empty,
|
||||
bytes,
|
||||
canLoadVrm0X,
|
||||
normalizeTransform,
|
||||
showMeshes,
|
||||
awaitCaller,
|
||||
materialGenerator,
|
||||
vrmMetaInformationCallback,
|
||||
ct);
|
||||
}
|
||||
|
||||
private static async Task<Vrm10Instance> LoadAsync(
|
||||
string name,
|
||||
byte[] bytes,
|
||||
bool canLoadVrm0X,
|
||||
bool normalizeTransform,
|
||||
bool showMeshes,
|
||||
IAwaitCaller awaitCaller,
|
||||
IMaterialDescriptorGenerator materialGenerator,
|
||||
VrmMetaInformationCallback vrmMetaInformationCallback,
|
||||
CancellationToken ct)
|
||||
{
|
||||
using (var data = new GlbLowLevelParser(name, bytes).Parse())
|
||||
{
|
||||
// 1. Try loading as vrm-1.0
|
||||
var vrm10Data = Vrm10Data.Parse(data);
|
||||
var vrm10Instance = await LoadVrm10DataAsync(
|
||||
vrm10Data,
|
||||
null,
|
||||
normalizeTransform,
|
||||
showMeshes,
|
||||
awaitCaller,
|
||||
materialGenerator,
|
||||
vrmMetaInformationCallback,
|
||||
ct);
|
||||
if (vrm10Instance != null) return vrm10Instance;
|
||||
|
||||
if (!canLoadVrm0X)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
// 2. Try migration from vrm-0.x into vrm-1.0
|
||||
MigrationData migrationData;
|
||||
using (var migrated = Vrm10Data.Migrate(data, out vrm10Data, out migrationData))
|
||||
{
|
||||
var instance = await LoadVrm10DataAsync(
|
||||
vrm10Data,
|
||||
migrationData,
|
||||
normalizeTransform,
|
||||
showMeshes,
|
||||
awaitCaller,
|
||||
materialGenerator,
|
||||
vrmMetaInformationCallback,
|
||||
ct);
|
||||
if (instance != null) return instance;
|
||||
}
|
||||
|
||||
// 3. failed
|
||||
if (migrationData != null)
|
||||
{
|
||||
Debug.LogWarning(migrationData.Message);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<Vrm10Instance> LoadVrm10DataAsync(
|
||||
Vrm10Data vrm10Data,
|
||||
MigrationData migrationData,
|
||||
bool normalizeTransform,
|
||||
bool showMeshes,
|
||||
IAwaitCaller awaitCaller,
|
||||
IMaterialDescriptorGenerator materialGenerator,
|
||||
VrmMetaInformationCallback vrmMetaInformationCallback,
|
||||
CancellationToken ct)
|
||||
{
|
||||
if (vrm10Data == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
using (var loader = new Vrm10Importer(vrm10Data, materialGenerator: materialGenerator, doNormalize: normalizeTransform))
|
||||
{
|
||||
// 1. Load meta information if callback was available.
|
||||
if (vrmMetaInformationCallback != null)
|
||||
{
|
||||
var thumbnail = await loader.LoadVrmThumbnailAsync();
|
||||
if (migrationData != null)
|
||||
{
|
||||
vrmMetaInformationCallback(thumbnail, default, migrationData.OriginalMetaBeforeMigration);
|
||||
}
|
||||
else
|
||||
{
|
||||
vrmMetaInformationCallback(thumbnail, vrm10Data.VrmExtension.Meta, default);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Load
|
||||
var gltfInstance = await loader.LoadAsync(awaitCaller);
|
||||
if (ct.IsCancellationRequested)
|
||||
{
|
||||
gltfInstance.Dispose();
|
||||
return default;
|
||||
}
|
||||
|
||||
var vrm10Instance = gltfInstance.GetComponent<Vrm10Instance>();
|
||||
if (vrm10Instance == null)
|
||||
{
|
||||
gltfInstance.Dispose();
|
||||
return default;
|
||||
}
|
||||
|
||||
if (showMeshes)
|
||||
{
|
||||
gltfInstance.ShowMeshes();
|
||||
}
|
||||
return vrm10Instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using UniGLTF;
|
||||
using UnityEngine;
|
||||
using VRMShaders;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
public static class Vrm10Utility
|
||||
{
|
||||
public delegate void MetaCallback(Texture2D thumbnail, UniGLTF.Extensions.VRMC_vrm.Meta meta1, Migration.Vrm0Meta meta0);
|
||||
public static async Task<RuntimeGltfInstance> LoadPathAsync(string path,
|
||||
bool doMigrate,
|
||||
bool doNormalize,
|
||||
IAwaitCaller awaitCaller = null,
|
||||
IMaterialDescriptorGenerator materialGenerator = null,
|
||||
MetaCallback metaCallback = null
|
||||
)
|
||||
{
|
||||
return await LoadBytesAsync(path, System.IO.File.ReadAllBytes(path), doMigrate, doNormalize, awaitCaller, materialGenerator, metaCallback);
|
||||
}
|
||||
|
||||
public static async Task<RuntimeGltfInstance> LoadBytesAsync(string path, byte[] bytes,
|
||||
bool doMigrate,
|
||||
bool doNormalize,
|
||||
IAwaitCaller awaitCaller = null,
|
||||
IMaterialDescriptorGenerator materialGenerator = null,
|
||||
MetaCallback metaCallback = null
|
||||
)
|
||||
{
|
||||
// 1st parse as vrm1
|
||||
using (var data = new GlbLowLevelParser(path, bytes).Parse())
|
||||
{
|
||||
var vrm1Data = Vrm10Data.Parse(data);
|
||||
if (vrm1Data != null)
|
||||
{
|
||||
// successfully parsed vrm-1.0
|
||||
using (var loader = new Vrm10Importer(vrm1Data, materialGenerator: materialGenerator, doNormalize: doNormalize))
|
||||
{
|
||||
if (metaCallback != null)
|
||||
{
|
||||
var thumbnail = await loader.LoadVrmThumbnailAsync();
|
||||
metaCallback(thumbnail, vrm1Data.VrmExtension.Meta, null);
|
||||
}
|
||||
var instance = await loader.LoadAsync(awaitCaller);
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
if (!doMigrate)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
// try migration...
|
||||
MigrationData migration;
|
||||
using (var migrated = Vrm10Data.Migrate(data, out vrm1Data, out migration))
|
||||
{
|
||||
if (vrm1Data != null)
|
||||
{
|
||||
// successfully migrated from vrm-0.x
|
||||
using (var loader = new Vrm10Importer(vrm1Data, materialGenerator: materialGenerator, doNormalize: doNormalize))
|
||||
{
|
||||
if (metaCallback != null)
|
||||
{
|
||||
var thumbnail = await loader.LoadVrmThumbnailAsync();
|
||||
metaCallback(thumbnail, vrm1Data.VrmExtension.Meta, null);
|
||||
}
|
||||
var instance = await loader.LoadAsync(awaitCaller);
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fail to migrate...
|
||||
if (migration != null)
|
||||
{
|
||||
Debug.LogWarning(migration.Message);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,12 +22,12 @@ namespace UniVRM10.Sample
|
||||
async void Run()
|
||||
{
|
||||
var src = new FileInfo(m_vrmPath);
|
||||
var instance = await Vrm10Utility.LoadPathAsync(m_vrmPath, true, true);
|
||||
var instance = await Vrm10.LoadPathAsync(m_vrmPath, true, true);
|
||||
|
||||
var exportedBytes = Vrm10Exporter.Export(instance.gameObject);
|
||||
|
||||
// Import 1.0
|
||||
var vrm10 = await Vrm10Utility.LoadBytesAsync("tmp.vrm", exportedBytes, false, true);
|
||||
var vrm10 = await Vrm10.LoadBytesAsync(exportedBytes, false, true);
|
||||
var pos = vrm10.transform.position;
|
||||
pos.x += 1.5f;
|
||||
vrm10.transform.position = pos;
|
||||
|
||||
@@ -38,7 +38,7 @@ RenderSettings:
|
||||
m_ReflectionIntensity: 1
|
||||
m_CustomReflection: {fileID: 0}
|
||||
m_Sun: {fileID: 705507994}
|
||||
m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1}
|
||||
m_IndirectSpecularColor: {r: 0.18028378, g: 0.22571412, b: 0.30692285, a: 1}
|
||||
m_UseRadianceAmbientProbe: 0
|
||||
--- !u!157 &3
|
||||
LightmapSettings:
|
||||
@@ -325,8 +325,7 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: d2dd74f31dd71684da8aa80eaa66390e, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_vrmPath: ../UniVRM_1_0/Tests/Models/Alicia_vrm-0.51/AliciaSolid_vrm-0.51.vrm
|
||||
m_rightHandToLeftHand: 1
|
||||
m_vrmPath: Tests/Models/Alicia_vrm-0.51/AliciaSolid_vrm-0.51.vrm
|
||||
--- !u!4 &1706915413
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -198,7 +198,7 @@ namespace UniVRM10
|
||||
{
|
||||
try
|
||||
{
|
||||
Vrm10Utility.LoadPathAsync(gltf.FullName, true, false).Wait();
|
||||
Vrm10.LoadPathAsync(gltf.FullName, true, false).Wait();
|
||||
}
|
||||
catch (UnNormalizedException)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace UniVRM10
|
||||
|
||||
public static Vrm10Instance LoadAlicia()
|
||||
{
|
||||
var task = Vrm10Utility.LoadPathAsync(AliciaPath, true, true);
|
||||
var task = Vrm10.LoadPathAsync(AliciaPath, true, true);
|
||||
task.Wait();
|
||||
var instance = task.Result;
|
||||
|
||||
|
||||
@@ -82,17 +82,14 @@ namespace UniVRM10.FirstPersonSample
|
||||
}
|
||||
m_target = humanPoseTransfer;
|
||||
SetupTarget(m_target);
|
||||
|
||||
instance.ShowMeshes();
|
||||
}
|
||||
|
||||
async Task<RuntimeGltfInstance> LoadAsync(string path)
|
||||
async Task<Vrm10Instance> LoadAsync(string path)
|
||||
{
|
||||
var instance = await Vrm10Utility.LoadPathAsync(path, true, true);
|
||||
var instance = await Vrm10.LoadPathAsync(path);
|
||||
|
||||
// VR用 FirstPerson 設定
|
||||
var controller = instance.GetComponent<Vrm10Instance>();
|
||||
await controller.Vrm.FirstPerson.SetupAsync(controller.gameObject);
|
||||
await instance.Vrm.FirstPerson.SetupAsync(instance.gameObject);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -415,16 +415,23 @@ namespace UniVRM10.VRM10Viewer
|
||||
}
|
||||
|
||||
Debug.LogFormat("{0}", path);
|
||||
var instance = await Vrm10Utility.LoadPathAsync(path, true, m_useNormalization.isOn,
|
||||
awaitCaller: new RuntimeOnlyAwaitCaller(),
|
||||
materialGenerator: GetVrmMaterialDescriptorGenerator(m_useUrpMaterial.isOn),
|
||||
metaCallback: m_texts.UpdateMeta);
|
||||
if (instance == null)
|
||||
var vrm10Instance = await Vrm10.LoadPathAsync(path,
|
||||
canLoadVrm0X: true,
|
||||
normalizeTransform: m_useNormalization.isOn,
|
||||
showMeshes: false,
|
||||
awaitCaller: new RuntimeOnlyAwaitCaller(),
|
||||
materialGenerator: GetVrmMaterialDescriptorGenerator(m_useUrpMaterial.isOn),
|
||||
vrmMetaInformationCallback: m_texts.UpdateMeta);
|
||||
if (vrm10Instance != null)
|
||||
{
|
||||
SetModel(vrm10Instance.GetComponent<RuntimeGltfInstance>());
|
||||
}
|
||||
else
|
||||
{
|
||||
// fallback to gltf
|
||||
instance = await GltfUtility.LoadAsync(path, awaitCaller: new RuntimeOnlyAwaitCaller());
|
||||
var instance = await GltfUtility.LoadAsync(path, awaitCaller: new RuntimeOnlyAwaitCaller());
|
||||
SetModel(instance);
|
||||
}
|
||||
SetModel(instance);
|
||||
}
|
||||
|
||||
void SetModel(RuntimeGltfInstance instance)
|
||||
|
||||
Reference in New Issue
Block a user