Created
April 12, 2019 09:30
-
-
Save m2wasabi/d9a380cfedd7daf4c4e3b39bab720b27 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using System.Linq; | |
using UnityEngine; | |
using UniGLTF; | |
namespace VRM.DynamicBoneExtension | |
{ | |
public class DynamicBoneLoadUtility { | |
public static void LoadSecondary(Transform root, List<Transform> nodes, | |
glTF_VRM_SecondaryAnimation secondaryAnimation) | |
{ | |
// clear components | |
var remove = root.Traverse() | |
.SelectMany(x => x.GetComponents<Component>()) | |
.Where(x => x is VRMSpringBone || x is VRMSpringBoneColliderGroup | |
|| x is DynamicBone || x is DynamicBoneCollider || x is DynamicBonePlaneCollider) | |
.ToArray(); | |
foreach (var x in remove) | |
{ | |
if (Application.isPlaying) | |
{ | |
GameObject.Destroy(x); | |
} | |
else | |
{ | |
GameObject.DestroyImmediate(x); | |
} | |
} | |
//var secondaryAnimation = context.VRM.extensions.VRM.secondaryAnimation; | |
var colliders = new List<DynamicBoneCollider>(); | |
foreach (var colliderGroup in secondaryAnimation.colliderGroups) | |
{ | |
foreach (var collider in colliderGroup.colliders) | |
{ | |
var dbCollider = nodes[colliderGroup.node].gameObject.AddComponent<DynamicBoneCollider>(); | |
dbCollider.m_Radius = collider.radius; | |
dbCollider.m_Center = collider.offset; | |
colliders.Add(dbCollider); | |
} | |
} | |
if (secondaryAnimation.boneGroups.Count > 0) | |
{ | |
foreach (var boneGroup in secondaryAnimation.boneGroups) | |
{ | |
foreach (var boneindex in boneGroup.bones) | |
{ | |
var db = nodes[boneindex].gameObject.AddComponent<DynamicBone>(); | |
if (boneGroup.center != -1) | |
{ | |
db.m_Root = nodes[boneGroup.center]; | |
} | |
else | |
{ | |
db.m_Root = db.gameObject.transform; | |
} | |
db.m_Damping = boneGroup.dragForce; | |
db.m_Stiffness = boneGroup.stiffiness * 0.25f; | |
db.m_Gravity = boneGroup.gravityDir * boneGroup.gravityPower; | |
db.m_Radius = boneGroup.hitRadius; | |
db.m_Colliders = new List<DynamicBoneColliderBase>(); | |
if (boneGroup.colliderGroups != null && boneGroup.colliderGroups.Any()) | |
{ | |
foreach (var colliderIndex in boneGroup.colliderGroups) | |
{ | |
db.m_Colliders.Add(colliders[colliderIndex]); | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ModelLoaderUniRx : MonoBehaviour | |
{ | |
void LoadVRM(byte[] bytes) | |
{ | |
// GLB形式のperse | |
var context = new VRMDbImporterContext(); | |
context.ParseGlb(bytes); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using UniGLTF; | |
using UnityEngine; | |
using VRM; | |
namespace VRM.DynamicBoneExtension | |
{ | |
public class VRMDbImporterContext : VRMImporterContext { | |
#region OnLoad | |
protected override void OnLoadModel() | |
{ | |
Root.name = "VRM"; | |
using (MeasureTime("VRM LoadMeta")) | |
{ | |
LoadMeta(); | |
} | |
using (MeasureTime("VRM LoadHumanoid")) | |
{ | |
LoadHumanoid(); | |
} | |
using (MeasureTime("VRM LoadBlendShapeMaster")) | |
{ | |
LoadBlendShapeMaster(); | |
} | |
using (MeasureTime("VRM LoadSecondary")) | |
{ | |
DynamicBoneLoadUtility.LoadSecondary(Root.transform, Nodes, | |
GLTF.extensions.VRM.secondaryAnimation); | |
} | |
using (MeasureTime("VRM LoadFirstPerson")) | |
{ | |
LoadFirstPerson(); | |
} | |
} | |
void LoadMeta() | |
{ | |
var meta = ReadMeta(); | |
if (meta.Thumbnail == null) | |
{ | |
/* | |
// 作る | |
var lookAt = Root.GetComponent<VRMLookAtHead>(); | |
var thumbnail = lookAt.CreateThumbnail(); | |
thumbnail.name = "thumbnail"; | |
meta.Thumbnail = thumbnail; | |
Textures.Add(new TextureItem(thumbnail)); | |
*/ | |
} | |
var _meta = Root.AddComponent<VRMMeta>(); | |
_meta.Meta = meta; | |
Meta = meta; | |
} | |
void LoadFirstPerson() | |
{ | |
var firstPerson = Root.AddComponent<VRMFirstPerson>(); | |
var gltfFirstPerson = GLTF.extensions.VRM.firstPerson; | |
if (gltfFirstPerson.firstPersonBone != -1) | |
{ | |
firstPerson.FirstPersonBone = Nodes[gltfFirstPerson.firstPersonBone]; | |
firstPerson.FirstPersonOffset = gltfFirstPerson.firstPersonBoneOffset; | |
} | |
else | |
{ | |
// fallback | |
firstPerson.SetDefault(); | |
} | |
firstPerson.TraverseRenderers(this); | |
// LookAt | |
var lookAtHead = Root.AddComponent<VRMLookAtHead>(); | |
lookAtHead.OnImported(this); | |
} | |
void LoadBlendShapeMaster() | |
{ | |
BlendShapeAvatar = ScriptableObject.CreateInstance<BlendShapeAvatar>(); | |
BlendShapeAvatar.name = "BlendShape"; | |
var transformMeshTable = new Dictionary<Mesh, Transform>(); | |
foreach (var transform in Root.transform.Traverse()) | |
{ | |
if (transform.GetSharedMesh() != null) | |
{ | |
transformMeshTable.Add(transform.GetSharedMesh(), transform); | |
} | |
} | |
var blendShapeList = GLTF.extensions.VRM.blendShapeMaster.blendShapeGroups; | |
if (blendShapeList != null && blendShapeList.Count > 0) | |
{ | |
foreach (var x in blendShapeList) | |
{ | |
BlendShapeAvatar.Clips.Add(LoadBlendShapeBind(x, transformMeshTable)); | |
} | |
} | |
var proxy = Root.AddComponent<VRMBlendShapeProxy>(); | |
BlendShapeAvatar.CreateDefaultPreset(); | |
proxy.BlendShapeAvatar = BlendShapeAvatar; | |
} | |
BlendShapeClip LoadBlendShapeBind(glTF_VRM_BlendShapeGroup group, Dictionary<Mesh, Transform> transformMeshTable) | |
{ | |
var asset = ScriptableObject.CreateInstance<BlendShapeClip>(); | |
var groupName = group.name; | |
var prefix = "BlendShape."; | |
while (groupName.StartsWith(prefix)) | |
{ | |
groupName = groupName.Substring(prefix.Length); | |
} | |
asset.name = "BlendShape." + groupName; | |
if (group != null) | |
{ | |
asset.BlendShapeName = groupName; | |
asset.Preset = EnumUtil.TryParseOrDefault<BlendShapePreset>(group.presetName); | |
asset.IsBinary = group.isBinary; | |
if (asset.Preset == BlendShapePreset.Unknown) | |
{ | |
// fallback | |
asset.Preset = EnumUtil.TryParseOrDefault<BlendShapePreset>(group.name); | |
} | |
asset.Values = group.binds.Select(x => | |
{ | |
var mesh = Meshes[x.mesh].Mesh; | |
var node = transformMeshTable[mesh]; | |
var relativePath = UniGLTF.UnityExtensions.RelativePathFrom(node, Root.transform); | |
return new BlendShapeBinding | |
{ | |
RelativePath = relativePath, | |
Index = x.index, | |
Weight = x.weight, | |
}; | |
}) | |
.ToArray(); | |
asset.MaterialValues = group.materialValues.Select(x => | |
{ | |
var value = new Vector4(); | |
for (int i = 0; i < x.targetValue.Length; ++i) | |
{ | |
switch (i) | |
{ | |
case 0: value.x = x.targetValue[0]; break; | |
case 1: value.y = x.targetValue[1]; break; | |
case 2: value.z = x.targetValue[2]; break; | |
case 3: value.w = x.targetValue[3]; break; | |
} | |
} | |
var material = GetMaterials().FirstOrDefault(y => y.name == x.materialName); | |
var propertyName = x.propertyName; | |
if (x.propertyName.EndsWith("_ST_S") | |
|| x.propertyName.EndsWith("_ST_T")) | |
{ | |
propertyName = x.propertyName.Substring(0, x.propertyName.Length - 2); | |
} | |
var binding = default(MaterialValueBinding?); | |
if (material != null) | |
{ | |
try | |
{ | |
binding = new MaterialValueBinding | |
{ | |
MaterialName = x.materialName, | |
ValueName = x.propertyName, | |
TargetValue = value, | |
BaseValue = material.GetColor(propertyName), | |
}; | |
} | |
catch (Exception) | |
{ | |
// do nothing | |
} | |
} | |
return binding; | |
}) | |
.Where(x => x.HasValue) | |
.Select(x => x.Value) | |
.ToArray(); | |
} | |
return asset; | |
} | |
static String ToHumanBoneName(HumanBodyBones b) | |
{ | |
foreach (var x in HumanTrait.BoneName) | |
{ | |
if (x.Replace(" ", "") == b.ToString()) | |
{ | |
return x; | |
} | |
} | |
throw new KeyNotFoundException(); | |
} | |
static SkeletonBone ToSkeletonBone(Transform t) | |
{ | |
var sb = new SkeletonBone(); | |
sb.name = t.name; | |
sb.position = t.localPosition; | |
sb.rotation = t.localRotation; | |
sb.scale = t.localScale; | |
return sb; | |
} | |
private void LoadHumanoid() | |
{ | |
AvatarDescription = GLTF.extensions.VRM.humanoid.ToDescription(Nodes); | |
AvatarDescription.name = "AvatarDescription"; | |
HumanoidAvatar = AvatarDescription.CreateAvatar(Root.transform); | |
if (!HumanoidAvatar.isValid || !HumanoidAvatar.isHuman) | |
{ | |
throw new Exception("fail to create avatar"); | |
} | |
HumanoidAvatar.name = "VrmAvatar"; | |
var humanoid = Root.AddComponent<VRMHumanoidDescription>(); | |
humanoid.Avatar = HumanoidAvatar; | |
humanoid.Description = AvatarDescription; | |
var animator = Root.GetComponent<Animator>(); | |
if (animator == null) | |
{ | |
animator = Root.AddComponent<Animator>(); | |
} | |
animator.avatar = HumanoidAvatar; | |
} | |
#endregion | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment