Merge pull request #2478 from ousttrue/fix/remove_vrmlib

[vrm10] vrmlib による mesh 処理を gltf/vrm0.x のものと同じものに
This commit is contained in:
ousttrue
2024-11-06 14:36:05 +09:00
committed by GitHub
9 changed files with 69 additions and 679 deletions

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using UniGLTF.Extensions.VRMC_vrm;
using UnityEngine;
using VrmLib;
namespace UniVRM10
{

View File

@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using VrmLib;
namespace UniVRM10
{

View File

@@ -8,16 +8,16 @@ namespace UniVRM10
{
public static class ExpressionExtensions
{
public static MorphTargetBinding? Build10(this MorphTargetBind bind, GameObject root, Vrm10Importer.ModelMap loader, VrmLib.Model model)
public static MorphTargetBinding? Build10(this MorphTargetBind bind, GameObject root, Vrm10Importer importer)
{
if (bind.Node.TryGetValidIndex(model.Nodes.Count, out var nodeIndex))
if (bind.Node.TryGetValidIndex(importer.Nodes.Count, out var nodeIndex))
{
var libNode = model.Nodes[nodeIndex];
if (libNode.MeshGroup == null)
var node = importer.Nodes[nodeIndex];
var smr = node.GetComponent<SkinnedMeshRenderer>();
if (smr == null)
{
return default;
}
var node = loader.Nodes[libNode].transform;
var relativePath = node.RelativePathFrom(root.transform);
return new MorphTargetBinding(relativePath, bind.Index.Value, bind.Weight.Value);
}

View File

@@ -1,307 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UniGLTF;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
using VrmLib;
using Mesh = UnityEngine.Mesh;
namespace UniVRM10
{
public static class MeshImporterDivided
{
public static Mesh LoadDivided(MeshGroup meshGroup)
{
Profiler.BeginSample("MeshImporterDivided.LoadDivided");
var vertexCount = meshGroup.Meshes.Sum(mesh => mesh.VertexBuffer.Count);
var indexCount = meshGroup.Meshes.Sum(mesh => mesh.IndexBuffer.Count);
var resultMesh = new Mesh();
// 頂点バッファ・BindPoseを構築して更新
UpdateVerticesAndBindPose(meshGroup, vertexCount, resultMesh);
// インデックスバッファを構築して更新
UpdateIndices(meshGroup, vertexCount, indexCount, resultMesh);
// SubMeshを更新
resultMesh.subMeshCount = meshGroup.Meshes.Count;
var indexOffset = 0;
for (var i = 0; i < meshGroup.Meshes.Count; ++i)
{
var mesh = meshGroup.Meshes[i];
resultMesh.SetSubMesh(i, new SubMeshDescriptor(indexOffset, mesh.IndexBuffer.Count));
indexOffset += mesh.IndexBuffer.Count;
}
// 各種データを再構築
resultMesh.RecalculateBounds();
resultMesh.RecalculateTangents();
if (meshGroup.Meshes.Any(mesh => mesh.VertexBuffer.Normals == null))
{
resultMesh.RecalculateNormals();
}
// BlendShapeを更新
var blendShapeCount = meshGroup.Meshes[0].MorphTargets.Count;
for (var i = 0; i < blendShapeCount; ++i)
{
var positionsCount = 0;
var normalsCount = 0;
foreach (var mesh in meshGroup.Meshes)
{
var morphTarget = mesh.MorphTargets[i];
positionsCount += morphTarget.VertexBuffer.Positions.Count;
normalsCount += morphTarget.VertexBuffer.Normals?.Count ?? morphTarget.VertexBuffer.Count;
}
using (var blendShapePositions = new NativeArray<Vector3>(positionsCount, Allocator.Temp))
using (var blendShapeNormals = new NativeArray<Vector3>(normalsCount, Allocator.Temp))
{
var blendShapePositionOffset = 0;
var blendShapeNormalOffset = 0;
foreach (var mesh in meshGroup.Meshes)
{
var morphTarget = mesh.MorphTargets[i];
NativeArray<Vector3>.Copy(
morphTarget.VertexBuffer.Positions.Bytes.Reinterpret<Vector3>(1),
blendShapePositions.GetSubArray(blendShapePositionOffset, morphTarget.VertexBuffer.Positions.Count));
if (morphTarget.VertexBuffer.Normals != null)
{
// nullならdefault(0)のまま
NativeArray<Vector3>.Copy(
morphTarget.VertexBuffer.Normals.Bytes.Reinterpret<Vector3>(1),
blendShapeNormals.GetSubArray(blendShapeNormalOffset, morphTarget.VertexBuffer.Normals.Count));
}
blendShapePositionOffset += morphTarget.VertexBuffer.Positions.Count;
blendShapeNormalOffset += morphTarget.VertexBuffer.Normals?.Count ?? morphTarget.VertexBuffer.Count;
}
resultMesh.AddBlendShapeFrame(meshGroup.Meshes[0].MorphTargets[i].Name,
100.0f,
blendShapePositions.ToArray(),
blendShapeNormals.ToArray(),
null);
}
}
Profiler.EndSample();
return resultMesh;
}
/// <summary>
/// インデックスバッファを更新する
/// MEMO: 出力に対するushortを考慮することをやめればかなりシンプルに書ける
/// </summary>
private static void UpdateIndices(MeshGroup meshGroup, int vertexCount, int indexCount, Mesh resultMesh)
{
Profiler.BeginSample("MeshImporterDivided.UpdateIndices");
JobHandle jobHandle = default;
var disposables = new List<IDisposable>();
//
// https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#_accessor_componenttype
//
if (vertexCount < ushort.MaxValue)
{
// vertex buffer への index が ushort に収まる
var indices = new NativeArray<ushort>(indexCount, Allocator.TempJob);
disposables.Add(indices);
var indexOffset = 0;
var vertexOffset = 0;
foreach (var mesh in meshGroup.Meshes)
{
switch (mesh.IndexBuffer.ComponentType)
{
case AccessorValueType.BYTE:
case AccessorValueType.UNSIGNED_BYTE:
case AccessorValueType.FLOAT:
throw new NotImplementedException($"{mesh.IndexBuffer.ComponentType}");
case AccessorValueType.SHORT:
case AccessorValueType.UNSIGNED_SHORT:
{
// unsigned short -> unsigned short
var source = mesh.IndexBuffer.Bytes.Reinterpret<ushort>(1);
jobHandle = new CopyIndicesJobs.Ushort2Ushort(
(ushort)vertexOffset,
new NativeSlice<ushort>(source),
new NativeSlice<ushort>(indices, indexOffset, mesh.IndexBuffer.Count))
.Schedule(mesh.IndexBuffer.Count, 1, jobHandle);
break;
}
case AccessorValueType.UNSIGNED_INT:
{
// unsigned int -> unsigned short
var source = mesh.IndexBuffer.Bytes.Reinterpret<uint>(1);
jobHandle = new CopyIndicesJobs.Uint2Ushort(
(ushort)vertexOffset,
source,
new NativeSlice<ushort>(indices, indexOffset, mesh.IndexBuffer.Count))
.Schedule(mesh.IndexBuffer.Count, 1, jobHandle);
break;
}
default:
throw new ArgumentException($"unknown index buffer type: {mesh.IndexBuffer.ComponentType}");
}
vertexOffset += mesh.VertexBuffer.Count;
indexOffset += mesh.IndexBuffer.Count;
}
jobHandle.Complete();
resultMesh.SetIndexBufferParams(indexCount, IndexFormat.UInt16);
resultMesh.SetIndexBufferData(indices, 0, 0, indexCount);
}
else
{
// vertex buffer への index が ushort を超える
var indices = new NativeArray<uint>(indexCount, Allocator.TempJob);
disposables.Add(indices);
var indexOffset = 0;
var vertexOffset = 0;
foreach (var mesh in meshGroup.Meshes)
{
switch (mesh.IndexBuffer.ComponentType)
{
case AccessorValueType.BYTE:
case AccessorValueType.UNSIGNED_BYTE:
case AccessorValueType.FLOAT:
throw new NotImplementedException($"{mesh.IndexBuffer.ComponentType}");
case AccessorValueType.SHORT:
case AccessorValueType.UNSIGNED_SHORT:
{
// unsigned short -> unsigned int
var source = mesh.IndexBuffer.Bytes.Reinterpret<ushort>(1);
jobHandle = new CopyIndicesJobs.Ushort2Uint(
(uint)vertexOffset,
source,
new NativeSlice<uint>(indices, indexOffset, mesh.IndexBuffer.Count))
.Schedule(mesh.IndexBuffer.Count, 1, jobHandle);
break;
}
case AccessorValueType.UNSIGNED_INT:
{
// unsigned int -> unsigned int
var source = mesh.IndexBuffer.Bytes.Reinterpret<uint>(1);
jobHandle = new CopyIndicesJobs.UInt2UInt(
(uint)vertexOffset,
source,
new NativeSlice<uint>(indices, indexOffset, mesh.IndexBuffer.Count))
.Schedule(mesh.IndexBuffer.Count, 1, jobHandle);
break;
}
default:
throw new ArgumentException($"unknown index buffer type: {mesh.IndexBuffer.ComponentType}");
}
vertexOffset += mesh.VertexBuffer.Count;
indexOffset += mesh.IndexBuffer.Count;
}
jobHandle.Complete();
resultMesh.SetIndexBufferParams(indexCount, IndexFormat.UInt32);
resultMesh.SetIndexBufferData(indices, 0, 0, indexCount);
}
foreach (var disposable in disposables)
{
disposable.Dispose();
}
Profiler.EndSample();
}
/// <summary>
/// メッシュの頂点情報の更新を行う際、MainThreadが空くため、その間にBindPoseの更新も行う
/// </summary>
private static void UpdateVerticesAndBindPose(
MeshGroup meshGroup,
int vertexCount,
Mesh resultMesh)
{
Profiler.BeginSample("MeshImporterDivided.UpdateVerticesAndBindPose");
var disposables = new List<IDisposable>();
// JobのSchedule
var vertices0 = new NativeArray<MeshVertex0>(vertexCount, Allocator.TempJob);
var vertices1 = new NativeArray<MeshVertex1>(vertexCount, Allocator.TempJob);
var vertices2 = new NativeArray<MeshVertex2>(vertexCount, Allocator.TempJob);
disposables.Add(vertices0);
disposables.Add(vertices1);
disposables.Add(vertices2);
var indexOffset = 0;
JobHandle interleaveVertexJob = default;
foreach (var mesh in meshGroup.Meshes)
{
var positions = mesh.VertexBuffer.Positions.Bytes.Reinterpret<Vector3>(1);
var normals = mesh.VertexBuffer.Normals?.Bytes.Reinterpret<Vector3>(1) ?? default;
var texCoords = mesh.VertexBuffer.TexCoords?.Bytes.Reinterpret<Vector2>(1) ?? default;
var weights = mesh.VertexBuffer.Weights?.GetAsVector4Array() ?? default;
var joints = mesh.VertexBuffer.Joints?.GetAsSkinJointsArray() ?? default;
interleaveVertexJob = new InterleaveMeshVerticesJob(
new NativeSlice<MeshVertex0>(vertices0, indexOffset, mesh.VertexBuffer.Count),
new NativeSlice<MeshVertex1>(vertices1, indexOffset, mesh.VertexBuffer.Count),
new NativeSlice<MeshVertex2>(vertices2, indexOffset, mesh.VertexBuffer.Count),
positions,
normals,
texCoords,
default,
weights,
joints)
.Schedule(mesh.VertexBuffer.Count, 1, interleaveVertexJob);
indexOffset += mesh.VertexBuffer.Count;
}
JobHandle.ScheduleBatchedJobs();
// 並行してBindposeの更新を行う
if (meshGroup.Skin != null)
{
resultMesh.bindposes = meshGroup.Skin.InverseMatrices.GetSpan<Matrix4x4>().ToArray();
}
// Jobを完了
interleaveVertexJob.Complete();
// VertexBufferを設定
MeshVertexUtility.SetVertexBufferParamsToMesh(resultMesh, vertexCount);
resultMesh.SetVertexBufferData(vertices0, 0, 0, vertexCount);
resultMesh.SetVertexBufferData(vertices1, 0, 0, vertexCount, 1);
resultMesh.SetVertexBufferData(vertices2, 0, 0, vertexCount, 2);
// 各種バッファを破棄
foreach (var disposable in disposables)
{
disposable.Dispose();
}
Profiler.EndSample();
}
}
}

View File

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

View File

@@ -1,150 +0,0 @@
using System;
using UniGLTF;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
using VrmLib;
using Mesh = UnityEngine.Mesh;
namespace UniVRM10
{
public static class MeshImporterShared
{
/// <summary>
/// VrmLib.Mesh => UnityEngine.Mesh
/// </summary>
/// <param name="mesh"></param>
/// <param name="src"></param>
/// <param name="skin"></param>
public static Mesh LoadSharedMesh(VrmLib.Mesh src, Skin skin = null)
{
Profiler.BeginSample("MeshImporterShared.LoadSharedMesh");
var mesh = new Mesh();
var positions = src.VertexBuffer.Positions.Bytes.Reinterpret<Vector3>(1);
var normals = src.VertexBuffer.Normals?.Bytes.Reinterpret<Vector3>(1) ?? default;
var texCoords = src.VertexBuffer.TexCoords?.Bytes.Reinterpret<Vector2>(1) ?? default;
NativeArray<Color> colors = default;
if (src.VertexBuffer.Colors is BufferAccessor colorBuffer)
{
if (colorBuffer.ComponentType == AccessorValueType.FLOAT && colorBuffer.AccessorType == AccessorVectorType.VEC4)
{
colors = colorBuffer.Bytes.Reinterpret<Color>(1);
}
else
{
Debug.LogWarning($"COLOR_0: {colorBuffer.ComponentType}.{colorBuffer.AccessorType} not supported. skip.");
}
}
var weights = src.VertexBuffer.Weights?.GetAsVector4Array() ?? default;
var joints = src.VertexBuffer.Joints?.GetAsSkinJointsArray() ?? default;
using (var vertices0 = new NativeArray<MeshVertex0>(positions.Length, Allocator.TempJob))
using (var vertices1 = new NativeArray<MeshVertex1>(positions.Length, Allocator.TempJob))
using (var vertices2 = new NativeArray<MeshVertex2>(positions.Length, Allocator.TempJob))
{
// JobとBindPoseの更新を並行して行う
var jobHandle =
new InterleaveMeshVerticesJob(
vertices0,
vertices1,
vertices2,
positions,
normals,
texCoords,
colors,
weights,
joints
)
.Schedule(vertices0.Length, 1);
JobHandle.ScheduleBatchedJobs();
// BindPoseを更新
if (weights.IsCreated && joints.IsCreated)
{
if (weights.Length != positions.Length || joints.Length != positions.Length)
{
throw new ArgumentException();
}
if (skin != null)
{
mesh.bindposes = skin.InverseMatrices.GetSpan<Matrix4x4>().ToArray();
}
}
// Jobを完了
jobHandle.Complete();
// 頂点を更新
MeshVertexUtility.SetVertexBufferParamsToMesh(mesh, vertices0.Length);
mesh.SetVertexBufferData(vertices0, 0, 0, vertices0.Length);
mesh.SetVertexBufferData(vertices1, 0, 0, vertices0.Length, 1);
mesh.SetVertexBufferData(vertices2, 0, 0, vertices0.Length, 2);
// 出力のNativeArrayを開放
}
// Indexを更新
switch (src.IndexBuffer.ComponentType)
{
case AccessorValueType.UNSIGNED_BYTE:
{
var intIndices = src.IndexBuffer.GetAsIntArray();
mesh.SetIndexBufferParams(intIndices.Length, IndexFormat.UInt32);
mesh.SetIndexBufferData(intIndices, 0, 0, intIndices.Length);
break;
}
case AccessorValueType.UNSIGNED_SHORT:
{
var shortIndices = src.IndexBuffer.Bytes.Reinterpret<ushort>(1);
mesh.SetIndexBufferParams(shortIndices.Length, IndexFormat.UInt16);
mesh.SetIndexBufferData(shortIndices, 0, 0, shortIndices.Length);
break;
}
case AccessorValueType.UNSIGNED_INT:
{
var intIndices = src.IndexBuffer.Bytes.Reinterpret<uint>(1);
mesh.SetIndexBufferParams(intIndices.Length, IndexFormat.UInt32);
mesh.SetIndexBufferData(intIndices, 0, 0, intIndices.Length);
break;
}
default:
throw new NotImplementedException();
}
// SubMeshを更新
mesh.subMeshCount = src.Submeshes.Count;
for (var i = 0; i < src.Submeshes.Count; ++i)
{
var subMesh = src.Submeshes[i];
mesh.SetSubMesh(i, new SubMeshDescriptor(subMesh.Offset, subMesh.DrawCount));
}
// MorphTargetを更新
foreach (var morphTarget in src.MorphTargets)
{
var morphTargetPositions =
morphTarget.VertexBuffer.Positions != null
? morphTarget.VertexBuffer.Positions.GetSpan<Vector3>().ToArray()
: new Vector3[mesh.vertexCount] // dummy
;
mesh.AddBlendShapeFrame(morphTarget.Name, 100.0f, morphTargetPositions, null, null);
}
// 各種パラメーターを再計算
mesh.RecalculateBounds();
mesh.RecalculateTangents();
if (src.VertexBuffer.Normals == null)
{
mesh.RecalculateNormals();
}
Profiler.EndSample();
return mesh;
}
}
}

View File

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

View File

@@ -15,10 +15,10 @@ namespace UniVRM10
{
private readonly Vrm10Data m_vrm;
/// VrmLib.Model の オブジェクトと UnityEngine.Object のマッピングを記録する
private readonly ModelMap m_map = new ModelMap();
// private readonly ModelMap m_map = new ModelMap();
private readonly bool m_useControlRig;
private VrmLib.Model m_model;
// private VrmLib.Model m_model;
private IReadOnlyDictionary<SubAssetKey, UnityEngine.Object> m_externalMap;
private Avatar m_humanoid;
private VRM10Object m_vrmObject;
@@ -36,7 +36,9 @@ namespace UniVRM10
IVrm10SpringBoneRuntime springboneRuntime = null,
bool isAssetImport = false
)
: base(vrm.Data, externalObjectMap, textureDeserializer, settings: settings, isAssetImport: isAssetImport)
: base(vrm.Data, externalObjectMap, textureDeserializer,
settings: new ImporterContextSettings(false, Axes.X),
isAssetImport: isAssetImport)
{
if (vrm == null)
{
@@ -97,177 +99,63 @@ namespace UniVRM10
}
}
public override async Task<RuntimeGltfInstance> LoadAsync(IAwaitCaller awaitCaller, Func<string, IDisposable> MeasureTime = null)
static IEnumerable<(HumanBodyBones, Transform)> EnumerateHumanbones(List<Transform> nodes, UniGLTF.Extensions.VRMC_vrm.HumanBones bones)
{
if (awaitCaller == null)
{
throw new ArgumentNullException();
}
// NOTE: VRM データに対して、Load 前に必要なヘビーな変換処理を行う.
// ヘビーなため、別スレッドで Run する.
await awaitCaller.Run(() =>
{
// bin に対して右手左手変換を破壊的に実行することに注意 !(bin が変換済みになる)
m_model = ModelReader.Read(Data);
// assign humanoid bones
if (m_vrm.VrmExtension.Humanoid is UniGLTF.Extensions.VRMC_vrm.Humanoid humanoid)
{
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.Hips, VrmLib.HumanoidBones.hips);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftUpperLeg, VrmLib.HumanoidBones.leftUpperLeg);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightUpperLeg, VrmLib.HumanoidBones.rightUpperLeg);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftLowerLeg, VrmLib.HumanoidBones.leftLowerLeg);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightLowerLeg, VrmLib.HumanoidBones.rightLowerLeg);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftFoot, VrmLib.HumanoidBones.leftFoot);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightFoot, VrmLib.HumanoidBones.rightFoot);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.Spine, VrmLib.HumanoidBones.spine);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.Chest, VrmLib.HumanoidBones.chest);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.Neck, VrmLib.HumanoidBones.neck);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.Head, VrmLib.HumanoidBones.head);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftShoulder, VrmLib.HumanoidBones.leftShoulder);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightShoulder, VrmLib.HumanoidBones.rightShoulder);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftUpperArm, VrmLib.HumanoidBones.leftUpperArm);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightUpperArm, VrmLib.HumanoidBones.rightUpperArm);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftLowerArm, VrmLib.HumanoidBones.leftLowerArm);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightLowerArm, VrmLib.HumanoidBones.rightLowerArm);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftHand, VrmLib.HumanoidBones.leftHand);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightHand, VrmLib.HumanoidBones.rightHand);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftToes, VrmLib.HumanoidBones.leftToes);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightToes, VrmLib.HumanoidBones.rightToes);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftEye, VrmLib.HumanoidBones.leftEye);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightEye, VrmLib.HumanoidBones.rightEye);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.Jaw, VrmLib.HumanoidBones.jaw);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftThumbMetacarpal, VrmLib.HumanoidBones.leftThumbMetacarpal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftThumbProximal, VrmLib.HumanoidBones.leftThumbProximal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftThumbDistal, VrmLib.HumanoidBones.leftThumbDistal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftIndexProximal, VrmLib.HumanoidBones.leftIndexProximal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftIndexIntermediate, VrmLib.HumanoidBones.leftIndexIntermediate);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftIndexDistal, VrmLib.HumanoidBones.leftIndexDistal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftMiddleProximal, VrmLib.HumanoidBones.leftMiddleProximal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftMiddleIntermediate, VrmLib.HumanoidBones.leftMiddleIntermediate);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftMiddleDistal, VrmLib.HumanoidBones.leftMiddleDistal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftRingProximal, VrmLib.HumanoidBones.leftRingProximal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftRingIntermediate, VrmLib.HumanoidBones.leftRingIntermediate);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftRingDistal, VrmLib.HumanoidBones.leftRingDistal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftLittleProximal, VrmLib.HumanoidBones.leftLittleProximal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftLittleIntermediate, VrmLib.HumanoidBones.leftLittleIntermediate);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.LeftLittleDistal, VrmLib.HumanoidBones.leftLittleDistal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightThumbMetacarpal, VrmLib.HumanoidBones.rightThumbMetacarpal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightThumbProximal, VrmLib.HumanoidBones.rightThumbProximal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightThumbDistal, VrmLib.HumanoidBones.rightThumbDistal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightIndexProximal, VrmLib.HumanoidBones.rightIndexProximal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightIndexIntermediate, VrmLib.HumanoidBones.rightIndexIntermediate);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightIndexDistal, VrmLib.HumanoidBones.rightIndexDistal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightMiddleProximal, VrmLib.HumanoidBones.rightMiddleProximal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightMiddleIntermediate, VrmLib.HumanoidBones.rightMiddleIntermediate);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightMiddleDistal, VrmLib.HumanoidBones.rightMiddleDistal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightRingProximal, VrmLib.HumanoidBones.rightRingProximal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightRingIntermediate, VrmLib.HumanoidBones.rightRingIntermediate);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightRingDistal, VrmLib.HumanoidBones.rightRingDistal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightLittleProximal, VrmLib.HumanoidBones.rightLittleProximal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightLittleIntermediate, VrmLib.HumanoidBones.rightLittleIntermediate);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.RightLittleDistal, VrmLib.HumanoidBones.rightLittleDistal);
AssignHumanoid(m_model.Nodes, humanoid.HumanBones.UpperChest, VrmLib.HumanoidBones.upperChest);
}
});
return await base.LoadAsync(awaitCaller, MeasureTime);
}
/// <summary>
/// VrmLib.Model から 構築する
/// </summary>
/// <param name="MeasureTime"></param>
/// <returns></returns>
protected override async Task LoadGeometryAsync(IAwaitCaller awaitCaller, Func<string, IDisposable> MeasureTime)
{
// fill assets
for (int i = 0; i < m_model.Materials.Count; ++i)
{
var src = m_model.Materials[i];
var dst = MaterialFactory.Materials[i].Asset;
}
await awaitCaller.NextFrame();
// mesh
for (int i = 0; i < m_model.MeshGroups.Count; ++i)
{
var src = m_model.MeshGroups[i];
UnityEngine.Mesh mesh = default;
if (src.Meshes.Count == 1)
{
mesh = MeshImporterShared.LoadSharedMesh(src.Meshes[0], src.Skin);
}
else
{
// 頂点バッファの連結が必用
// VRM-1 はこっち
// https://github.com/vrm-c/UniVRM/issues/800
mesh = MeshImporterDivided.LoadDivided(src);
}
mesh.name = src.Name;
m_map.Meshes.Add(src, mesh);
Meshes.Add(new MeshWithMaterials
{
Mesh = mesh,
Materials = src.Meshes[0].Submeshes.Select(
x =>
{
if (x.Material.HasValidIndex())
{
return MaterialFactory.Materials[x.Material.Value].Asset;
}
else
{
return null;
}
}
).ToArray(),
});
await awaitCaller.NextFrame();
}
// node: recursive
CreateNodes(m_model.Root, null, m_map.Nodes);
for (int i = 0; i < m_model.Nodes.Count; ++i)
{
Nodes.Add(m_map.Nodes[m_model.Nodes[i]].transform);
}
await awaitCaller.NextFrame();
if (Root == null)
{
Root = m_map.Nodes[m_model.Root];
}
else
{
// replace
var modelRoot = m_map.Nodes[m_model.Root];
foreach (Transform child in modelRoot.transform)
{
child.SetParent(Root.transform, true);
}
m_map.Nodes[m_model.Root] = Root;
}
await awaitCaller.NextFrame();
// renderer
var map = m_map;
foreach (var (node, go) in map.Nodes.Select(kv => (kv.Key, kv.Value)))
{
if (node.MeshGroup is null)
{
continue;
}
await CreateRendererAsync(node, go, map, MaterialFactory, awaitCaller);
await awaitCaller.NextFrame();
}
{ if (bones.Hips != null && bones.Hips.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.Hips, nodes[index]); }
{ if (bones.LeftUpperLeg != null && bones.LeftUpperLeg.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftUpperLeg, nodes[index]); }
{ if (bones.RightUpperLeg != null && bones.RightUpperLeg.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightUpperLeg, nodes[index]); }
{ if (bones.LeftLowerLeg != null && bones.LeftLowerLeg.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftLowerLeg, nodes[index]); }
{ if (bones.RightLowerLeg != null && bones.RightLowerLeg.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightLowerLeg, nodes[index]); }
{ if (bones.LeftFoot != null && bones.LeftFoot.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftFoot, nodes[index]); }
{ if (bones.RightFoot != null && bones.RightFoot.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightFoot, nodes[index]); }
{ if (bones.Spine != null && bones.Spine.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.Spine, nodes[index]); }
{ if (bones.Chest != null && bones.Chest.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.Chest, nodes[index]); }
{ if (bones.Neck != null && bones.Neck.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.Neck, nodes[index]); }
{ if (bones.Head != null && bones.Head.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.Head, nodes[index]); }
{ if (bones.LeftShoulder != null && bones.LeftShoulder.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftShoulder, nodes[index]); }
{ if (bones.RightShoulder != null && bones.RightShoulder.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightShoulder, nodes[index]); }
{ if (bones.LeftUpperArm != null && bones.LeftUpperArm.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftUpperArm, nodes[index]); }
{ if (bones.RightUpperArm != null && bones.RightUpperArm.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightUpperArm, nodes[index]); }
{ if (bones.LeftLowerArm != null && bones.LeftLowerArm.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftLowerArm, nodes[index]); }
{ if (bones.RightLowerArm != null && bones.RightLowerArm.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightLowerArm, nodes[index]); }
{ if (bones.LeftHand != null && bones.LeftHand.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftHand, nodes[index]); }
{ if (bones.RightHand != null && bones.RightHand.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightHand, nodes[index]); }
{ if (bones.LeftToes != null && bones.LeftToes.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftToes, nodes[index]); }
{ if (bones.RightToes != null && bones.RightToes.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightToes, nodes[index]); }
{ if (bones.LeftEye != null && bones.LeftEye.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftEye, nodes[index]); }
{ if (bones.RightEye != null && bones.RightEye.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightEye, nodes[index]); }
{ if (bones.Jaw != null && bones.Jaw.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.Jaw, nodes[index]); }
{ if (bones.LeftThumbMetacarpal != null && bones.LeftThumbMetacarpal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftThumbProximal, nodes[index]); }
{ if (bones.LeftThumbProximal != null && bones.LeftThumbProximal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftThumbIntermediate, nodes[index]); }
{ if (bones.LeftThumbDistal != null && bones.LeftThumbDistal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftThumbDistal, nodes[index]); }
{ if (bones.LeftIndexProximal != null && bones.LeftIndexProximal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftIndexProximal, nodes[index]); }
{ if (bones.LeftIndexIntermediate != null && bones.LeftIndexIntermediate.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftIndexIntermediate, nodes[index]); }
{ if (bones.LeftIndexDistal != null && bones.LeftIndexDistal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftIndexDistal, nodes[index]); }
{ if (bones.LeftMiddleProximal != null && bones.LeftMiddleProximal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftMiddleProximal, nodes[index]); }
{ if (bones.LeftMiddleIntermediate != null && bones.LeftMiddleIntermediate.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftMiddleIntermediate, nodes[index]); }
{ if (bones.LeftMiddleDistal != null && bones.LeftMiddleDistal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftMiddleDistal, nodes[index]); }
{ if (bones.LeftRingProximal != null && bones.LeftRingProximal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftRingProximal, nodes[index]); }
{ if (bones.LeftRingIntermediate != null && bones.LeftRingIntermediate.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftRingIntermediate, nodes[index]); }
{ if (bones.LeftRingDistal != null && bones.LeftRingDistal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftRingDistal, nodes[index]); }
{ if (bones.LeftLittleProximal != null && bones.LeftLittleProximal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftLittleProximal, nodes[index]); }
{ if (bones.LeftLittleIntermediate != null && bones.LeftLittleIntermediate.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftLittleIntermediate, nodes[index]); }
{ if (bones.LeftLittleDistal != null && bones.LeftLittleDistal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.LeftLittleDistal, nodes[index]); }
{ if (bones.RightThumbMetacarpal != null && bones.RightThumbMetacarpal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightThumbProximal, nodes[index]); }
{ if (bones.RightThumbProximal != null && bones.RightThumbProximal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightThumbIntermediate, nodes[index]); }
{ if (bones.RightThumbDistal != null && bones.RightThumbDistal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightThumbDistal, nodes[index]); }
{ if (bones.RightIndexProximal != null && bones.RightIndexProximal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightIndexProximal, nodes[index]); }
{ if (bones.RightIndexIntermediate != null && bones.RightIndexIntermediate.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightIndexIntermediate, nodes[index]); }
{ if (bones.RightIndexDistal != null && bones.RightIndexDistal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightIndexDistal, nodes[index]); }
{ if (bones.RightMiddleProximal != null && bones.RightMiddleProximal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightMiddleProximal, nodes[index]); }
{ if (bones.RightMiddleIntermediate != null && bones.RightMiddleIntermediate.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightMiddleIntermediate, nodes[index]); }
{ if (bones.RightMiddleDistal != null && bones.RightMiddleDistal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightMiddleDistal, nodes[index]); }
{ if (bones.RightRingProximal != null && bones.RightRingProximal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightRingProximal, nodes[index]); }
{ if (bones.RightRingIntermediate != null && bones.RightRingIntermediate.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightRingIntermediate, nodes[index]); }
{ if (bones.RightRingDistal != null && bones.RightRingDistal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightRingDistal, nodes[index]); }
{ if (bones.RightLittleProximal != null && bones.RightLittleProximal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightLittleProximal, nodes[index]); }
{ if (bones.RightLittleIntermediate != null && bones.RightLittleIntermediate.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightLittleIntermediate, nodes[index]); }
{ if (bones.RightLittleDistal != null && bones.RightLittleDistal.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.RightLittleDistal, nodes[index]); }
{ if (bones.UpperChest != null && bones.UpperChest.Node.TryGetValidIndex(nodes.Count, out var index)) yield return (HumanBodyBones.UpperChest, nodes[index]); }
}
/// <summary>
@@ -279,7 +167,7 @@ namespace UniVRM10
// humanoid
var humanoid = Root.AddComponent<UniHumanoid.Humanoid>();
humanoid.AssignBones(m_map.Nodes.Select(x => (ToUnity(x.Key.HumanoidBone.GetValueOrDefault()), x.Value.transform)));
humanoid.AssignBones(EnumerateHumanbones(Nodes, m_vrm.VrmExtension.Humanoid.HumanBones));
m_humanoid = humanoid.CreateAvatar();
m_humanoid.name = "humanoid";
var animator = Root.AddComponent<Animator>();
@@ -362,7 +250,7 @@ namespace UniVRM10
if (expression.MorphTargetBinds != null)
{
clip.MorphTargetBindings = expression.MorphTargetBinds?
.Select(x => x.Build10(Root, m_map, m_model))
.Select(x => x.Build10(Root, this))
.Where(x => x.HasValue)
.Select(x => x.Value)
.ToArray();

View File

@@ -1,8 +1,5 @@
using System;
using System.IO;
using System.IO;
using UnityEngine;
using VrmLib;
using UniGLTF;
namespace UniVRM10.Sample
@@ -38,18 +35,5 @@ namespace UniVRM10.Sample
Debug.Log($"write : {path}");
File.WriteAllBytes(path, exportedBytes);
}
static void Printmatrices(Model model)
{
var matrices = model.Skins[0].InverseMatrices.GetSpan<System.Numerics.Matrix4x4>();
var sb = new System.Text.StringBuilder();
for (int i = 0; i < matrices.Length; ++i)
{
var m = matrices[i];
sb.AppendLine($"#{i:00}[{m.M11:.00}, {m.M12:.00}, {m.M13:.00}, {m.M14:.00}][{m.M21:.00}, {m.M22:.00}, {m.M23:.00}, {m.M24:.00}][{m.M31:.00}, {m.M32:.00}, {m.M33:.00}, {m.M34:.00}][{m.M41:.00}, {m.M42:.00}, {m.M43:.00}, {m.M44:.00}]");
}
Debug.Log(sb.ToString());
}
}
}