mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-09-27 05:12:32 -05:00
Merge branch 'master' into fix-springbone-buffer-leak-on-cancel
This commit is contained in:
6
.github/workflows/create-unitypackage.yml
vendored
6
.github/workflows/create-unitypackage.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- id: checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
lfs: true
|
||||
@@ -82,7 +82,7 @@ jobs:
|
||||
|
||||
- name: Upload test results
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: run-edit-mode-tests.xml
|
||||
path: ${{ env.UNITY_PROJECT_PATH }}/run-edit-mode-tests.xml
|
||||
@@ -100,7 +100,7 @@ jobs:
|
||||
echo "Success to create UnityPackage."
|
||||
|
||||
- name: Upload UnityPackage
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: unitypackage
|
||||
path: ${{ env.UNITY_PROJECT_PATH }}/*.unitypackage
|
||||
|
||||
@@ -37,7 +37,17 @@
|
||||
"name": "com.atteneder.gltfast",
|
||||
"expression": "",
|
||||
"define": "UNIGLTF_DISABLE_DEFAULT_GLTF_IMPORTER"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "com.unity.cloud.gltfast",
|
||||
"expression": "",
|
||||
"define": "UNIGLTF_DISABLE_DEFAULT_GLB_IMPORTER"
|
||||
},
|
||||
{
|
||||
"name": "com.unity.cloud.gltfast",
|
||||
"expression": "",
|
||||
"define": "UNIGLTF_DISABLE_DEFAULT_GLTF_IMPORTER"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Linq;
|
||||
using Unity.Profiling;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
@@ -20,6 +21,9 @@ namespace UniGLTF
|
||||
private readonly IReadOnlyDictionary<SubAssetKey, Texture> m_subAssets;
|
||||
UnityPath m_textureDirectory;
|
||||
|
||||
private static ProfilerMarker s_MarkerStartExtractTextures = new ProfilerMarker("Start Extract Textures");
|
||||
private static ProfilerMarker s_MarkerDelayedExtractTextures = new ProfilerMarker("Delayed Extract Textures");
|
||||
|
||||
public TextureExtractor(GltfData data, UnityPath textureDirectory, IReadOnlyDictionary<SubAssetKey, Texture> subAssets)
|
||||
{
|
||||
m_data = data;
|
||||
@@ -77,14 +81,33 @@ namespace UniGLTF
|
||||
Action<SubAssetKey, Texture2D> addRemap,
|
||||
Action<IEnumerable<UnityPath>> onCompleted = null)
|
||||
{
|
||||
s_MarkerStartExtractTextures.Begin();
|
||||
|
||||
var extractor = new TextureExtractor(data, textureDirectory, subAssets);
|
||||
foreach (var param in textureDescriptorGenerator.Get().GetEnumerable())
|
||||
try
|
||||
{
|
||||
extractor.Extract(param.SubAssetKey, param);
|
||||
AssetDatabase.StartAssetEditing();
|
||||
|
||||
foreach (var param in textureDescriptorGenerator.Get().GetEnumerable())
|
||||
{
|
||||
extractor.Extract(param.SubAssetKey, param);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
AssetDatabase.StopAssetEditing();
|
||||
}
|
||||
|
||||
s_MarkerStartExtractTextures.End();
|
||||
|
||||
EditorApplication.delayCall += () =>
|
||||
{
|
||||
s_MarkerDelayedExtractTextures.Begin();
|
||||
|
||||
// Wait for the texture assets to be imported
|
||||
|
||||
foreach (var (key, targetPath) in extractor.Textures)
|
||||
@@ -97,6 +120,8 @@ namespace UniGLTF
|
||||
}
|
||||
}
|
||||
|
||||
s_MarkerDelayedExtractTextures.End();
|
||||
|
||||
if (onCompleted != null)
|
||||
{
|
||||
onCompleted(extractor.Textures.Values);
|
||||
|
||||
@@ -52,8 +52,8 @@ namespace UniGLTF.MeshUtility
|
||||
|
||||
if (copyBlendShape)
|
||||
{
|
||||
var vertices = src.vertices;
|
||||
var normals = src.normals;
|
||||
var deltaVertices = new Vector3[src.vertexCount];
|
||||
var deltaNormals = new Vector3[src.vertexCount];
|
||||
Vector3[] tangents = null;
|
||||
if (Symbols.VRM_NORMALIZE_BLENDSHAPE_TANGENT)
|
||||
{
|
||||
@@ -62,14 +62,18 @@ namespace UniGLTF.MeshUtility
|
||||
|
||||
for (int i = 0; i < src.blendShapeCount; ++i)
|
||||
{
|
||||
src.GetBlendShapeFrameVertices(i, 0, vertices, normals, tangents);
|
||||
dst.AddBlendShapeFrame(
|
||||
src.GetBlendShapeName(i),
|
||||
src.GetBlendShapeFrameWeight(i, 0),
|
||||
vertices,
|
||||
normals,
|
||||
tangents
|
||||
);
|
||||
var frameCount = src.GetBlendShapeFrameCount(i);
|
||||
for (int f = 0; f < frameCount; ++f)
|
||||
{
|
||||
src.GetBlendShapeFrameVertices(i, f, deltaVertices, deltaNormals, tangents);
|
||||
dst.AddBlendShapeFrame(
|
||||
src.GetBlendShapeName(i),
|
||||
src.GetBlendShapeFrameWeight(i, f),
|
||||
deltaVertices,
|
||||
deltaNormals,
|
||||
tangents
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace UniGLTF.SpringBoneJobs
|
||||
case AnglelimitTypes.Cone:
|
||||
{
|
||||
var angleSpaceToWorld = anglelimitSpaceToWorld(logic, joint, parentRotation);
|
||||
var tailDir = math.mul(math.inverse(angleSpaceToWorld), math.normalize(nextTail - head));
|
||||
var tailDir = math.mul(math.inverse(angleSpaceToWorld), math.normalizesafe(nextTail - head));
|
||||
tailDir = AnglelimitCone.Apply(tailDir, joint.anglelimit1);
|
||||
return head + math.mul(angleSpaceToWorld, tailDir) * logic.length;
|
||||
}
|
||||
@@ -26,7 +26,7 @@ namespace UniGLTF.SpringBoneJobs
|
||||
case AnglelimitTypes.Hinge:
|
||||
{
|
||||
var angleSpaceToWorld = anglelimitSpaceToWorld(logic, joint, parentRotation);
|
||||
var tailDir = math.mul(math.inverse(angleSpaceToWorld), math.normalize(nextTail - head));
|
||||
var tailDir = math.mul(math.inverse(angleSpaceToWorld), math.normalizesafe(nextTail - head));
|
||||
tailDir = AnglelimitHinge.Apply(tailDir, joint.anglelimit1);
|
||||
return head + math.mul(angleSpaceToWorld, tailDir) * logic.length;
|
||||
}
|
||||
@@ -35,7 +35,7 @@ namespace UniGLTF.SpringBoneJobs
|
||||
case AnglelimitTypes.Spherical:
|
||||
{
|
||||
var angleSpaceToWorld = anglelimitSpaceToWorld(logic, joint, parentRotation);
|
||||
var tailDir = math.mul(math.inverse(angleSpaceToWorld), math.normalize(nextTail - head));
|
||||
var tailDir = math.mul(math.inverse(angleSpaceToWorld), math.normalizesafe(nextTail - head));
|
||||
tailDir = AnglelimitSpherical.Apply(tailDir, joint.anglelimit1, joint.anglelimit2);
|
||||
return head + math.mul(angleSpaceToWorld, tailDir) * logic.length;
|
||||
}
|
||||
@@ -52,7 +52,7 @@ namespace UniGLTF.SpringBoneJobs
|
||||
in quaternion parentRotation)
|
||||
{
|
||||
// Y+方向からjointのheadからtailに向かうベクトルへの最小回転
|
||||
var axisRotation = fromToQuaternion(new float3(0, 1, 0), logic.boneAxis);
|
||||
var axisRotation = getAxisRotation(logic.boneAxis);
|
||||
|
||||
// limitのローカル空間をワールド空間に写像する回転
|
||||
return
|
||||
@@ -63,29 +63,28 @@ namespace UniGLTF.SpringBoneJobs
|
||||
;
|
||||
}
|
||||
|
||||
// https://discussions.unity.com/t/unity-mathematics-equivalent-to-quaternion-fromtorotation/237459
|
||||
public static quaternion fromToQuaternion(in float3 from, in float3 to)
|
||||
/// <summary>
|
||||
/// Y軸正方向から `to` への回転を表すクォータニオンを計算して返す。
|
||||
/// `to` は正規化されていると仮定する。
|
||||
///
|
||||
/// See: https://github.com/0b5vr/vrm-specification/blob/75fbd48a7cb1d7250fa955838af6140e9c84844c/specification/VRMC_springBone_limit-1.0/README.ja.md#rotation-1
|
||||
///
|
||||
/// TODO: Replace with the appropriate link to the specification later
|
||||
/// </summary>
|
||||
public static quaternion getAxisRotation(in float3 to)
|
||||
{
|
||||
var fromNorm = math.normalize(from);
|
||||
var toNorm = math.normalize(to);
|
||||
var dot = math.dot(fromNorm, toNorm);
|
||||
// dot(from, to) + 1
|
||||
var dot1 = to.y + 1f;
|
||||
|
||||
// Handle the case where from and to are parallel but opposite
|
||||
if (math.abs(dot + 1f) < 1e-6f) // dot is approximately -1
|
||||
// Handle the case where from and to are parallel and opposite
|
||||
if (dot1 < 1e-8f) // dot is approximately -1
|
||||
{
|
||||
// Find a perpendicular axis
|
||||
var perpAxis = math.abs(fromNorm.x) > math.abs(fromNorm.z)
|
||||
? new float3(-fromNorm.y, fromNorm.x, 0f)
|
||||
: new float3(0f, -fromNorm.z, fromNorm.y);
|
||||
return quaternion.AxisAngle(math.normalize(perpAxis), math.PI);
|
||||
return new quaternion(1f, 0f, 0f, 0f);
|
||||
}
|
||||
|
||||
// General case
|
||||
return quaternion.AxisAngle(
|
||||
angle: math.acos(math.clamp(dot, -1f, 1f)),
|
||||
axis: math.normalize(math.cross(fromNorm, toNorm))
|
||||
);
|
||||
// quaternion(cross(from, to); dot(from, to) + 1).normalized
|
||||
return math.normalizesafe(new quaternion(to.z, 0f, -to.x, dot1));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace UniGLTF.SpringBoneJobs
|
||||
// x要素を0にし、正規化する
|
||||
float3 tailDir = src;
|
||||
tailDir.x = 0.0f;
|
||||
tailDir = math.normalize(tailDir);
|
||||
tailDir = math.normalizesafe(tailDir);
|
||||
|
||||
// tailDirのy要素をjointに設定されたangleの余弦と比較する
|
||||
var cosAngle = math.cos(limitAngle);
|
||||
|
||||
@@ -140,7 +140,7 @@ namespace UniGLTF.SpringBoneJobs.Blittables
|
||||
|
||||
if(parent.HasValue)
|
||||
{
|
||||
newLocalRotation = math.normalize(math.mul(math.inverse(parent.Value.rotation), newRotation));
|
||||
newLocalRotation = math.normalizesafe(math.mul(math.inverse(parent.Value.rotation), newRotation));
|
||||
newLocalToWorldMatrix = math.mul(parent.Value.localToWorldMatrix, float4x4.TRS(localPosition, newLocalRotation, localScale));
|
||||
}
|
||||
else
|
||||
|
||||
@@ -125,7 +125,7 @@ namespace UniGLTF.SpringBoneJobs.InputPorts
|
||||
parentTransformIndex: Array.IndexOf<Transform>(Transforms, joint.Transform.parent),
|
||||
tailTransformIndex: Array.IndexOf<Transform>(Transforms, tailJoint.Transform),
|
||||
localRotation: joint.DefaultLocalRotation,
|
||||
boneAxis: math.normalize(localChildPosition),
|
||||
boneAxis: math.normalizesafe(localChildPosition),
|
||||
length: math.length(localChildPosition));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,10 +47,10 @@ namespace UniGLTF.SpringBoneJobs
|
||||
if (math.lengthsq(nextTail - worldPosition) <= (r * r))
|
||||
{
|
||||
// ヒット。Colliderの半径方向に押し出す
|
||||
var normal = math.normalize(nextTail - worldPosition);
|
||||
var normal = math.normalizesafe(nextTail - worldPosition);
|
||||
var posFromCollider = worldPosition + normal * r;
|
||||
// 長さをboneLengthに強制
|
||||
newNextTail = headTransform.position + math.normalize(posFromCollider - headTransform.position) * logic.length;
|
||||
newNextTail = headTransform.position + math.normalizesafe(posFromCollider - headTransform.position) * logic.length;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -76,7 +76,7 @@ namespace UniGLTF.SpringBoneJobs
|
||||
// head側半球の球判定
|
||||
return TryResolveSphereCollision(joint, collider, worldPosition, headTransform, maxColliderScale, logic, nextTail, out newNextTail);
|
||||
}
|
||||
var P = math.normalize(direction);
|
||||
var P = math.normalizesafe(direction);
|
||||
var Q = headTransform.position - worldPosition;
|
||||
var dot = math.dot(P, Q);
|
||||
if (dot <= 0)
|
||||
@@ -110,7 +110,7 @@ namespace UniGLTF.SpringBoneJobs
|
||||
in float3 nextTail, out float3 newNextTail)
|
||||
{
|
||||
var transformedOffset = MathHelper.MultiplyPoint(colliderTransform.localToWorldMatrix, collider.offset);
|
||||
var transformedNormal = math.normalize(MathHelper.MultiplyVector(colliderTransform.localToWorldMatrix, collider.tailOrNormal));
|
||||
var transformedNormal = math.normalizesafe(MathHelper.MultiplyVector(colliderTransform.localToWorldMatrix, collider.tailOrNormal));
|
||||
var delta = nextTail - transformedOffset;
|
||||
|
||||
// ジョイントとコライダーの距離。負の値は衝突していることを示す
|
||||
@@ -145,7 +145,7 @@ namespace UniGLTF.SpringBoneJobs
|
||||
// ジョイントとコライダーの距離の方向。衝突している場合、この方向にジョイントを押し出す
|
||||
if (distance < 0)
|
||||
{
|
||||
var direction = -1 * math.normalize(delta);
|
||||
var direction = -1 * math.normalizesafe(delta);
|
||||
newNextTail = nextTail - direction * distance;
|
||||
return true;
|
||||
}
|
||||
@@ -192,7 +192,7 @@ namespace UniGLTF.SpringBoneJobs
|
||||
// ジョイントとコライダーの距離の方向。衝突している場合、この方向にジョイントを押し出す
|
||||
if (distance < 0)
|
||||
{
|
||||
var direction = -1 * math.normalize(delta);
|
||||
var direction = -1 * math.normalizesafe(delta);
|
||||
newNextTail = nextTail - direction * distance;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace UniGLTF.SpringBoneJobs
|
||||
+ external * scalingFactor; // 外力による移動量
|
||||
|
||||
// 長さをboneLengthに強制
|
||||
nextTail = headTransform.position + math.normalize(nextTail - headTransform.position) * logic.length;
|
||||
nextTail = headTransform.position + math.normalizesafe(nextTail - headTransform.position) * logic.length;
|
||||
|
||||
nextTail = Anglelimit.Apply(logic, joint, parentRotation, head: headTransform.position, nextTail: nextTail);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
@@ -6,19 +6,19 @@ namespace UniGLTF
|
||||
{
|
||||
public static RenderPipelineTypes GetRenderPipelineType()
|
||||
{
|
||||
RenderPipeline currentPipeline = RenderPipelineManager.currentPipeline;
|
||||
RenderPipelineAsset currentRenderPipelineAsset = GraphicsSettings.currentRenderPipeline;
|
||||
|
||||
if (currentPipeline == null)
|
||||
if (currentRenderPipelineAsset == null)
|
||||
{
|
||||
return RenderPipelineTypes.BuiltinRenderPipeline;
|
||||
}
|
||||
|
||||
if (currentPipeline.GetType().Name.Contains("HDRenderPipeline"))
|
||||
if (currentRenderPipelineAsset.GetType().Name.Contains("HDRenderPipeline"))
|
||||
{
|
||||
return RenderPipelineTypes.HighDefinitionRenderPipeline;
|
||||
}
|
||||
|
||||
if (currentPipeline.GetType().Name.Contains("UniversalRenderPipeline"))
|
||||
if (currentRenderPipelineAsset.GetType().Name.Contains("UniversalRenderPipeline"))
|
||||
{
|
||||
return RenderPipelineTypes.UniversalRenderPipeline;
|
||||
}
|
||||
@@ -26,4 +26,4 @@ namespace UniGLTF
|
||||
return RenderPipelineTypes.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,6 +283,138 @@ namespace UniGLTF
|
||||
}
|
||||
}
|
||||
|
||||
private static NativeArray<Vector3> GetMorphTargetVec3(GltfData data, int accessorIndex, string attribute)
|
||||
{
|
||||
if (accessorIndex < 0) return data.NativeArrayManager.CreateNativeArray<Vector3>(0);
|
||||
|
||||
var accessor = data.GLTF.accessors[accessorIndex];
|
||||
if (accessor.type != "VEC3")
|
||||
{
|
||||
throw new ArgumentException($"unknown {attribute} type: {accessor.componentType}:{accessor.type}");
|
||||
}
|
||||
|
||||
static float NormalizeSByte(sbyte v)
|
||||
{
|
||||
// glTF normalized signed integer maps min to -1.0 exactly.
|
||||
return Mathf.Max(v / 127.0f, -1.0f);
|
||||
}
|
||||
|
||||
static float NormalizeShort(short v)
|
||||
{
|
||||
// glTF normalized signed integer maps min to -1.0 exactly.
|
||||
return Mathf.Max(v / 32767.0f, -1.0f);
|
||||
}
|
||||
|
||||
switch (accessor.componentType)
|
||||
{
|
||||
case glComponentType.FLOAT:
|
||||
return data.GetArrayFromAccessor<Vector3>(accessorIndex);
|
||||
|
||||
case glComponentType.BYTE:
|
||||
{
|
||||
var src = data.GetArrayFromAccessor<SByte3>(accessorIndex);
|
||||
var dst = data.NativeArrayManager.CreateNativeArray<Vector3>(src.Length);
|
||||
if (accessor.normalized)
|
||||
{
|
||||
for (int i = 0; i < src.Length; ++i)
|
||||
{
|
||||
var v = src[i];
|
||||
dst[i] = new Vector3(
|
||||
NormalizeSByte(v.x),
|
||||
NormalizeSByte(v.y),
|
||||
NormalizeSByte(v.z));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < src.Length; ++i)
|
||||
{
|
||||
var v = src[i];
|
||||
dst[i] = new Vector3(v.x, v.y, v.z);
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
case glComponentType.UNSIGNED_BYTE:
|
||||
{
|
||||
var src = data.GetArrayFromAccessor<Byte3>(accessorIndex);
|
||||
var dst = data.NativeArrayManager.CreateNativeArray<Vector3>(src.Length);
|
||||
if (accessor.normalized)
|
||||
{
|
||||
const float factor = 1.0f / 255.0f;
|
||||
for (int i = 0; i < src.Length; ++i)
|
||||
{
|
||||
var v = src[i];
|
||||
dst[i] = new Vector3(v.x * factor, v.y * factor, v.z * factor);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < src.Length; ++i)
|
||||
{
|
||||
var v = src[i];
|
||||
dst[i] = new Vector3(v.x, v.y, v.z);
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
case glComponentType.SHORT:
|
||||
{
|
||||
var src = data.GetArrayFromAccessor<Short3>(accessorIndex);
|
||||
var dst = data.NativeArrayManager.CreateNativeArray<Vector3>(src.Length);
|
||||
if (accessor.normalized)
|
||||
{
|
||||
for (int i = 0; i < src.Length; ++i)
|
||||
{
|
||||
var v = src[i];
|
||||
dst[i] = new Vector3(
|
||||
NormalizeShort(v.x),
|
||||
NormalizeShort(v.y),
|
||||
NormalizeShort(v.z));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < src.Length; ++i)
|
||||
{
|
||||
var v = src[i];
|
||||
dst[i] = new Vector3(v.x, v.y, v.z);
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
case glComponentType.UNSIGNED_SHORT:
|
||||
{
|
||||
var src = data.GetArrayFromAccessor<UShort3>(accessorIndex);
|
||||
var dst = data.NativeArrayManager.CreateNativeArray<Vector3>(src.Length);
|
||||
if (accessor.normalized)
|
||||
{
|
||||
const float factor = 1.0f / 65535.0f;
|
||||
for (int i = 0; i < src.Length; ++i)
|
||||
{
|
||||
var v = src[i];
|
||||
dst[i] = new Vector3(v.x * factor, v.y * factor, v.z * factor);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < src.Length; ++i)
|
||||
{
|
||||
var v = src[i];
|
||||
dst[i] = new Vector3(v.x, v.y, v.z);
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new NotImplementedException($"unknown {attribute} type: {accessor.componentType}:{accessor.type}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 各 primitive の attribute の要素が同じでない。=> uv が有るものと無いものが混在するなど
|
||||
/// glTF 的にはありうる。
|
||||
@@ -438,7 +570,7 @@ namespace UniGLTF
|
||||
var blendShape = GetOrCreateBlendShape(i);
|
||||
if (primTarget.POSITION != -1)
|
||||
{
|
||||
var array = data.GetArrayFromAccessor<Vector3>(primTarget.POSITION);
|
||||
var array = GetMorphTargetVec3(data, primTarget.POSITION, "POSITION");
|
||||
if (array.Length != positions.Length)
|
||||
{
|
||||
throw new Exception("different length");
|
||||
@@ -449,7 +581,7 @@ namespace UniGLTF
|
||||
|
||||
if (primTarget.NORMAL != -1)
|
||||
{
|
||||
var array = data.GetArrayFromAccessor<Vector3>(primTarget.NORMAL);
|
||||
var array = GetMorphTargetVec3(data, primTarget.NORMAL, "NORMAL");
|
||||
if (array.Length != positions.Length)
|
||||
{
|
||||
throw new Exception("different length");
|
||||
@@ -460,7 +592,7 @@ namespace UniGLTF
|
||||
|
||||
if (primTarget.TANGENT != -1)
|
||||
{
|
||||
var array = data.GetArrayFromAccessor<Vector3>(primTarget.TANGENT);
|
||||
var array = GetMorphTargetVec3(data, primTarget.TANGENT, "TANGENT");
|
||||
if (array.Length != positions.Length)
|
||||
{
|
||||
throw new Exception("different length");
|
||||
@@ -579,7 +711,7 @@ namespace UniGLTF
|
||||
|
||||
if (hasPosition)
|
||||
{
|
||||
var morphPositions = data.GetArrayFromAccessor<Vector3>(primTarget.POSITION);
|
||||
var morphPositions = GetMorphTargetVec3(data, primTarget.POSITION, "POSITION");
|
||||
blendShape.Positions.Capacity = morphPositions.Length;
|
||||
for (var j = 0; j < positions.Length; ++j)
|
||||
{
|
||||
@@ -589,7 +721,7 @@ namespace UniGLTF
|
||||
|
||||
if (hasNormal)
|
||||
{
|
||||
var morphNormals = data.GetArrayFromAccessor<Vector3>(primTarget.NORMAL);
|
||||
var morphNormals = GetMorphTargetVec3(data, primTarget.NORMAL, "NORMAL");
|
||||
blendShape.Normals.Capacity = morphNormals.Length;
|
||||
for (var j = 0; j < positions.Length; ++j)
|
||||
{
|
||||
@@ -600,7 +732,7 @@ namespace UniGLTF
|
||||
|
||||
if (hasTangent)
|
||||
{
|
||||
var morphTangents = data.GetArrayFromAccessor<Vector3>(primTarget.TANGENT);
|
||||
var morphTangents = GetMorphTargetVec3(data, primTarget.TANGENT, "TANGENT");
|
||||
blendShape.Tangents.Capacity = morphTangents.Length;
|
||||
for (var j = 0; j < positions.Length; ++j)
|
||||
{
|
||||
@@ -639,4 +771,4 @@ namespace UniGLTF
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
@@ -41,28 +40,33 @@ namespace UniGLTF
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task BuildBlendShapeAsync(IAwaitCaller awaitCaller, Mesh mesh, BlendShape blendShape,
|
||||
private static async Task BuildBlendShapeAsync(
|
||||
IAwaitCaller awaitCaller,
|
||||
Mesh mesh,
|
||||
BlendShape blendShape,
|
||||
Vector3[] emptyVertices)
|
||||
{
|
||||
Vector3[] positions = null;
|
||||
Vector3[] normals = null;
|
||||
await awaitCaller.Run(() =>
|
||||
{
|
||||
positions = blendShape.Positions.ToArray();
|
||||
if (blendShape.Normals != null)
|
||||
{
|
||||
normals = blendShape.Normals.ToArray();
|
||||
}
|
||||
positions = blendShape.Positions != null ? blendShape.Positions.ToArray() : Array.Empty<Vector3>();
|
||||
normals = blendShape.Normals != null ? blendShape.Normals.ToArray() : Array.Empty<Vector3>();
|
||||
});
|
||||
|
||||
Profiler.BeginSample("MeshUploader.BuildBlendShapeAsync");
|
||||
var hasPositions = positions.Length == mesh.vertexCount;
|
||||
var hasNormals = normals.Length == mesh.vertexCount;
|
||||
|
||||
if (positions.Length > 0)
|
||||
{
|
||||
if (positions.Length == mesh.vertexCount)
|
||||
if (hasPositions)
|
||||
{
|
||||
var deltaNormals = hasNormals ? normals : null;
|
||||
|
||||
mesh.AddBlendShapeFrame(blendShape.Name, FrameWeight,
|
||||
positions,
|
||||
normals.Length == mesh.vertexCount && normals.Length == positions.Length ? normals : null,
|
||||
deltaNormals,
|
||||
null
|
||||
);
|
||||
}
|
||||
@@ -76,7 +80,7 @@ namespace UniGLTF
|
||||
// add empty blend shape for keep blend shape index
|
||||
mesh.AddBlendShapeFrame(blendShape.Name, FrameWeight,
|
||||
emptyVertices,
|
||||
null,
|
||||
normals.Length == mesh.vertexCount ? normals : null,
|
||||
null
|
||||
);
|
||||
}
|
||||
@@ -132,7 +136,11 @@ namespace UniGLTF
|
||||
var emptyVertices = new Vector3[mesh.vertexCount];
|
||||
foreach (var blendShape in data.BlendShapes)
|
||||
{
|
||||
await BuildBlendShapeAsync(awaitCaller, mesh, blendShape, emptyVertices);
|
||||
await BuildBlendShapeAsync(
|
||||
awaitCaller,
|
||||
mesh,
|
||||
blendShape,
|
||||
emptyVertices);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
25
Packages/UniGLTF/Runtime/UniGLTF/IO/SByte3.cs
Normal file
25
Packages/UniGLTF/Runtime/UniGLTF/IO/SByte3.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable, StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public readonly struct SByte3 : IEquatable<SByte3>
|
||||
{
|
||||
public readonly sbyte x;
|
||||
public readonly sbyte y;
|
||||
public readonly sbyte z;
|
||||
|
||||
public SByte3(sbyte _x, sbyte _y, sbyte _z)
|
||||
{
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
}
|
||||
|
||||
public bool Equals(SByte3 other)
|
||||
{
|
||||
return x == other.x && y == other.y && z == other.z;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Packages/UniGLTF/Runtime/UniGLTF/IO/SByte3.cs.meta
Normal file
2
Packages/UniGLTF/Runtime/UniGLTF/IO/SByte3.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93c772ed657e23c448e9b036d9c9071c
|
||||
25
Packages/UniGLTF/Runtime/UniGLTF/IO/Short3.cs
Normal file
25
Packages/UniGLTF/Runtime/UniGLTF/IO/Short3.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Serializable, StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public readonly struct Short3 : IEquatable<Short3>
|
||||
{
|
||||
public readonly short x;
|
||||
public readonly short y;
|
||||
public readonly short z;
|
||||
|
||||
public Short3(short _x, short _y, short _z)
|
||||
{
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
}
|
||||
|
||||
public bool Equals(Short3 other)
|
||||
{
|
||||
return x == other.x && y == other.y && z == other.z;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Packages/UniGLTF/Runtime/UniGLTF/IO/Short3.cs.meta
Normal file
2
Packages/UniGLTF/Runtime/UniGLTF/IO/Short3.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f74b316e688844c428c7b45dcb38ee54
|
||||
@@ -5,7 +5,7 @@ namespace UniGLTF
|
||||
{
|
||||
public const int MAJOR = 0;
|
||||
public const int MINOR = 131;
|
||||
public const int PATCH = 0;
|
||||
public const string VERSION = "0.131.0";
|
||||
public const int PATCH = 1;
|
||||
public const string VERSION = "0.131.1";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,9 +255,10 @@ namespace UniGLTF
|
||||
}
|
||||
}
|
||||
|
||||
static Dictionary<Transform, IReadOnlyDictionary<Transform, TransformState>> PoseMap = new();
|
||||
static readonly Dictionary<Transform, IReadOnlyDictionary<Transform, TransformState>> PoseMap = new();
|
||||
|
||||
public static IReadOnlyDictionary<Transform, TransformState> SafeGetInitialPose(
|
||||
Transform root, bool useCache = true)
|
||||
Transform root, bool useCache = false)
|
||||
{
|
||||
if (useCache && PoseMap.TryGetValue(root, out var pose))
|
||||
{
|
||||
@@ -278,7 +279,10 @@ namespace UniGLTF
|
||||
}
|
||||
|
||||
// add cache
|
||||
PoseMap.Add(root, pose);
|
||||
if (useCache)
|
||||
{
|
||||
PoseMap.Add(root, pose);
|
||||
}
|
||||
|
||||
return pose;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace UniGLTF
|
||||
{
|
||||
public const int MAJOR = 2;
|
||||
public const int MINOR = 67;
|
||||
public const int PATCH = 0;
|
||||
public const string VERSION = "2.67.0";
|
||||
public const int PATCH = 1;
|
||||
public const string VERSION = "2.67.1";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using UniGLTF;
|
||||
using UniGLTF.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -51,11 +53,19 @@ namespace UniHumanoid
|
||||
x => x);
|
||||
|
||||
/// <summary>
|
||||
/// Avatar を保持する既存の Animatorヒエラルキーの Transform を変更したのちに、
|
||||
/// HumanBone のマッピングを流用して、新たな Avatar を作り直す。
|
||||
/// 古い Avatar は破棄する。
|
||||
/// Recreates an animiator's humanoid avatar.
|
||||
/// The old Avatar is discarded.
|
||||
/// </summary>
|
||||
public static void RebuildHumanAvatar(Animator animator)
|
||||
{
|
||||
var task = RebuildHumanAvatarAsync(animator, new ImmediateCaller());
|
||||
if (!task.IsCompleted)
|
||||
{
|
||||
throw new Exception("task not completed");
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task RebuildHumanAvatarAsync(Animator animator, IAwaitCaller awaitCaller)
|
||||
{
|
||||
if (animator == null)
|
||||
{
|
||||
@@ -73,16 +83,22 @@ namespace UniHumanoid
|
||||
newAvatar.name = "re-created";
|
||||
|
||||
// var newAvatar = LoadHumanoidAvatarFromAnimator(animator);
|
||||
// Animator.avatar を代入したときに副作用でTransformが変更されるのを回避するために削除します。
|
||||
// 1. Delete this to avoid changing Transform as a side effect when assigning Animator.avatar.
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
GameObject.Destroy(animator);
|
||||
|
||||
// https://github.com/vrm-c/UniVRM/pull/2764
|
||||
// Require IAwaitCaller that has NextFrame capability. RuntimeOnlyAwaitCaller etc. not ImmediateCaller.
|
||||
// Else, the following AddComponent call will fail.
|
||||
await awaitCaller.NextFrame();
|
||||
}
|
||||
else
|
||||
{
|
||||
GameObject.DestroyImmediate(animator);
|
||||
}
|
||||
// 新たに AddComponent する
|
||||
|
||||
// 2. Attach a new one
|
||||
target.AddComponent<Animator>().avatar = newAvatar;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,33 +27,36 @@ namespace UniGLTF.Runtime.Utils
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static quaternion FromToRotation(in float3 fromVector, in float3 toVector)
|
||||
{
|
||||
if (math.lengthsq(fromVector) == 0 || math.lengthsq(toVector) == 0)
|
||||
const float epsilon = 1e-6f;
|
||||
const float epsilonSq = epsilon * epsilon;
|
||||
|
||||
if (math.lengthsq(fromVector) < epsilonSq || math.lengthsq(toVector) < epsilonSq)
|
||||
{
|
||||
return quaternion.identity;
|
||||
}
|
||||
|
||||
float3 from = math.normalize(fromVector);
|
||||
float3 to = math.normalize(toVector);
|
||||
float3 from = math.normalizesafe(fromVector);
|
||||
float3 to = math.normalizesafe(toVector);
|
||||
|
||||
var dot = math.dot(from, to);
|
||||
switch(dot)
|
||||
var dot = math.clamp(math.dot(from, to), -1.0f, 1.0f);
|
||||
switch (dot)
|
||||
{
|
||||
case >= 1.0f:
|
||||
return quaternion.identity;
|
||||
case <= -1.0f:
|
||||
case > 1.0f - epsilon:
|
||||
return quaternion.identity;
|
||||
case < -1.0f + epsilon:
|
||||
{
|
||||
var axis = math.cross(from, new float3(1, 0, 0));
|
||||
if (math.lengthsq(axis) < 0.0001f)
|
||||
if (math.lengthsq(axis) < epsilonSq)
|
||||
{
|
||||
axis = math.cross(from, new float3(0, 1, 0));
|
||||
}
|
||||
return quaternion.AxisAngle(math.normalize(axis), math.PI);
|
||||
return quaternion.AxisAngle(math.normalizesafe(axis), math.PI);
|
||||
}
|
||||
default:
|
||||
{
|
||||
var angle = math.acos(dot);
|
||||
var axis = math.cross(from, to);
|
||||
return quaternion.AxisAngle(math.normalize(axis), angle);
|
||||
return quaternion.AxisAngle(math.normalizesafe(axis), angle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,5 +45,66 @@ namespace UniGLTF
|
||||
var expected = Quaternion.FromToRotation(_vector1, _vector2);
|
||||
Assert.That(MathHelper.Approximately(result, expected), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FromToRotationMatchesUnityForStandardCasesTest()
|
||||
{
|
||||
AssertFromToRotationMatchesUnity(new float3(1, 0, 0), new float3(0, 1, 0));
|
||||
AssertFromToRotationMatchesUnity(new float3(0, 1, 0), new float3(0, 0, 1));
|
||||
AssertFromToRotationMatchesUnity(new float3(1, 2, 3), new float3(4, 5, 6));
|
||||
AssertFromToRotationMatchesUnity(new float3(-2, 0.5f, 3), new float3(1, -4, 0.25f));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FromToRotationSameDirectionTest()
|
||||
{
|
||||
AssertFromToRotation(new float3(1, 0, 0), new float3(2, 0, 0));
|
||||
AssertFromToRotation(new float3(1, 2, 3), new float3(2, 4, 6));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FromToRotationOppositeDirectionTest()
|
||||
{
|
||||
AssertFromToRotation(new float3(1, 0, 0), new float3(-1, 0, 0));
|
||||
AssertFromToRotation(new float3(0, 1, 0), new float3(0, -1, 0));
|
||||
AssertFromToRotation(new float3(0, 0, 1), new float3(0, 0, -1));
|
||||
AssertFromToRotation(new float3(1, 2, 3), new float3(-1, -2, -3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FromToRotationNearlyOppositeDirectionTest()
|
||||
{
|
||||
AssertFromToRotation(new float3(1, 0, 0), math.normalize(new float3(-1, 0.0001f, 0)));
|
||||
AssertFromToRotation(new float3(1, 2, 3), math.normalize(new float3(-1.0001f, -2, -3)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FromToRotationZeroVectorTest()
|
||||
{
|
||||
Assert.That(MathHelper.Approximately(MathHelper.FromToRotation(float3.zero, new float3(0, 1, 0)), quaternion.identity), Is.True);
|
||||
Assert.That(MathHelper.Approximately(MathHelper.FromToRotation(new float3(1, 0, 0), float3.zero), quaternion.identity), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FromToRotationTinyVectorTest()
|
||||
{
|
||||
var result = MathHelper.FromToRotation(new float3(1e-12f, 0, 0), new float3(0, 1, 0));
|
||||
Assert.That(MathHelper.Approximately(result, quaternion.identity), Is.True);
|
||||
}
|
||||
|
||||
private static void AssertFromToRotation(float3 from, float3 to)
|
||||
{
|
||||
var result = MathHelper.FromToRotation(from, to);
|
||||
var rotated = math.mul(result, math.normalize(from));
|
||||
var dot = math.dot(math.normalize(rotated), math.normalize(to));
|
||||
Assert.That(dot, Is.GreaterThan(0.9999f));
|
||||
}
|
||||
|
||||
private static void AssertFromToRotationMatchesUnity(float3 from, float3 to)
|
||||
{
|
||||
var result = MathHelper.FromToRotation(from, to);
|
||||
var expected = Quaternion.FromToRotation(from, to);
|
||||
Assert.That(MathHelper.Approximately(result, expected), Is.True);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "com.vrmc.gltf",
|
||||
"version": "0.131.0",
|
||||
"version": "0.131.1",
|
||||
"displayName": "UniGLTF",
|
||||
"description": "GLTF importer and exporter",
|
||||
"unity": "2021.3",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UniGLTF;
|
||||
using Unity.Profiling;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -12,6 +13,8 @@ namespace VRM
|
||||
UnityPath m_prefabPath;
|
||||
List<UnityPath> m_paths = new List<UnityPath>();
|
||||
|
||||
private static ProfilerMarker s_MarkerConvertAndExtractImages = new ProfilerMarker("Convert and Extract Images");
|
||||
|
||||
public ITextureDescriptorGenerator TextureDescriptorGenerator => m_context.TextureDescriptorGenerator;
|
||||
|
||||
public VRMEditorImporterContext(VRMImporterContext context, UnityPath prefabPath)
|
||||
@@ -76,22 +79,27 @@ namespace VRM
|
||||
/// </summary>
|
||||
public void ConvertAndExtractImages(Action<IEnumerable<UnityPath>> onTextureReloaded)
|
||||
{
|
||||
s_MarkerConvertAndExtractImages.Begin();
|
||||
|
||||
//
|
||||
// convert images(metallic roughness, occlusion map)
|
||||
//
|
||||
var task = m_context.LoadMaterialsAsync(new ImmediateCaller());
|
||||
if (!task.IsCompleted)
|
||||
{
|
||||
s_MarkerConvertAndExtractImages.End();
|
||||
throw new Exception();
|
||||
}
|
||||
if (task.IsFaulted)
|
||||
{
|
||||
if (task.Exception is AggregateException ae && ae.InnerExceptions.Count == 1)
|
||||
{
|
||||
s_MarkerConvertAndExtractImages.End();
|
||||
throw ae.InnerException;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_MarkerConvertAndExtractImages.End();
|
||||
throw task.Exception;
|
||||
}
|
||||
}
|
||||
@@ -100,6 +108,7 @@ namespace VRM
|
||||
var task2 = m_context.ReadMetaAsync(new ImmediateCaller());
|
||||
if (!task2.IsCompleted || task2.IsCanceled || task2.IsFaulted)
|
||||
{
|
||||
s_MarkerConvertAndExtractImages.End();
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
@@ -110,6 +119,8 @@ namespace VRM
|
||||
var vrmTextures = new BuiltInVrmMaterialDescriptorGenerator(m_context.VRM);
|
||||
var dirName = $"{m_prefabPath.FileNameWithoutExtension}.Textures";
|
||||
TextureExtractor.ExtractTextures(m_context.Data, m_prefabPath.Parent.Child(dirName), m_context.TextureDescriptorGenerator, subAssets, (_x, _y) => { }, onTextureReloaded);
|
||||
|
||||
s_MarkerConvertAndExtractImages.End();
|
||||
}
|
||||
|
||||
void SaveAsAsset(SubAssetKey _, UnityEngine.Object o)
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UniGLTF;
|
||||
using Unity.Profiling;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -10,6 +11,8 @@ namespace VRM
|
||||
{
|
||||
public class vrmAssetPostprocessor : AssetPostprocessor
|
||||
{
|
||||
private static ProfilerMarker s_MarkerCreatePrefab = new ProfilerMarker("Create Prefab");
|
||||
|
||||
#if !VRM_STOP_ASSETPOSTPROCESSOR
|
||||
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
|
||||
{
|
||||
@@ -63,6 +66,9 @@ namespace VRM
|
||||
return;
|
||||
}
|
||||
|
||||
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
/// <summary>
|
||||
/// これは EditorApplication.delayCall により呼び出される。
|
||||
///
|
||||
@@ -73,24 +79,46 @@ namespace VRM
|
||||
/// <value></value>
|
||||
Action<IEnumerable<UnityPath>> onCompleted = texturePaths =>
|
||||
{
|
||||
s_MarkerCreatePrefab.Begin();
|
||||
|
||||
var map = texturePaths
|
||||
.Select(x => x.LoadAsset<Texture>())
|
||||
.ToDictionary(x => new SubAssetKey(x), x => x as UnityEngine.Object);
|
||||
var settings = new ImporterContextSettings();
|
||||
|
||||
// 確実に Dispose するために敢えて再パースしている
|
||||
using (var data = new GlbFileParser(vrmPath).Parse())
|
||||
using (var context = new VRMImporterContext(new VRMData(data), externalObjectMap: map, settings: settings))
|
||||
try
|
||||
{
|
||||
var editor = new VRMEditorImporterContext(context, prefabPath);
|
||||
foreach (var textureInfo in context.TextureDescriptorGenerator.Get().GetEnumerable())
|
||||
AssetDatabase.StartAssetEditing();
|
||||
|
||||
var settings = new ImporterContextSettings();
|
||||
|
||||
// 確実に Dispose するために敢えて再パースしている
|
||||
using (var data = new GlbFileParser(vrmPath).Parse())
|
||||
using (var context = new VRMImporterContext(new VRMData(data), externalObjectMap: map, settings: settings))
|
||||
{
|
||||
TextureImporterConfigurator.Configure(textureInfo, context.TextureFactory.ExternalTextures);
|
||||
var editor = new VRMEditorImporterContext(context, prefabPath);
|
||||
foreach (var textureInfo in context.TextureDescriptorGenerator.Get().GetEnumerable())
|
||||
{
|
||||
TextureImporterConfigurator.Configure(textureInfo, context.TextureFactory.ExternalTextures);
|
||||
}
|
||||
var loaded = context.Load();
|
||||
editor.SaveAsAsset(loaded);
|
||||
}
|
||||
var loaded = context.Load();
|
||||
editor.SaveAsAsset(loaded);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
AssetDatabase.StopAssetEditing();
|
||||
}
|
||||
|
||||
s_MarkerCreatePrefab.End();
|
||||
|
||||
sw.Stop();
|
||||
|
||||
Debug.Log($"Import complete [importMs={sw.ElapsedMilliseconds}]");
|
||||
};
|
||||
|
||||
using (var data = new GlbFileParser(vrmPath).Parse())
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using UniGLTF;
|
||||
using UniGLTF.MeshUtility;
|
||||
using UniGLTF.Utils;
|
||||
@@ -54,6 +55,15 @@ namespace VRM
|
||||
/// <param name="forceTPose">強制的にT-Pose化するか</param>
|
||||
/// <param name="useCurrentBlendShapeWeight">BlendShape の現状をbakeするか</param>
|
||||
public static void Execute(GameObject go, bool forceTPose, bool useCurrentBlendShapeWeight)
|
||||
{
|
||||
var task = ExecuteAsync(go, forceTPose, useCurrentBlendShapeWeight, new ImmediateCaller());
|
||||
if (!task.IsCompleted)
|
||||
{
|
||||
throw new Exception("task not completed");
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task ExecuteAsync(GameObject go, bool forceTPose, bool useCurrentBlendShapeWeight, IAwaitCaller awaitCaller)
|
||||
{
|
||||
if (forceTPose)
|
||||
{
|
||||
@@ -83,7 +93,7 @@ namespace VRM
|
||||
// 回転とスケールが除去された新しいヒエラルキーからAvatarを作る
|
||||
if (go.TryGetComponent<Animator>(out var animator))
|
||||
{
|
||||
HumanoidLoader.RebuildHumanAvatar(animator);
|
||||
await HumanoidLoader.RebuildHumanAvatarAsync(animator, awaitCaller);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
"GUID:8d76e605759c3f64a957d63ef96ada7c",
|
||||
"GUID:5f875fdc81c40184c8333b9d63c6ddd5",
|
||||
"GUID:f9fe54bb3090be448aa10ac92648a614",
|
||||
"GUID:da3e51d19d51a544fa14d43fee843098",
|
||||
"GUID:27619889b8ba8c24980f49ee34dbb44a",
|
||||
"GUID:0acc523941302664db1f4e527237feb3"
|
||||
"GUID:0acc523941302664db1f4e527237feb3",
|
||||
"GUID:1cd941934d098654fa21a13f28346412"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "com.vrmc.univrm",
|
||||
"version": "0.131.0",
|
||||
"version": "0.131.1",
|
||||
"displayName": "VRM",
|
||||
"description": "VRM importer",
|
||||
"unity": "2021.3",
|
||||
@@ -14,7 +14,7 @@
|
||||
"name": "VRM Consortium"
|
||||
},
|
||||
"dependencies": {
|
||||
"com.vrmc.gltf": "0.131.0",
|
||||
"com.vrmc.gltf": "0.131.1",
|
||||
"com.unity.ugui": "1.0.0"
|
||||
},
|
||||
"samples": [
|
||||
|
||||
@@ -99,6 +99,21 @@ namespace UniVRM10
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Vec3Prop(Rect rect, SerializedProperty prop)
|
||||
{
|
||||
var oldValue = prop.vector3Value;
|
||||
var newValue = EditorGUI.Vector3Field(rect, prop.displayName, oldValue);
|
||||
if (newValue != oldValue)
|
||||
{
|
||||
prop.vector3Value = newValue;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static Rect AdvanceRect(ref float x, float y, float w, float h)
|
||||
{
|
||||
var rect = new Rect(x, y, w, h);
|
||||
|
||||
@@ -110,6 +110,10 @@ namespace UniVRM10
|
||||
int subMeshCount = item.Mesh.subMeshCount;
|
||||
for (int i = 0; i < subMeshCount; i++)
|
||||
{
|
||||
if (item.SkinnedMeshRenderer != null)
|
||||
{
|
||||
item.SkinnedMeshRenderer.BakeMesh(item.Mesh);
|
||||
}
|
||||
m_previewUtility.DrawMesh(item.Mesh,
|
||||
item.Position, item.Rotation,
|
||||
item.Materials[i], i);
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
public class ReorderableNodeTransformBindingList
|
||||
{
|
||||
ReorderableList m_ValuesList;
|
||||
SerializedProperty m_valuesProp;
|
||||
bool m_changed;
|
||||
|
||||
public ReorderableNodeTransformBindingList(SerializedObject serializedObject, PreviewSceneManager previewSceneManager, int height)
|
||||
{
|
||||
m_valuesProp = serializedObject.FindProperty(nameof(VRM10Expression.NodeTransformBindings));
|
||||
m_ValuesList = new ReorderableList(serializedObject, m_valuesProp);
|
||||
m_ValuesList.elementHeight = height * 4;
|
||||
m_ValuesList.drawElementCallback =
|
||||
(rect, index, isActive, isFocused) =>
|
||||
{
|
||||
var element = m_valuesProp.GetArrayElementAtIndex(index);
|
||||
rect.height -= 4;
|
||||
rect.y += 2;
|
||||
if (DrawNodeTransformBinding(rect, element, previewSceneManager, height))
|
||||
{
|
||||
m_changed = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
///
|
||||
/// NodeTransform List のElement描画
|
||||
///
|
||||
static bool DrawNodeTransformBinding(Rect position, SerializedProperty property,
|
||||
PreviewSceneManager scene, int height)
|
||||
{
|
||||
bool changed = false;
|
||||
if (scene != null)
|
||||
{
|
||||
var y = position.y;
|
||||
var rect = new Rect(position.x, y, position.width, height);
|
||||
int pathIndex;
|
||||
if (ExpressionEditorHelper.StringPopup(rect, property.FindPropertyRelative(nameof(NodeTransformBinding.RelativePath)), scene.NodeTransformPathList, out pathIndex))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// T`
|
||||
y += height;
|
||||
rect = new Rect(position.x, y, position.width, height);
|
||||
if (ExpressionEditorHelper.Vec3Prop(rect, property.FindPropertyRelative(nameof(NodeTransformBinding.OffsetTranslation))))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// R
|
||||
y += height;
|
||||
rect = new Rect(position.x, y, position.width, height);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUI.PropertyField(rect, property.FindPropertyRelative(nameof(NodeTransformBinding.OffsetRotation)));
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// S
|
||||
y += height;
|
||||
rect = new Rect(position.x, y, position.width, height);
|
||||
if (ExpressionEditorHelper.Vec3Prop(rect, property.FindPropertyRelative(nameof(NodeTransformBinding.TargetScale))))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
public void SetValues(NodeTransformBinding[] bindings)
|
||||
{
|
||||
m_valuesProp.ClearArray();
|
||||
m_valuesProp.arraySize = bindings.Length;
|
||||
for (int i = 0; i < bindings.Length; ++i)
|
||||
{
|
||||
var item = m_valuesProp.GetArrayElementAtIndex(i);
|
||||
|
||||
var endProperty = item.GetEndProperty();
|
||||
while (item.NextVisible(true))
|
||||
{
|
||||
if (SerializedProperty.EqualContents(item, endProperty))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
switch (item.name)
|
||||
{
|
||||
case nameof(NodeTransformBinding.RelativePath):
|
||||
item.stringValue = bindings[i].RelativePath;
|
||||
break;
|
||||
|
||||
case nameof(NodeTransformBinding.OffsetTranslation):
|
||||
item.vector3Value = bindings[i].OffsetTranslation;
|
||||
break;
|
||||
|
||||
case nameof(NodeTransformBinding.OffsetRotation):
|
||||
item.quaternionValue = bindings[i].OffsetRotation;
|
||||
break;
|
||||
|
||||
case nameof(NodeTransformBinding.TargetScale):
|
||||
item.vector3Value = bindings[i].TargetScale;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public bool Draw(string label)
|
||||
{
|
||||
m_changed = false;
|
||||
m_ValuesList.DoLayoutList();
|
||||
if (GUILayout.Button($"Clear {label}"))
|
||||
{
|
||||
m_changed = true;
|
||||
m_valuesProp.arraySize = 0;
|
||||
}
|
||||
return m_changed;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 186e6dd105c86904497f3ac0dfd61212
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
@@ -28,21 +29,24 @@ namespace UniVRM10
|
||||
ReorderableMorphTargetBindingList m_morphTargetBindings;
|
||||
ReorderableMaterialColorBindingList m_materialColorBindings;
|
||||
ReorderableMaterialUVBindingList m_materialUVBindings;
|
||||
|
||||
ReorderableNodeTransformBindingList m_nodeTransformBindings;
|
||||
#region Editor values
|
||||
|
||||
bool m_changed;
|
||||
|
||||
static int s_Mode;
|
||||
static bool s_MorphTargetFoldout = true;
|
||||
static bool s_OptionFoldout;
|
||||
static bool s_ListFoldout;
|
||||
|
||||
static string[] MODES = new[]{
|
||||
"MorphTarget",
|
||||
"Material Color",
|
||||
"Texture Transform"
|
||||
};
|
||||
enum ListMode
|
||||
{
|
||||
MorphTarget,
|
||||
MaterialColor,
|
||||
TextureTransform,
|
||||
NodeTransform,
|
||||
}
|
||||
static ListMode s_Mode;
|
||||
static string[] MODES = ((ListMode[])Enum.GetValues(typeof(ListMode))).Select(x => x.ToString()).ToArray();
|
||||
|
||||
PreviewMeshItem[] m_items;
|
||||
#endregion
|
||||
@@ -71,6 +75,7 @@ namespace UniVRM10
|
||||
m_morphTargetBindings = new ReorderableMorphTargetBindingList(serializedObject, previewSceneManager, 20);
|
||||
m_materialColorBindings = new ReorderableMaterialColorBindingList(serializedObject, previewSceneManager?.MaterialNames, 20);
|
||||
m_materialUVBindings = new ReorderableMaterialUVBindingList(serializedObject, previewSceneManager?.MaterialNames, 20);
|
||||
m_nodeTransformBindings = new ReorderableNodeTransformBindingList(serializedObject, previewSceneManager, 20);
|
||||
|
||||
m_items = previewSceneManager.EnumRenderItems
|
||||
.Where(x => x.SkinnedMeshRenderer != null)
|
||||
@@ -109,33 +114,39 @@ namespace UniVRM10
|
||||
if (s_ListFoldout)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
s_Mode = GUILayout.Toolbar(s_Mode, MODES);
|
||||
s_Mode = (ListMode)GUILayout.Toolbar((int)s_Mode, MODES);
|
||||
switch (s_Mode)
|
||||
{
|
||||
case 0:
|
||||
// MorphTarget
|
||||
case ListMode.MorphTarget:
|
||||
{
|
||||
if (m_morphTargetBindings.Draw("MorphTarget"))
|
||||
if (m_morphTargetBindings.Draw(s_Mode.ToString()))
|
||||
{
|
||||
m_changed = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Material
|
||||
case ListMode.MaterialColor:
|
||||
{
|
||||
if (m_materialColorBindings.Draw("MaterialColor"))
|
||||
if (m_materialColorBindings.Draw(s_Mode.ToString()))
|
||||
{
|
||||
m_changed = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// TextureTransform
|
||||
case ListMode.TextureTransform:
|
||||
{
|
||||
if (m_materialUVBindings.Draw("TextureTransform"))
|
||||
if (m_materialUVBindings.Draw(s_Mode.ToString()))
|
||||
{
|
||||
m_changed = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ListMode.NodeTransform:
|
||||
{
|
||||
if (m_nodeTransformBindings.Draw(s_Mode.ToString()))
|
||||
{
|
||||
m_changed = true;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace UniVRM10
|
||||
|
||||
private const string Vrm10SpecDir = "vrm-specification/specification";
|
||||
private const string Vrm10FormatGeneratedDir = "Packages/VRM10/Runtime/Format";
|
||||
private const string UniGltfFormatGeneratedDir = "Packages/UniGLTF/Runtime/UniGLTF/Format";
|
||||
|
||||
public static void Run(bool debug)
|
||||
{
|
||||
@@ -48,7 +49,7 @@ namespace UniVRM10
|
||||
// VRMC_hdr_emissiveMultiplier
|
||||
new GenerateInfo(
|
||||
$"{Vrm10SpecDir}/VRMC_materials_hdr_emissiveMultiplier-1.0/schema/VRMC_materials_hdr_emissiveMultiplier.json",
|
||||
"Assets/UniGLTF/Runtime/UniGLTF/Format/ExtensionsAndExtras/EmissiveMultiplier"
|
||||
$"{UniGltfFormatGeneratedDir}/ExtensionsAndExtras/EmissiveMultiplier"
|
||||
),
|
||||
|
||||
// VRMC_vrm
|
||||
@@ -94,6 +95,14 @@ namespace UniVRM10
|
||||
$"{Vrm10SpecDir}/VRMC_springBone_limit-1.0/schema/VRMC_springBone_limit.schema.json",
|
||||
$"{Vrm10FormatGeneratedDir}/SpringBoneLimit"
|
||||
),
|
||||
|
||||
// VRMC_vrm_expressions_node_transform-1.0
|
||||
// (experimental)
|
||||
// https://github.com/ousttrue/vrm-specification/tree/VRMC_vrm_expression_joint
|
||||
new GenerateInfo(
|
||||
$"{Vrm10SpecDir}/VRMC_vrm_expressions_node_transform-1.0/schema/VRMC_vrm_expressions_node_transform.schema.json",
|
||||
$"{Vrm10FormatGeneratedDir}/ExpressionsNodeTransform"
|
||||
),
|
||||
};
|
||||
|
||||
foreach (var arg in args)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UniGLTF.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
@@ -23,9 +24,13 @@ namespace UniVRM10
|
||||
|
||||
MorphTargetBindingMerger m_morphTargetBindingMerger;
|
||||
MaterialValueBindingMerger m_materialValueBindingMerger;
|
||||
NodeTransformBindingMerger m_boneTransformBindingMerger;
|
||||
|
||||
|
||||
public ExpressionMerger(VRM10ObjectExpression expressions, Transform root, bool isPrefabInstance)
|
||||
public ExpressionMerger(VRM10ObjectExpression expressions,
|
||||
Transform root,
|
||||
bool isPrefabInstance,
|
||||
IReadOnlyDictionary<Transform, TransformState> initPose)
|
||||
{
|
||||
m_clipMap = expressions.Clips.ToDictionary(
|
||||
x => expressions.CreateKey(x.Clip),
|
||||
@@ -35,6 +40,7 @@ namespace UniVRM10
|
||||
m_valueMap = new Dictionary<ExpressionKey, float>(ExpressionKey.Comparer);
|
||||
m_morphTargetBindingMerger = new MorphTargetBindingMerger(m_clipMap, root);
|
||||
m_materialValueBindingMerger = new MaterialValueBindingMerger(m_clipMap, root, isPrefabInstance);
|
||||
m_boneTransformBindingMerger = new NodeTransformBindingMerger(m_clipMap, root, initPose);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -50,6 +56,7 @@ namespace UniVRM10
|
||||
|
||||
m_morphTargetBindingMerger.Apply();
|
||||
m_materialValueBindingMerger.Apply();
|
||||
m_boneTransformBindingMerger.Apply();
|
||||
}
|
||||
|
||||
private void AccumulateValue(ExpressionKey key, float value)
|
||||
@@ -69,6 +76,7 @@ namespace UniVRM10
|
||||
|
||||
m_morphTargetBindingMerger.AccumulateValue(key, value);
|
||||
m_materialValueBindingMerger.AccumulateValue(clip, value);
|
||||
m_boneTransformBindingMerger.AccumulateValue(key, value);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using UniGLTF.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
[Serializable]
|
||||
public struct NodeTransformBinding
|
||||
{
|
||||
public string RelativePath;
|
||||
|
||||
/// <summary>
|
||||
/// t = init_t + offset_t * weight
|
||||
/// disable if offset_t = (0, 0, 0)
|
||||
/// </summary>
|
||||
public Vector3 OffsetTranslation;
|
||||
|
||||
/// <summary>
|
||||
/// r = slerp(init_t, init_t * offset r, weight)
|
||||
/// disable if rotation_t = (0, 0, 0, 1)
|
||||
/// </summary>
|
||||
public Quaternion OffsetRotation;
|
||||
|
||||
/// <summary>
|
||||
/// s = lerp(init_s, blend_s, weight)
|
||||
/// disalbe if blend_s = init_s. maybe(1, 1, 1)
|
||||
/// </summary>
|
||||
public Vector3 TargetScale;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="weight">0 to 1.0</param>
|
||||
public NodeTransformBinding(string path, in Vector3 t, in Quaternion r, in Vector3 s)
|
||||
{
|
||||
RelativePath = path;
|
||||
OffsetTranslation = t;
|
||||
OffsetRotation = r;
|
||||
TargetScale = s;
|
||||
}
|
||||
|
||||
public void Apply(Transform node, in TransformState init, float weight)
|
||||
{
|
||||
node.SetLocalPositionAndRotation(
|
||||
init.LocalPosition + this.OffsetTranslation * weight,
|
||||
Quaternion.Slerp(init.LocalRotation, init.LocalRotation * this.OffsetRotation, weight)
|
||||
);
|
||||
if (this.TargetScale != Vector3.zero)
|
||||
{
|
||||
node.localScale = Vector3.Lerp(init.LocalScale, this.TargetScale, weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd660f7a77373234c85064f97150eef6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.Collections.Generic;
|
||||
using UniGLTF.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
internal sealed class NodeTransformBindingMerger
|
||||
{
|
||||
IReadOnlyDictionary<ExpressionKey, VRM10Expression> _clipMap;
|
||||
Transform _root;
|
||||
IReadOnlyDictionary<Transform, TransformState> _initPose;
|
||||
Dictionary<ExpressionKey, float> _weightMap = new();
|
||||
|
||||
public NodeTransformBindingMerger(
|
||||
IReadOnlyDictionary<ExpressionKey, VRM10Expression> clipMap,
|
||||
Transform root,
|
||||
IReadOnlyDictionary<Transform, TransformState> initPose)
|
||||
{
|
||||
_clipMap = clipMap;
|
||||
_root = root;
|
||||
_initPose = initPose;
|
||||
}
|
||||
|
||||
public void AccumulateValue(ExpressionKey key, float value)
|
||||
{
|
||||
_weightMap[key] = value;
|
||||
}
|
||||
|
||||
public void Apply()
|
||||
{
|
||||
foreach (var (k, weight) in _weightMap)
|
||||
{
|
||||
if (_clipMap.TryGetValue(k, out var clip))
|
||||
{
|
||||
foreach (var b in clip.NodeTransformBindings)
|
||||
{
|
||||
var node = _root.GetFromPath(b.RelativePath);
|
||||
if (node != null)
|
||||
{
|
||||
if (_initPose.TryGetValue(node, out var init))
|
||||
{
|
||||
b.Apply(node, init, weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe2bf5e71647b0f4d93ca6c22bb9fb7f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -123,7 +123,9 @@ namespace UniVRM10
|
||||
{
|
||||
return new PreviewMeshItem(t.RelativePathFrom(root), t, skinnedMeshRenderer.sharedMaterials)
|
||||
{
|
||||
Mesh = skinnedMeshRenderer.sharedMesh,
|
||||
SkinnedMeshRenderer = skinnedMeshRenderer,
|
||||
Mesh = new Mesh(), // for bake
|
||||
BlendShapeNames = new string[]{},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using UniGLTF;
|
||||
using UniGLTF.Utils;
|
||||
|
||||
|
||||
namespace UniVRM10
|
||||
@@ -16,6 +17,8 @@ namespace UniVRM10
|
||||
|
||||
public bool hasError;
|
||||
|
||||
private IReadOnlyDictionary<Transform, TransformState> m_defaultTransformStates;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static PreviewSceneManager GetOrCreate(GameObject prefab)
|
||||
{
|
||||
@@ -85,7 +88,7 @@ namespace UniVRM10
|
||||
private void Initialize(GameObject prefab)
|
||||
{
|
||||
hasError = false;
|
||||
|
||||
|
||||
Prefab = prefab;
|
||||
|
||||
var materialNames = new List<string>();
|
||||
@@ -104,14 +107,14 @@ namespace UniVRM10
|
||||
{
|
||||
dst = new Material(src);
|
||||
map.Add(src, dst);
|
||||
|
||||
|
||||
if (!PreviewMaterialUtil.TryCreateForPreview(dst, out var previewMaterialItem))
|
||||
{
|
||||
hasError = true;
|
||||
// Return cloned material for preview
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
m_materialMap.Add(src.name, previewMaterialItem);
|
||||
|
||||
materialNames.Add(src.name);
|
||||
@@ -119,6 +122,10 @@ namespace UniVRM10
|
||||
return dst;
|
||||
};
|
||||
|
||||
// initPose for nodeTransform
|
||||
m_defaultTransformStates = transform.GetComponentsInChildren<Transform>()
|
||||
.ToDictionary(tf => tf, tf => new TransformState(tf));
|
||||
|
||||
m_meshes = transform.Traverse()
|
||||
.Select(x => PreviewMeshItem.Create(x, transform, getOrCreateMaterial))
|
||||
.Where(x => x != null)
|
||||
@@ -136,8 +143,13 @@ namespace UniVRM10
|
||||
.Where(x => x.SkinnedMeshRenderer != null)
|
||||
.Select(x => x.Path)
|
||||
.ToArray();
|
||||
m_nodeTransformPathList = transform.GetComponentsInChildren<Transform>()
|
||||
.Select(x => x.RelativePathFrom(transform))
|
||||
.Where(x => x != null)
|
||||
.ToArray()
|
||||
;
|
||||
|
||||
if(TryGetComponent<Animator>(out var animator))
|
||||
if (TryGetComponent<Animator>(out var animator))
|
||||
{
|
||||
var head = animator.GetBoneTransform(HumanBodyBones.Head);
|
||||
if (head != null)
|
||||
@@ -184,6 +196,12 @@ namespace UniVRM10
|
||||
get { return m_skinnedMeshRendererPathList; }
|
||||
}
|
||||
|
||||
string[] m_nodeTransformPathList;
|
||||
public string[] NodeTransformPathList
|
||||
{
|
||||
get { return m_nodeTransformPathList; }
|
||||
}
|
||||
|
||||
public string[] GetBlendShapeNames(int blendShapeMeshIndex)
|
||||
{
|
||||
if (blendShapeMeshIndex >= 0 && blendShapeMeshIndex < m_blendShapeMeshes.Length)
|
||||
@@ -228,19 +246,28 @@ namespace UniVRM10
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// bake NodeTransform
|
||||
//
|
||||
foreach (var nodeTransform in bake.NodeTransformBindings)
|
||||
{
|
||||
var node = transform.GetFromPath(nodeTransform.RelativePath);
|
||||
if (m_defaultTransformStates.TryGetValue(node, out var init))
|
||||
{
|
||||
nodeTransform.Apply(node, init, weight);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Bake Expression
|
||||
//
|
||||
m_bounds = default(Bounds);
|
||||
if (m_meshes != null)
|
||||
{
|
||||
if (bake != null)
|
||||
foreach (var x in m_meshes)
|
||||
{
|
||||
foreach (var x in m_meshes)
|
||||
{
|
||||
x.Bake(bake.MorphTargetBindings, weight);
|
||||
m_bounds.Expand(x.Mesh.bounds.size);
|
||||
}
|
||||
x.Bake(bake.MorphTargetBindings, weight);
|
||||
m_bounds.Expand(x.Mesh.bounds.size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,5 +46,11 @@ namespace UniVRM10
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public UniGLTF.Extensions.VRMC_vrm.ExpressionOverrideType OverrideMouth;
|
||||
|
||||
/// <summary>
|
||||
/// from UniVRM-132.0. experimental
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
public NodeTransformBinding[] NodeTransformBindings = new NodeTransformBinding[] { };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace UniVRM10
|
||||
}
|
||||
Constraints = instance.GetComponentsInChildren<IVrm10Constraint>();
|
||||
LookAt = new Vrm10RuntimeLookAt(instance, instance.Humanoid, ControlRig);
|
||||
Expression = new Vrm10RuntimeExpression(instance, LookAt.EyeDirectionApplicable, isPrefabInstance);
|
||||
Expression = new Vrm10RuntimeExpression(instance, LookAt.EyeDirectionApplicable, isPrefabInstance, initPose);
|
||||
SpringBone = springBoneRuntime;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UniGLTF.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
{
|
||||
@@ -23,9 +25,13 @@ namespace UniVRM10
|
||||
public float LookAtOverrideRate { get; private set; }
|
||||
public float MouthOverrideRate { get; private set; }
|
||||
|
||||
internal Vrm10RuntimeExpression(Vrm10Instance target, ILookAtEyeDirectionApplicable eyeDirectionApplicable, bool isPrefabInstance)
|
||||
internal Vrm10RuntimeExpression(Vrm10Instance target,
|
||||
ILookAtEyeDirectionApplicable eyeDirectionApplicable,
|
||||
bool isPrefabInstance,
|
||||
IReadOnlyDictionary<Transform, TransformState> initPose
|
||||
)
|
||||
{
|
||||
_merger = new ExpressionMerger(target.Vrm.Expression, target.transform, isPrefabInstance);
|
||||
_merger = new ExpressionMerger(target.Vrm.Expression, target.transform, isPrefabInstance, initPose);
|
||||
_keys = target.Vrm.Expression.Clips
|
||||
.Select(x => target.Vrm.Expression.CreateKey(x.Clip))
|
||||
.ToList();
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d80842db26fe76645bf195c10b9c6bf7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,145 @@
|
||||
// This file is generated from JsonSchema. Don't modify this source code.
|
||||
using UniJSON;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniGLTF.Extensions.VRMC_vrm_expressions_node_transform {
|
||||
|
||||
public static class GltfDeserializer
|
||||
{
|
||||
public static readonly Utf8String ExtensionNameUtf8 = Utf8String.From(VRMC_vrm_expressions_node_transform.ExtensionName);
|
||||
|
||||
public static bool TryGet(UniGLTF.glTFExtension src, out VRMC_vrm_expressions_node_transform extension)
|
||||
{
|
||||
if(src is UniGLTF.glTFExtensionImport extensions)
|
||||
{
|
||||
foreach(var kv in extensions.ObjectItems())
|
||||
{
|
||||
if(kv.Key.GetUtf8String() == ExtensionNameUtf8)
|
||||
{
|
||||
extension = Deserialize(kv.Value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static VRMC_vrm_expressions_node_transform Deserialize(JsonNode parsed)
|
||||
{
|
||||
var value = new VRMC_vrm_expressions_node_transform();
|
||||
|
||||
foreach(var kv in parsed.ObjectItems())
|
||||
{
|
||||
var key = kv.Key.GetString();
|
||||
|
||||
if(key=="extensions"){
|
||||
value.Extensions = new glTFExtensionImport(kv.Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="extras"){
|
||||
value.Extras = new glTFExtensionImport(kv.Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="nodeTransformBinds"){
|
||||
value.NodeTransformBinds = Deserialize_NodeTransformBinds(kv.Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static List<NodeTransformBind> Deserialize_NodeTransformBinds(JsonNode parsed)
|
||||
{
|
||||
var value = new List<NodeTransformBind>();
|
||||
foreach(var x in parsed.ArrayItems())
|
||||
{
|
||||
value.Add(Deserialize_NodeTransformBinds_ITEM(x));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static NodeTransformBind Deserialize_NodeTransformBinds_ITEM(JsonNode parsed)
|
||||
{
|
||||
var value = new NodeTransformBind();
|
||||
|
||||
foreach(var kv in parsed.ObjectItems())
|
||||
{
|
||||
var key = kv.Key.GetString();
|
||||
|
||||
if(key=="extensions"){
|
||||
value.Extensions = new glTFExtensionImport(kv.Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="extras"){
|
||||
value.Extras = new glTFExtensionImport(kv.Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="node"){
|
||||
value.Node = kv.Value.GetInt32();
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="rotation"){
|
||||
value.Rotation = __nodeTransformBinds_ITEM_Deserialize_Rotation(kv.Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="scale"){
|
||||
value.Scale = __nodeTransformBinds_ITEM_Deserialize_Scale(kv.Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key=="translation"){
|
||||
value.Translation = __nodeTransformBinds_ITEM_Deserialize_Translation(kv.Value);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static float[] __nodeTransformBinds_ITEM_Deserialize_Rotation(JsonNode parsed)
|
||||
{
|
||||
var value = new float[parsed.GetArrayCount()];
|
||||
int i=0;
|
||||
foreach(var x in parsed.ArrayItems())
|
||||
{
|
||||
value[i++] = x.GetSingle();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static float[] __nodeTransformBinds_ITEM_Deserialize_Scale(JsonNode parsed)
|
||||
{
|
||||
var value = new float[parsed.GetArrayCount()];
|
||||
int i=0;
|
||||
foreach(var x in parsed.ArrayItems())
|
||||
{
|
||||
value[i++] = x.GetSingle();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static float[] __nodeTransformBinds_ITEM_Deserialize_Translation(JsonNode parsed)
|
||||
{
|
||||
var value = new float[parsed.GetArrayCount()];
|
||||
int i=0;
|
||||
foreach(var x in parsed.ArrayItems())
|
||||
{
|
||||
value[i++] = x.GetSingle();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
} // GltfDeserializer
|
||||
} // UniGLTF
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a0544899292fe54e961d98e2f7d755c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,43 @@
|
||||
// This file is generated from JsonSchema. Don't modify this source code.
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace UniGLTF.Extensions.VRMC_vrm_expressions_node_transform
|
||||
{
|
||||
|
||||
public class NodeTransformBind
|
||||
{
|
||||
// Dictionary object with extension-specific objects.
|
||||
public object Extensions;
|
||||
|
||||
// Application-specific data.
|
||||
public object Extras;
|
||||
|
||||
// The node index.
|
||||
public int? Node;
|
||||
|
||||
// The node's unit quaternion rotation in the order (x, y, z, w), where w is the scalar.
|
||||
public float[] Rotation;
|
||||
|
||||
// The node's non-uniform scale, given as the scaling factors along the x, y, and z axes.
|
||||
public float[] Scale;
|
||||
|
||||
// The node's translation along the x, y, and z axes.
|
||||
public float[] Translation;
|
||||
}
|
||||
|
||||
public class VRMC_vrm_expressions_node_transform
|
||||
{
|
||||
public const string ExtensionName = "VRMC_vrm_expressions_node_transform";
|
||||
|
||||
// Dictionary object with extension-specific objects.
|
||||
public object Extensions;
|
||||
|
||||
// Application-specific data.
|
||||
public object Extras;
|
||||
|
||||
// Specify a node transform
|
||||
public List<NodeTransformBind> NodeTransformBinds;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f6d0369358084249b383bea969b16a6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,141 @@
|
||||
// This file is generated from JsonSchema. Don't modify this source code.
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UniJSON;
|
||||
|
||||
namespace UniGLTF.Extensions.VRMC_vrm_expressions_node_transform {
|
||||
|
||||
static public class GltfSerializer
|
||||
{
|
||||
|
||||
public static void SerializeTo(ref UniGLTF.glTFExtension dst, VRMC_vrm_expressions_node_transform extension)
|
||||
{
|
||||
if (dst is glTFExtensionImport)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
if (!(dst is glTFExtensionExport extensions))
|
||||
{
|
||||
extensions = new glTFExtensionExport();
|
||||
dst = extensions;
|
||||
}
|
||||
|
||||
var f = new JsonFormatter();
|
||||
Serialize(f, extension);
|
||||
extensions.Add(VRMC_vrm_expressions_node_transform.ExtensionName, f.GetStoreBytes());
|
||||
}
|
||||
|
||||
|
||||
public static void Serialize(JsonFormatter f, VRMC_vrm_expressions_node_transform value)
|
||||
{
|
||||
f.BeginMap();
|
||||
|
||||
|
||||
if(value.Extensions!=null){
|
||||
f.Key("extensions");
|
||||
(value.Extensions as glTFExtension).Serialize(f);
|
||||
}
|
||||
|
||||
if(value.Extras!=null){
|
||||
f.Key("extras");
|
||||
(value.Extras as glTFExtension).Serialize(f);
|
||||
}
|
||||
|
||||
if(value.NodeTransformBinds!=null&&value.NodeTransformBinds.Count()>=1){
|
||||
f.Key("nodeTransformBinds");
|
||||
Serialize_NodeTransformBinds(f, value.NodeTransformBinds);
|
||||
}
|
||||
|
||||
f.EndMap();
|
||||
}
|
||||
|
||||
public static void Serialize_NodeTransformBinds(JsonFormatter f, List<NodeTransformBind> value)
|
||||
{
|
||||
f.BeginList();
|
||||
|
||||
foreach(var item in value)
|
||||
{
|
||||
Serialize_NodeTransformBinds_ITEM(f, item);
|
||||
|
||||
}
|
||||
f.EndList();
|
||||
}
|
||||
|
||||
public static void Serialize_NodeTransformBinds_ITEM(JsonFormatter f, NodeTransformBind value)
|
||||
{
|
||||
f.BeginMap();
|
||||
|
||||
|
||||
if(value.Extensions!=null){
|
||||
f.Key("extensions");
|
||||
(value.Extensions as glTFExtension).Serialize(f);
|
||||
}
|
||||
|
||||
if(value.Extras!=null){
|
||||
f.Key("extras");
|
||||
(value.Extras as glTFExtension).Serialize(f);
|
||||
}
|
||||
|
||||
if(value.Node.HasValue){
|
||||
f.Key("node");
|
||||
f.Value(value.Node.GetValueOrDefault());
|
||||
}
|
||||
|
||||
if(value.Rotation!=null&&value.Rotation.Count()>=4){
|
||||
f.Key("rotation");
|
||||
__nodeTransformBinds_ITEM_Serialize_Rotation(f, value.Rotation);
|
||||
}
|
||||
|
||||
if(value.Scale!=null&&value.Scale.Count()>=3){
|
||||
f.Key("scale");
|
||||
__nodeTransformBinds_ITEM_Serialize_Scale(f, value.Scale);
|
||||
}
|
||||
|
||||
if(value.Translation!=null&&value.Translation.Count()>=3){
|
||||
f.Key("translation");
|
||||
__nodeTransformBinds_ITEM_Serialize_Translation(f, value.Translation);
|
||||
}
|
||||
|
||||
f.EndMap();
|
||||
}
|
||||
|
||||
public static void __nodeTransformBinds_ITEM_Serialize_Rotation(JsonFormatter f, float[] value)
|
||||
{
|
||||
f.BeginList();
|
||||
|
||||
foreach(var item in value)
|
||||
{
|
||||
f.Value(item);
|
||||
|
||||
}
|
||||
f.EndList();
|
||||
}
|
||||
|
||||
public static void __nodeTransformBinds_ITEM_Serialize_Scale(JsonFormatter f, float[] value)
|
||||
{
|
||||
f.BeginList();
|
||||
|
||||
foreach(var item in value)
|
||||
{
|
||||
f.Value(item);
|
||||
|
||||
}
|
||||
f.EndList();
|
||||
}
|
||||
|
||||
public static void __nodeTransformBinds_ITEM_Serialize_Translation(JsonFormatter f, float[] value)
|
||||
{
|
||||
f.BeginList();
|
||||
|
||||
foreach(var item in value)
|
||||
{
|
||||
f.Value(item);
|
||||
|
||||
}
|
||||
f.EndList();
|
||||
}
|
||||
|
||||
} // class
|
||||
} // namespace
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16a49328d069d9f47840c104597af4a4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -44,10 +44,10 @@ namespace UniGLTF.Extensions.VRMC_springBone_limit
|
||||
// Application-specific data.
|
||||
public object Extras;
|
||||
|
||||
// The phi angle of the spherical limit in radians. If the phi angle is set to π or greater, the angle will be interpreted as π by the implementation.
|
||||
// The pitch angle of the spherical limit in radians. If the pitch angle is set to π or greater, the angle will be interpreted as π by the implementation.
|
||||
public float? Pitch;
|
||||
|
||||
// The theta angle of the spherical limit in radians. If the theta angle is set to π/2 or greater, the angle will be interpreted as π/2 by the implementation.
|
||||
// The yaw angle of the spherical limit in radians. If the yaw angle is set to π/2 or greater, the angle will be interpreted as π/2 by the implementation.
|
||||
public float? Yaw;
|
||||
|
||||
// The rotation from the default orientation of the spherical limit. The rotation is represented as a quaternion (x, y, z, w), where w is the scalar.
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using UniGLTF;
|
||||
using UniGLTF.Extensions.VRMC_vrm;
|
||||
using UniGLTF.Extensions.VRMC_vrm_expressions_node_transform;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10
|
||||
@@ -60,7 +61,15 @@ namespace UniVRM10
|
||||
var binding = default(UniVRM10.MaterialUVBinding?);
|
||||
if (material != null)
|
||||
{
|
||||
var (scale, offset) = UniGLTF.TextureTransform.VerticalFlipScaleOffset(new Vector2(bind.Scale[0], bind.Scale[1]), new Vector2(bind.Offset[0], bind.Offset[1]));
|
||||
// Default values: scale [1, 1], offset [0, 0]
|
||||
Vector2 scaleVec = bind.Scale != null && bind.Scale.Length >= 2
|
||||
? new Vector2(bind.Scale[0], bind.Scale[1])
|
||||
: new Vector2(1.0f, 1.0f);
|
||||
Vector2 offsetVec = bind.Offset != null && bind.Offset.Length >= 2
|
||||
? new Vector2(bind.Offset[0], bind.Offset[1])
|
||||
: new Vector2(0.0f, 0.0f);
|
||||
|
||||
var (scale, offset) = UniGLTF.TextureTransform.VerticalFlipScaleOffset(scaleVec, offsetVec);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -78,5 +87,29 @@ namespace UniVRM10
|
||||
}
|
||||
return binding;
|
||||
}
|
||||
|
||||
public static NodeTransformBinding? Build10(this NodeTransformBind bind, GameObject root, Vrm10Importer importer)
|
||||
{
|
||||
if (bind.Node.TryGetValidIndex(importer.Nodes.Count, out var nodeIndex))
|
||||
{
|
||||
var node = importer.Nodes[nodeIndex];
|
||||
var relativePath = node.RelativePathFrom(root.transform);
|
||||
|
||||
var t = bind.Translation != null && bind.Translation.Length >= 3
|
||||
? new Vector3(bind.Translation[0], bind.Translation[1], bind.Translation[2])
|
||||
: Vector3.zero;
|
||||
var r = bind.Rotation != null && bind.Rotation.Length >= 4
|
||||
? new Quaternion(bind.Rotation[0], bind.Rotation[1], bind.Rotation[2], bind.Rotation[3])
|
||||
: Quaternion.identity;
|
||||
var s = bind.Scale != null && bind.Scale.Length >= 3
|
||||
? new Vector3(bind.Scale[0], bind.Scale[1], bind.Scale[2])
|
||||
: node.transform.localScale;
|
||||
return new NodeTransformBinding(relativePath, t, r, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace UniVRM10
|
||||
// use material.name, because material name may renamed in GltfParser.
|
||||
matDesc = new MaterialDescriptor(
|
||||
m.name,
|
||||
Shader.Find(MToon10Meta.UnityShaderName),
|
||||
Shader,
|
||||
null,
|
||||
Vrm10MToonTextureImporter.EnumerateAllTextures(data, m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.Item2.Item2),
|
||||
TryGetAllFloats(m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.value),
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace UniVRM10
|
||||
// use material.name, because material name may renamed in GltfParser.
|
||||
matDesc = new MaterialDescriptor(
|
||||
m.name,
|
||||
Shader.Find(MToon10Meta.UnityUrpShaderName),
|
||||
Shader,
|
||||
null,
|
||||
Vrm10MToonTextureImporter.EnumerateAllTextures(data, m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.Item2.Item2),
|
||||
BuiltInVrm10MToonMaterialImporter.TryGetAllFloats(m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.value),
|
||||
|
||||
@@ -131,16 +131,16 @@ namespace UniVRM10
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// revere X
|
||||
/// reverse X
|
||||
/// </summary>
|
||||
/// <param name="v"></param>
|
||||
/// <returns></returns>
|
||||
static float[] ReverseX(Vector3 v)
|
||||
static float[] ReverseXToFloat3(Vector3 v)
|
||||
{
|
||||
return new float[] { -v.x, v.y, v.z };
|
||||
}
|
||||
|
||||
static float[] ReverseX(Quaternion q)
|
||||
static float[] ReverseXToFloat4(Quaternion q)
|
||||
{
|
||||
q = UniGLTF.Axes.X.Create().InvertQuaternion(q);
|
||||
return new float[] { q.x, q.y, q.z, q.w };
|
||||
@@ -330,7 +330,7 @@ namespace UniVRM10
|
||||
shape.Sphere = new UniGLTF.Extensions.VRMC_springBone.ColliderShapeSphere
|
||||
{
|
||||
Radius = z.Radius,
|
||||
Offset = ReverseX(z.Offset),
|
||||
Offset = ReverseXToFloat3(z.Offset),
|
||||
};
|
||||
break;
|
||||
}
|
||||
@@ -340,8 +340,8 @@ namespace UniVRM10
|
||||
shape.Capsule = new UniGLTF.Extensions.VRMC_springBone.ColliderShapeCapsule
|
||||
{
|
||||
Radius = z.Radius,
|
||||
Offset = ReverseX(z.Offset),
|
||||
Tail = ReverseX(z.Tail),
|
||||
Offset = ReverseXToFloat3(z.Offset),
|
||||
Tail = ReverseXToFloat3(z.Tail),
|
||||
};
|
||||
break;
|
||||
}
|
||||
@@ -352,7 +352,7 @@ namespace UniVRM10
|
||||
shape.Sphere = new UniGLTF.Extensions.VRMC_springBone.ColliderShapeSphere
|
||||
{
|
||||
Radius = 1000.0f,
|
||||
Offset = ReverseX(z.Offset - z.TailOrNormal.normalized * DISTANCE),
|
||||
Offset = ReverseXToFloat3(z.Offset - z.TailOrNormal.normalized * DISTANCE),
|
||||
};
|
||||
break;
|
||||
}
|
||||
@@ -382,7 +382,7 @@ namespace UniVRM10
|
||||
shape.Sphere = new UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapeSphere
|
||||
{
|
||||
Radius = z.Radius,
|
||||
Offset = ReverseX(z.Offset),
|
||||
Offset = ReverseXToFloat3(z.Offset),
|
||||
};
|
||||
break;
|
||||
}
|
||||
@@ -392,8 +392,8 @@ namespace UniVRM10
|
||||
shape.Capsule = new UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapeCapsule
|
||||
{
|
||||
Radius = z.Radius,
|
||||
Offset = ReverseX(z.Offset),
|
||||
Tail = ReverseX(z.Tail),
|
||||
Offset = ReverseXToFloat3(z.Offset),
|
||||
Tail = ReverseXToFloat3(z.Tail),
|
||||
};
|
||||
break;
|
||||
}
|
||||
@@ -403,7 +403,7 @@ namespace UniVRM10
|
||||
shape.Sphere = new UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapeSphere
|
||||
{
|
||||
Radius = z.Radius,
|
||||
Offset = ReverseX(z.Offset),
|
||||
Offset = ReverseXToFloat3(z.Offset),
|
||||
Inside = true,
|
||||
};
|
||||
break;
|
||||
@@ -414,8 +414,8 @@ namespace UniVRM10
|
||||
shape.Capsule = new UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapeCapsule
|
||||
{
|
||||
Radius = z.Radius,
|
||||
Offset = ReverseX(z.Offset),
|
||||
Tail = ReverseX(z.Tail),
|
||||
Offset = ReverseXToFloat3(z.Offset),
|
||||
Tail = ReverseXToFloat3(z.Tail),
|
||||
Inside = true,
|
||||
};
|
||||
break;
|
||||
@@ -425,8 +425,8 @@ namespace UniVRM10
|
||||
{
|
||||
shape.Plane = new UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapePlane
|
||||
{
|
||||
Offset = ReverseX(z.Offset),
|
||||
Normal = ReverseX(z.Normal),
|
||||
Offset = ReverseXToFloat3(z.Offset),
|
||||
Normal = ReverseXToFloat3(z.Normal),
|
||||
};
|
||||
break;
|
||||
}
|
||||
@@ -447,7 +447,7 @@ namespace UniVRM10
|
||||
HitRadius = y.m_jointRadius,
|
||||
DragForce = y.m_dragForce,
|
||||
Stiffness = y.m_stiffnessForce,
|
||||
GravityDir = ReverseX(y.m_gravityDir),
|
||||
GravityDir = ReverseXToFloat3(y.m_gravityDir),
|
||||
GravityPower = y.m_gravityPower,
|
||||
};
|
||||
|
||||
@@ -461,7 +461,7 @@ namespace UniVRM10
|
||||
{
|
||||
Cone = new UniGLTF.Extensions.VRMC_springBone_limit.ConeLimit
|
||||
{
|
||||
Rotation = ReverseX(y.m_limitSpaceOffset),
|
||||
Rotation = ReverseXToFloat4(y.m_limitSpaceOffset),
|
||||
Angle = y.m_pitch,
|
||||
}
|
||||
}
|
||||
@@ -479,7 +479,7 @@ namespace UniVRM10
|
||||
{
|
||||
Hinge = new UniGLTF.Extensions.VRMC_springBone_limit.HingeLimit
|
||||
{
|
||||
Rotation = ReverseX(y.m_limitSpaceOffset),
|
||||
Rotation = ReverseXToFloat4(y.m_limitSpaceOffset),
|
||||
Angle = y.m_pitch,
|
||||
}
|
||||
}
|
||||
@@ -497,7 +497,7 @@ namespace UniVRM10
|
||||
{
|
||||
Spherical = new UniGLTF.Extensions.VRMC_springBone_limit.SphericalLimit
|
||||
{
|
||||
Rotation = ReverseX(y.m_limitSpaceOffset),
|
||||
Rotation = ReverseXToFloat4(y.m_limitSpaceOffset),
|
||||
Pitch = y.m_pitch,
|
||||
Yaw = y.m_yaw,
|
||||
}
|
||||
@@ -779,6 +779,19 @@ namespace UniVRM10
|
||||
};
|
||||
}
|
||||
|
||||
static UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.NodeTransformBind ExportNodeTransformBinding(NodeTransformBinding binding, Func<string, int> getIndex)
|
||||
{
|
||||
var translation = ReverseXToFloat3(binding.OffsetTranslation);
|
||||
var rotation = ReverseXToFloat4(binding.OffsetRotation);
|
||||
return new UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.NodeTransformBind
|
||||
{
|
||||
Node = getIndex(binding.RelativePath),
|
||||
Translation = translation,
|
||||
Rotation = rotation,
|
||||
Scale = new float[] { binding.TargetScale.x, binding.TargetScale.y, binding.TargetScale.z },
|
||||
};
|
||||
}
|
||||
|
||||
static UniGLTF.Extensions.VRMC_vrm.Expression ExportExpression(VRM10Expression e, Vrm10Instance vrmController, Model model, ModelExporter converter)
|
||||
{
|
||||
if (e == null)
|
||||
@@ -786,7 +799,7 @@ namespace UniVRM10
|
||||
return null;
|
||||
}
|
||||
|
||||
Func<string, int> getIndexFromRelativePath = relativePath =>
|
||||
Func<string, int> getRendererNodeIndexFromRelativePath = relativePath =>
|
||||
{
|
||||
var rendererNode = vrmController.transform.GetFromPath(relativePath);
|
||||
var renderer = rendererNode.GetComponent<Renderer>();
|
||||
@@ -831,7 +844,7 @@ namespace UniVRM10
|
||||
{
|
||||
try
|
||||
{
|
||||
var binding = ExportMorphTargetBinding(b, getIndexFromRelativePath);
|
||||
var binding = ExportMorphTargetBinding(b, getRendererNodeIndexFromRelativePath);
|
||||
if (binding.Node < 0)
|
||||
{
|
||||
// node もしくは renderer が存在しない
|
||||
@@ -867,6 +880,43 @@ namespace UniVRM10
|
||||
UniGLTFLogger.Warning($"{ex}");
|
||||
}
|
||||
}
|
||||
|
||||
if (e.NodeTransformBindings != null && e.NodeTransformBindings.Length > 0)
|
||||
{
|
||||
Func<string, int> getNodeIndexFromRelativePath = relativePath =>
|
||||
{
|
||||
var n = vrmController.transform.GetFromPath(relativePath);
|
||||
var node = converter.Nodes[n.gameObject];
|
||||
return model.Nodes.IndexOf(node);
|
||||
};
|
||||
|
||||
var nodeTransform = new UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.VRMC_vrm_expressions_node_transform
|
||||
{
|
||||
NodeTransformBinds = new(),
|
||||
};
|
||||
foreach (var b in e.NodeTransformBindings)
|
||||
{
|
||||
try
|
||||
{
|
||||
var binding = ExportNodeTransformBinding(b, getNodeIndexFromRelativePath);
|
||||
if (binding.Node < 0)
|
||||
{
|
||||
// node もしくは renderer が存在しない
|
||||
continue;
|
||||
}
|
||||
|
||||
nodeTransform.NodeTransformBinds.Add(binding);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UniGLTFLogger.Warning($"{ex}");
|
||||
}
|
||||
}
|
||||
glTFExtension extensions = default;
|
||||
UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.GltfSerializer.SerializeTo(ref extensions, nodeTransform);
|
||||
vrmExpression.Extensions = extensions;
|
||||
}
|
||||
|
||||
return vrmExpression;
|
||||
}
|
||||
|
||||
|
||||
@@ -286,6 +286,25 @@ namespace UniVRM10
|
||||
clip.MaterialUVBindings = new MaterialUVBinding[] { };
|
||||
}
|
||||
|
||||
if (UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.GltfDeserializer.TryGet(
|
||||
expression.Extensions as glTFExtension,
|
||||
out UniGLTF.Extensions.VRMC_vrm_expressions_node_transform.VRMC_vrm_expressions_node_transform nodeTransform))
|
||||
{
|
||||
if (nodeTransform.NodeTransformBinds != null)
|
||||
{
|
||||
clip.NodeTransformBindings = nodeTransform.NodeTransformBinds?
|
||||
.Select(x => x.Build10(Root, this))
|
||||
.Where(x => x.HasValue)
|
||||
.Select(x => x.Value)
|
||||
.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
clip.NodeTransformBindings = new NodeTransformBinding[] { };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_expressions.Add((preset, clip));
|
||||
}
|
||||
return clip;
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
"GUID:8d76e605759c3f64a957d63ef96ada7c",
|
||||
"GUID:5f875fdc81c40184c8333b9d63c6ddd5",
|
||||
"GUID:f9fe54bb3090be448aa10ac92648a614",
|
||||
"GUID:da3e51d19d51a544fa14d43fee843098",
|
||||
"GUID:27619889b8ba8c24980f49ee34dbb44a",
|
||||
"GUID:0acc523941302664db1f4e527237feb3"
|
||||
"GUID:0acc523941302664db1f4e527237feb3",
|
||||
"GUID:1cd941934d098654fa21a13f28346412"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "com.vrmc.vrm",
|
||||
"version": "0.131.0",
|
||||
"version": "0.131.1",
|
||||
"displayName": "VRM-1.0",
|
||||
"description": "VRM-1.0 importer",
|
||||
"unity": "2021.3",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"com.unity.timeline": "1.7.6",
|
||||
"com.vrmc.gltf": "0.131.0"
|
||||
"com.vrmc.gltf": "0.131.1"
|
||||
},
|
||||
"samples": [
|
||||
{
|
||||
|
||||
@@ -163,7 +163,7 @@
|
||||
"depth": 0,
|
||||
"source": "embedded",
|
||||
"dependencies": {
|
||||
"com.vrmc.gltf": "0.131.0",
|
||||
"com.vrmc.gltf": "0.131.1",
|
||||
"com.unity.ugui": "1.0.0"
|
||||
}
|
||||
},
|
||||
@@ -173,7 +173,7 @@
|
||||
"source": "embedded",
|
||||
"dependencies": {
|
||||
"com.unity.timeline": "1.7.6",
|
||||
"com.vrmc.gltf": "0.131.0"
|
||||
"com.vrmc.gltf": "0.131.1"
|
||||
}
|
||||
},
|
||||
"com.unity.modules.ai": {
|
||||
|
||||
Reference in New Issue
Block a user