您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

808 行
40 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using UniGLTF;
using UnityEngine;
using VrmLib;
using VRMShaders;
namespace UniVRM10
{
public class Vrm10Exporter : IDisposable
{
public const string VRM_SPEC_VERSION = "1.0";
public const string SPRINGBONE_SPEC_VERSION = "1.0";
public const string NODE_CONSTRAINT_SPEC_VERSION = "1.0";
public const string MTOON_SPEC_VERSION = "1.0";
public const string LICENSE_URL_JA = "https://vrm.dev/licenses/1.0/";
public const string LICENSE_URL_EN = "https://vrm.dev/licenses/1.0/en/";
public readonly ExportingGltfData Storage = new ExportingGltfData();
public readonly string VrmExtensionName = "VRMC_vrm";
ITextureSerializer m_textureSerializer;
TextureExporter m_textureExporter;
GltfExportSettings m_settings;
public AssetBundleManifest BundleManifest{get;set;}
public Vrm10Exporter(ITextureSerializer textureSerializer, GltfExportSettings settings)
{
m_settings = settings;
if (textureSerializer == null)
{
throw new ArgumentException(nameof(textureSerializer));
}
Storage.Gltf.extensionsUsed.Add(glTF_KHR_texture_transform.ExtensionName);
Storage.Gltf.extensionsUsed.Add(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm.ExtensionName);
Storage.Gltf.extensionsUsed.Add(glTF_KHR_materials_unlit.ExtensionName);
Storage.Gltf.extensionsUsed.Add(UniGLTF.Extensions.VRMC_materials_mtoon.VRMC_materials_mtoon.ExtensionName);
Storage.Gltf.extensionsUsed.Add(UniGLTF.Extensions.VRMC_springBone.VRMC_springBone.ExtensionName);
Storage.Gltf.extensionsUsed.Add(UniGLTF.Extensions.VRMC_node_constraint.VRMC_node_constraint.ExtensionName);
m_textureSerializer = textureSerializer;
m_textureExporter = new TextureExporter(m_textureSerializer);
}
public void Dispose()
{
m_textureExporter.Dispose();
}
public static glTFAssets ExportAsset(Model model)
{
var asset = new glTFAssets();
if (!string.IsNullOrEmpty(model.AssetVersion)) asset.version = model.AssetVersion;
if (!string.IsNullOrEmpty(model.AssetMinVersion)) asset.minVersion = model.AssetMinVersion;
if (!string.IsNullOrEmpty(model.AssetGenerator)) asset.generator = model.AssetGenerator;
if (!string.IsNullOrEmpty(model.AssetCopyright)) asset.copyright = model.AssetCopyright;
return asset;
}
public static IEnumerable<glTFMesh> ExportMeshes(List<MeshGroup> groups, List<object> materials, ExportingGltfData data, ExportArgs option)
{
foreach (var group in groups)
{
yield return group.ExportMeshGroup(materials, data, option);
}
}
public static IEnumerable<(glTFNode, glTFSkin)> ExportNodes(INativeArrayManager arrayManager, List<Node> nodes, List<MeshGroup> groups, ExportingGltfData data, ExportArgs option)
{
foreach (var node in nodes)
{
var gltfNode = new glTFNode
{
name = node.Name,
};
glTFSkin gltfSkin = default;
gltfNode.translation = node.LocalTranslation.ToFloat3();
gltfNode.rotation = node.LocalRotation.ToFloat4();
gltfNode.scale = node.LocalScaling.ToFloat3();
if (node.MeshGroup != null)
{
gltfNode.mesh = groups.IndexOfThrow(node.MeshGroup);
var skin = node.MeshGroup.Skin;
if (skin != null)
{
gltfSkin = new glTFSkin()
{
joints = skin.Joints.Select(joint => nodes.IndexOfThrow(joint)).ToArray()
};
if (skin.InverseMatrices == null)
{
skin.CalcInverseMatrices(arrayManager);
}
if (skin.InverseMatrices != null)
{
gltfSkin.inverseBindMatrices = skin.InverseMatrices.AddAccessorTo(data, 0, option.sparse);
}
if (skin.Root != null)
{
gltfSkin.skeleton = nodes.IndexOf(skin.Root);
}
}
}
gltfNode.children = node.Children.Select(child => nodes.IndexOfThrow(child)).ToArray();
yield return (gltfNode, gltfSkin);
}
}
/// <summary>
/// revere X
/// </summary>
/// <param name="v"></param>
/// <returns></returns>
static float[] ReverseX(Vector3 v)
{
return new float[] { -v.x, v.y, v.z };
}
///
/// 必要な容量を計算
/// (sparseは考慮してないので大きめ)
static int CalcReserveBytes(Model model)
{
int reserveBytes = 0;
// mesh
foreach (var g in model.MeshGroups)
{
foreach (var mesh in g.Meshes)
{
// 頂点バッファ
reserveBytes += mesh.IndexBuffer.ByteLength;
foreach (var kv in mesh.VertexBuffer)
{
reserveBytes += kv.Value.ByteLength;
}
// morph
foreach (var morph in mesh.MorphTargets)
{
foreach (var kv in morph.VertexBuffer)
{
reserveBytes += kv.Value.ByteLength;
}
}
}
}
return reserveBytes;
}
static IEnumerable<glTFMaterial> ExportMaterials(Model model, ITextureExporter textureExporter, GltfExportSettings settings,AssetBundleManifest bundleManifest)
{
if(settings.useCustomShader)
{
var materialExporter = new CustomMaterialExporter();
foreach (Material material in model.Materials)
{
yield return materialExporter.ExportMaterial(material, textureExporter, settings,bundleManifest);
}
}
else
{
var materialExporter = new BuiltInVrm10MaterialExporter();
foreach (Material material in model.Materials)
{
yield return materialExporter.ExportMaterial(material, textureExporter, settings);
}
}
}
public void Export(GameObject root, Model model, ModelExporter converter, ExportArgs option, VRM10ObjectMeta vrmMeta = null)
{
Storage.Gltf.asset = ExportAsset(model);
Storage.Reserve(CalcReserveBytes(model));
foreach (var material in ExportMaterials(model, m_textureExporter, m_settings,BundleManifest))
{
Storage.Gltf.materials.Add(material);
}
foreach (var mesh in ExportMeshes(model.MeshGroups, model.Materials, Storage, option))
{
Storage.Gltf.meshes.Add(mesh);
}
using (var arrayManager = new NativeArrayManager())
{
foreach (var (node, skin) in ExportNodes(arrayManager, model.Nodes, model.MeshGroups, Storage, option))
{
Storage.Gltf.nodes.Add(node);
if (skin != null)
{
var skinIndex = Storage.Gltf.skins.Count;
Storage.Gltf.skins.Add(skin);
node.skin = skinIndex;
}
}
}
Storage.Gltf.scenes.Add(new gltfScene()
{
nodes = model.Root.Children.Select(child => model.Nodes.IndexOfThrow(child)).ToArray()
});
var (vrm, vrmSpringBone, thumbnailTextureIndex) = ExportVrm(root, model, converter, vrmMeta, Storage.Gltf.nodes, m_textureExporter);
// Extension で Texture が増える場合があるので最後に呼ぶ
var exportedTextures = m_textureExporter.Export();
for (var exportedTextureIdx = 0; exportedTextureIdx < exportedTextures.Count; ++exportedTextureIdx)
{
var (unityTexture, texColorSpace) = exportedTextures[exportedTextureIdx];
GltfTextureExporter.PushGltfTexture(Storage, unityTexture, texColorSpace, m_textureSerializer);
}
if (thumbnailTextureIndex.HasValue)
{
vrm.Meta.ThumbnailImage = Storage.Gltf.textures[thumbnailTextureIndex.Value].source;
}
UniGLTF.Extensions.VRMC_vrm.GltfSerializer.SerializeTo(ref Storage.Gltf.extensions, vrm);
if (vrmSpringBone != null)
{
UniGLTF.Extensions.VRMC_springBone.GltfSerializer.SerializeTo(ref Storage.Gltf.extensions, vrmSpringBone);
}
// Fix Duplicated name
gltfExporter.FixName(Storage.Gltf);
}
/// <summary>
/// VRMコンポーネントのエクスポート
/// </summary>
/// <param name="vrm"></param>
/// <param name="springBone"></param>
/// <param name="constraint"></param>
/// <param name="root"></param>
/// <param name="model"></param>
/// <param name="converter"></param>
/// <param name="vrmObject"></param>
/// <returns></returns>
(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm,
UniGLTF.Extensions.VRMC_springBone.VRMC_springBone springBone,
int? thumbnailIndex) ExportVrm(GameObject root, Model model, ModelExporter converter,
VRM10ObjectMeta vrmMeta, List<glTFNode> nodes, ITextureExporter textureExporter)
{
var vrmController = root?.GetComponent<Vrm10Instance>();
if (vrmMeta == null)
{
if (vrmController?.Vrm?.Meta == null)
{
throw new NullReferenceException("metaObject is null");
}
vrmMeta = vrmController.Vrm.Meta;
}
var vrm = new UniGLTF.Extensions.VRMC_vrm.VRMC_vrm
{
SpecVersion = VRM_SPEC_VERSION,
Humanoid = new UniGLTF.Extensions.VRMC_vrm.Humanoid
{
HumanBones = new UniGLTF.Extensions.VRMC_vrm.HumanBones
{
},
},
Meta = new UniGLTF.Extensions.VRMC_vrm.Meta
{
LicenseUrl = LICENSE_URL_JA,
AllowExcessivelySexualUsage = false,
AllowExcessivelyViolentUsage = false,
AllowPoliticalOrReligiousUsage = false,
AllowRedistribution = false,
},
};
//
// required
//
ExportHumanoid(vrm, model);
var thumbnailTextureIndex = ExportMeta(vrm, vrmMeta, textureExporter);
//
// optional
//
UniGLTF.Extensions.VRMC_springBone.VRMC_springBone vrmSpringBone = default;
if (vrmController != null)
{
ExportExpression(vrm, vrmController, model, converter);
ExportLookAt(vrm, vrmController);
ExportFirstPerson(vrm, vrmController, model, converter);
vrmSpringBone = ExportSpringBone(vrmController, model, converter);
ExportConstraints(vrmController, model, converter, nodes);
}
return (vrm, vrmSpringBone, thumbnailTextureIndex);
}
static UniGLTF.Extensions.VRMC_springBone.ColliderShape ExportShape(VRM10SpringBoneCollider z)
{
var shape = new UniGLTF.Extensions.VRMC_springBone.ColliderShape();
switch (z.ColliderType)
{
case VRM10SpringBoneColliderTypes.Sphere:
{
shape.Sphere = new UniGLTF.Extensions.VRMC_springBone.ColliderShapeSphere
{
Radius = z.Radius,
Offset = ReverseX(z.Offset),
};
break;
}
case VRM10SpringBoneColliderTypes.Capsule:
{
shape.Capsule = new UniGLTF.Extensions.VRMC_springBone.ColliderShapeCapsule
{
Radius = z.Radius,
Offset = ReverseX(z.Offset),
Tail = ReverseX(z.Tail),
};
break;
}
}
return shape;
}
static UniGLTF.Extensions.VRMC_springBone.SpringBoneJoint ExportJoint(VRM10SpringBoneJoint y, Func<Transform, int> getIndexFromTransform)
{
var joint = new UniGLTF.Extensions.VRMC_springBone.SpringBoneJoint
{
Node = getIndexFromTransform(y.transform),
HitRadius = y.m_jointRadius,
DragForce = y.m_dragForce,
Stiffness = y.m_stiffnessForce,
GravityDir = ReverseX(y.m_gravityDir),
GravityPower = y.m_gravityPower,
};
return joint;
}
static UniGLTF.Extensions.VRMC_springBone.VRMC_springBone ExportSpringBone(Vrm10Instance controller, Model model, ModelExporter converter)
{
var colliders = controller.GetComponentsInChildren<VRM10SpringBoneCollider>();
// if colliders, collider groups and springs don't exist, don't export the extension
if (
colliders.Length == 0 &&
controller.SpringBone.ColliderGroups.Count == 0 &&
controller.SpringBone.Springs.Count == 0
)
{
return null;
}
var springBone = new UniGLTF.Extensions.VRMC_springBone.VRMC_springBone
{
SpecVersion = SPRINGBONE_SPEC_VERSION,
Colliders = new List<UniGLTF.Extensions.VRMC_springBone.Collider>(),
ColliderGroups = new List<UniGLTF.Extensions.VRMC_springBone.ColliderGroup>(),
Springs = new List<UniGLTF.Extensions.VRMC_springBone.Spring>(),
};
// colliders
Func<Transform, int> getNodeIndexFromTransform = t =>
{
var node = converter.Nodes[t.gameObject];
return model.Nodes.IndexOf(node);
};
foreach (var c in colliders)
{
springBone.Colliders.Add(new UniGLTF.Extensions.VRMC_springBone.Collider
{
Node = getNodeIndexFromTransform(c.transform),
Shape = ExportShape(c),
});
}
// colliderGroups
foreach (var x in controller.SpringBone.ColliderGroups)
{
springBone.ColliderGroups.Add(new UniGLTF.Extensions.VRMC_springBone.ColliderGroup
{
Colliders = x.Colliders.Select(y => Array.IndexOf(colliders, y)).ToArray(),
});
}
// springs
foreach (var x in controller.SpringBone.Springs)
{
var spring = new UniGLTF.Extensions.VRMC_springBone.Spring
{
Name = x.Name,
Joints = x.Joints.Select(y => ExportJoint(y, getNodeIndexFromTransform)).ToList(),
ColliderGroups = x.ColliderGroups.Select(y => controller.SpringBone.ColliderGroups.IndexOf(y)).ToArray(),
};
if (x.Center != null)
{
var center = model.Nodes.IndexOf(converter.Nodes[x.Center.gameObject]);
if (center != -1)
{
spring.Center = center;
}
}
springBone.Springs.Add(spring);
}
return springBone;
}
static void ExportConstraints(Vrm10Instance vrmController, Model model, ModelExporter converter, List<glTFNode> nodes)
{
var constraints = vrmController.GetComponentsInChildren<IVrm10Constraint>();
foreach (var constraint in constraints)
{
var vrmConstraint = new UniGLTF.Extensions.VRMC_node_constraint.VRMC_node_constraint
{
SpecVersion = NODE_CONSTRAINT_SPEC_VERSION,
Constraint = new UniGLTF.Extensions.VRMC_node_constraint.Constraint
{
},
};
switch (constraint)
{
case Vrm10AimConstraint aimConstraint:
vrmConstraint.Constraint.Aim = new UniGLTF.Extensions.VRMC_node_constraint.AimConstraint
{
Source = model.Nodes.IndexOf(converter.Nodes[aimConstraint.Source.gameObject]),
Weight = aimConstraint.Weight,
AimAxis = Vrm10ConstraintUtil.ReverseX(aimConstraint.AimAxis),
};
break;
case Vrm10RollConstraint rollConstraint:
vrmConstraint.Constraint.Roll = new UniGLTF.Extensions.VRMC_node_constraint.RollConstraint
{
Source = model.Nodes.IndexOf(converter.Nodes[rollConstraint.Source.gameObject]),
Weight = rollConstraint.Weight,
RollAxis = rollConstraint.RollAxis,
};
break;
case Vrm10RotationConstraint rotationConstraint:
vrmConstraint.Constraint.Rotation = new UniGLTF.Extensions.VRMC_node_constraint.RotationConstraint
{
Source = model.Nodes.IndexOf(converter.Nodes[rotationConstraint.Source.gameObject]),
Weight = rotationConstraint.Weight,
};
break;
default:
throw new NotImplementedException();
}
// serialize to gltfNode
var node = converter.Nodes[constraint.ConstraintTarget];
var nodeIndex = model.Nodes.IndexOf(node);
var gltfNode = nodes[nodeIndex];
UniGLTF.Extensions.VRMC_node_constraint.GltfSerializer.SerializeTo(ref gltfNode.extensions, vrmConstraint);
}
}
static bool[] ToArray(AxisMask mask)
{
return new bool[]
{
mask.HasFlag(AxisMask.X),
mask.HasFlag(AxisMask.Y),
mask.HasFlag(AxisMask.Z),
};
}
static UniGLTF.Extensions.VRMC_vrm.MeshAnnotation ExportMeshAnnotation(RendererFirstPersonFlags flags, Transform root, Func<Renderer, int> getIndex)
{
return new UniGLTF.Extensions.VRMC_vrm.MeshAnnotation
{
Node = getIndex(flags.GetRenderer(root)),
Type = flags.FirstPersonFlag,
};
}
void ExportFirstPerson(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, Vrm10Instance vrmController, Model model, ModelExporter converter)
{
if (!(vrmController?.Vrm?.FirstPerson is VRM10ObjectFirstPerson firstPerson))
{
return;
}
vrm.FirstPerson = new UniGLTF.Extensions.VRMC_vrm.FirstPerson
{
MeshAnnotations = new List<UniGLTF.Extensions.VRMC_vrm.MeshAnnotation>(),
};
Func<Renderer, int> getIndex = r =>
{
var node = converter.Nodes[r.gameObject];
return model.Nodes.IndexOf(node);
};
foreach (var f in firstPerson.Renderers)
{
vrm.FirstPerson.MeshAnnotations.Add(ExportMeshAnnotation(f, vrmController.transform, getIndex));
}
}
static UniGLTF.Extensions.VRMC_vrm.LookAtRangeMap ExportLookAtRangeMap(CurveMapper mapper)
{
return new UniGLTF.Extensions.VRMC_vrm.LookAtRangeMap
{
InputMaxValue = mapper.CurveXRangeDegree,
OutputScale = mapper.CurveYRangeDegree,
};
}
static void ExportLookAt(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, Vrm10Instance vrmController)
{
if (!(vrmController?.Vrm?.LookAt is VRM10ObjectLookAt lookAt))
{
return;
}
vrm.LookAt = new UniGLTF.Extensions.VRMC_vrm.LookAt
{
Type = lookAt.LookAtType,
OffsetFromHeadBone = lookAt.OffsetFromHead.ReverseX().ToFloat3(),
RangeMapHorizontalInner = ExportLookAtRangeMap(lookAt.HorizontalInner),
RangeMapHorizontalOuter = ExportLookAtRangeMap(lookAt.HorizontalOuter),
RangeMapVerticalDown = ExportLookAtRangeMap(lookAt.VerticalDown),
RangeMapVerticalUp = ExportLookAtRangeMap(lookAt.VerticalUp),
};
}
static UniGLTF.Extensions.VRMC_vrm.MorphTargetBind ExportMorphTargetBinding(MorphTargetBinding binding, Func<string, int> getIndex)
{
return new UniGLTF.Extensions.VRMC_vrm.MorphTargetBind
{
Node = getIndex(binding.RelativePath),
Index = binding.Index,
Weight = binding.Weight,
};
}
static UniGLTF.Extensions.VRMC_vrm.MaterialColorBind ExportMaterialColorBinding(MaterialColorBinding binding, Func<string, int> getIndex)
{
return new UniGLTF.Extensions.VRMC_vrm.MaterialColorBind
{
Material = getIndex(binding.MaterialName),
Type = binding.BindType,
TargetValue = new float[] { binding.TargetValue.x, binding.TargetValue.y, binding.TargetValue.z, binding.TargetValue.w },
};
}
static UniGLTF.Extensions.VRMC_vrm.TextureTransformBind ExportTextureTransformBinding(MaterialUVBinding binding, Func<string, int> getIndex)
{
var (scale, offset) = TextureTransform.VerticalFlipScaleOffset(binding.Scaling, binding.Offset);
return new UniGLTF.Extensions.VRMC_vrm.TextureTransformBind
{
Material = getIndex(binding.MaterialName),
Offset = new float[] { offset.x, offset.y },
Scale = new float[] { scale.x, scale.y },
};
}
static UniGLTF.Extensions.VRMC_vrm.Expression ExportExpression(VRM10Expression e, Vrm10Instance vrmController, Model model, ModelExporter converter)
{
if (e == null)
{
return null;
}
Func<string, int> getIndexFromRelativePath = relativePath =>
{
var rendererNode = vrmController.transform.GetFromPath(relativePath);
var node = converter.Nodes[rendererNode.gameObject];
return model.Nodes.IndexOf(node);
};
var vrmExpression = new UniGLTF.Extensions.VRMC_vrm.Expression
{
// Preset = e.Preset,
// Name = e.ExpressionName,
IsBinary = e.IsBinary,
OverrideBlink = e.OverrideBlink,
OverrideLookAt = e.OverrideLookAt,
OverrideMouth = e.OverrideMouth,
MorphTargetBinds = new List<UniGLTF.Extensions.VRMC_vrm.MorphTargetBind>(),
MaterialColorBinds = new List<UniGLTF.Extensions.VRMC_vrm.MaterialColorBind>(),
TextureTransformBinds = new List<UniGLTF.Extensions.VRMC_vrm.TextureTransformBind>(),
};
Func<string, int> getIndexFromMaterialName = materialName =>
{
for (int i = 0; i < model.Materials.Count; ++i)
{
var m = model.Materials[i] as Material;
if (m.name == materialName)
{
return i;
}
}
throw new KeyNotFoundException();
};
foreach (var b in e.MorphTargetBindings)
{
try
{
vrmExpression.MorphTargetBinds.Add(ExportMorphTargetBinding(b, getIndexFromRelativePath));
}
catch (Exception ex)
{
Debug.LogWarning(ex);
}
}
foreach (var b in e.MaterialColorBindings)
{
try
{
vrmExpression.MaterialColorBinds.Add(ExportMaterialColorBinding(b, getIndexFromMaterialName));
}
catch (Exception ex)
{
Debug.LogWarning(ex);
}
}
foreach (var b in e.MaterialUVBindings)
{
try
{
vrmExpression.TextureTransformBinds.Add(ExportTextureTransformBinding(b, getIndexFromMaterialName));
}
catch (Exception ex)
{
Debug.LogWarning(ex);
}
}
return vrmExpression;
}
static void ExportExpression(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, Vrm10Instance vrmController, Model model, ModelExporter converter)
{
if (vrmController?.Vrm?.Expression?.Clips == null)
{
return;
}
vrm.Expressions = new UniGLTF.Extensions.VRMC_vrm.Expressions
{
Preset = new UniGLTF.Extensions.VRMC_vrm.Preset
{
Happy = ExportExpression(vrmController.Vrm.Expression.Happy, vrmController, model, converter),
Angry = ExportExpression(vrmController.Vrm.Expression.Angry, vrmController, model, converter),
Sad = ExportExpression(vrmController.Vrm.Expression.Sad, vrmController, model, converter),
Relaxed = ExportExpression(vrmController.Vrm.Expression.Relaxed, vrmController, model, converter),
Surprised = ExportExpression(vrmController.Vrm.Expression.Surprised, vrmController, model, converter),
Aa = ExportExpression(vrmController.Vrm.Expression.Aa, vrmController, model, converter),
Ih = ExportExpression(vrmController.Vrm.Expression.Ih, vrmController, model, converter),
Ou = ExportExpression(vrmController.Vrm.Expression.Ou, vrmController, model, converter),
Ee = ExportExpression(vrmController.Vrm.Expression.Ee, vrmController, model, converter),
Oh = ExportExpression(vrmController.Vrm.Expression.Oh, vrmController, model, converter),
Blink = ExportExpression(vrmController.Vrm.Expression.Blink, vrmController, model, converter),
BlinkLeft = ExportExpression(vrmController.Vrm.Expression.BlinkLeft, vrmController, model, converter),
BlinkRight = ExportExpression(vrmController.Vrm.Expression.BlinkRight, vrmController, model, converter),
LookUp = ExportExpression(vrmController.Vrm.Expression.LookUp, vrmController, model, converter),
LookDown = ExportExpression(vrmController.Vrm.Expression.LookDown, vrmController, model, converter),
LookLeft = ExportExpression(vrmController.Vrm.Expression.LookLeft, vrmController, model, converter),
LookRight = ExportExpression(vrmController.Vrm.Expression.LookRight, vrmController, model, converter),
Neutral = ExportExpression(vrmController.Vrm.Expression.Neutral, vrmController, model, converter),
},
Custom = vrmController.Vrm.Expression.CustomClips.ToDictionary(c => c.name, c => ExportExpression(c, vrmController, model, converter)),
};
}
public static int? ExportMeta(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, VRM10ObjectMeta meta, ITextureExporter textureExporter)
{
vrm.Meta.Name = meta.Name;
vrm.Meta.Version = meta.Version;
vrm.Meta.Authors = meta.Authors.ToList();
vrm.Meta.CopyrightInformation = meta.CopyrightInformation;
vrm.Meta.ContactInformation = meta.ContactInformation;
vrm.Meta.References = meta.References.ToList();
vrm.Meta.ThirdPartyLicenses = meta.ThirdPartyLicenses;
vrm.Meta.AvatarPermission = meta.AvatarPermission;
vrm.Meta.AllowExcessivelyViolentUsage = meta.ViolentUsage;
vrm.Meta.AllowExcessivelySexualUsage = meta.SexualUsage;
vrm.Meta.CommercialUsage = meta.CommercialUsage;
vrm.Meta.AllowPoliticalOrReligiousUsage = meta.PoliticalOrReligiousUsage;
vrm.Meta.AllowAntisocialOrHateUsage = meta.AntisocialOrHateUsage;
vrm.Meta.CreditNotation = meta.CreditNotation;
vrm.Meta.AllowRedistribution = meta.Redistribution;
vrm.Meta.Modification = meta.Modification;
vrm.Meta.OtherLicenseUrl = meta.OtherLicenseUrl;
int? thumbnailTextureIndex = default;
if (meta.Thumbnail != null)
{
thumbnailTextureIndex = textureExporter.RegisterExportingAsSRgb(meta.Thumbnail, needsAlpha: true);
}
return thumbnailTextureIndex;
}
static void ExportHumanoid(UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm, Model model)
{
// humanoid
for (int i = 0; i < model.Nodes.Count; ++i)
{
var bone = model.Nodes[i];
switch (bone.HumanoidBone)
{
case HumanoidBones.hips: vrm.Humanoid.HumanBones.Hips = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.spine: vrm.Humanoid.HumanBones.Spine = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.chest: vrm.Humanoid.HumanBones.Chest = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.upperChest: vrm.Humanoid.HumanBones.UpperChest = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.neck: vrm.Humanoid.HumanBones.Neck = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.head: vrm.Humanoid.HumanBones.Head = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftEye: vrm.Humanoid.HumanBones.LeftEye = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightEye: vrm.Humanoid.HumanBones.RightEye = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.jaw: vrm.Humanoid.HumanBones.Jaw = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftUpperLeg: vrm.Humanoid.HumanBones.LeftUpperLeg = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftLowerLeg: vrm.Humanoid.HumanBones.LeftLowerLeg = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftFoot: vrm.Humanoid.HumanBones.LeftFoot = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftToes: vrm.Humanoid.HumanBones.LeftToes = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightUpperLeg: vrm.Humanoid.HumanBones.RightUpperLeg = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightLowerLeg: vrm.Humanoid.HumanBones.RightLowerLeg = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightFoot: vrm.Humanoid.HumanBones.RightFoot = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightToes: vrm.Humanoid.HumanBones.RightToes = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftShoulder: vrm.Humanoid.HumanBones.LeftShoulder = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftUpperArm: vrm.Humanoid.HumanBones.LeftUpperArm = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftLowerArm: vrm.Humanoid.HumanBones.LeftLowerArm = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftHand: vrm.Humanoid.HumanBones.LeftHand = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightShoulder: vrm.Humanoid.HumanBones.RightShoulder = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightUpperArm: vrm.Humanoid.HumanBones.RightUpperArm = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightLowerArm: vrm.Humanoid.HumanBones.RightLowerArm = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightHand: vrm.Humanoid.HumanBones.RightHand = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftThumbMetacarpal: vrm.Humanoid.HumanBones.LeftThumbMetacarpal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftThumbProximal: vrm.Humanoid.HumanBones.LeftThumbProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftThumbDistal: vrm.Humanoid.HumanBones.LeftThumbDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftIndexProximal: vrm.Humanoid.HumanBones.LeftIndexProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftIndexIntermediate: vrm.Humanoid.HumanBones.LeftIndexIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftIndexDistal: vrm.Humanoid.HumanBones.LeftIndexDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftMiddleProximal: vrm.Humanoid.HumanBones.LeftMiddleProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftMiddleIntermediate: vrm.Humanoid.HumanBones.LeftMiddleIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftMiddleDistal: vrm.Humanoid.HumanBones.LeftMiddleDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftRingProximal: vrm.Humanoid.HumanBones.LeftRingProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftRingIntermediate: vrm.Humanoid.HumanBones.LeftRingIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftRingDistal: vrm.Humanoid.HumanBones.LeftRingDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftLittleProximal: vrm.Humanoid.HumanBones.LeftLittleProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftLittleIntermediate: vrm.Humanoid.HumanBones.LeftLittleIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.leftLittleDistal: vrm.Humanoid.HumanBones.LeftLittleDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightThumbMetacarpal: vrm.Humanoid.HumanBones.RightThumbMetacarpal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightThumbProximal: vrm.Humanoid.HumanBones.RightThumbProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightThumbDistal: vrm.Humanoid.HumanBones.RightThumbDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightIndexProximal: vrm.Humanoid.HumanBones.RightIndexProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightIndexIntermediate: vrm.Humanoid.HumanBones.RightIndexIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightIndexDistal: vrm.Humanoid.HumanBones.RightIndexDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightMiddleProximal: vrm.Humanoid.HumanBones.RightMiddleProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightMiddleIntermediate: vrm.Humanoid.HumanBones.RightMiddleIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightMiddleDistal: vrm.Humanoid.HumanBones.RightMiddleDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightRingProximal: vrm.Humanoid.HumanBones.RightRingProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightRingIntermediate: vrm.Humanoid.HumanBones.RightRingIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightRingDistal: vrm.Humanoid.HumanBones.RightRingDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightLittleProximal: vrm.Humanoid.HumanBones.RightLittleProximal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightLittleIntermediate: vrm.Humanoid.HumanBones.RightLittleIntermediate = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
case HumanoidBones.rightLittleDistal: vrm.Humanoid.HumanBones.RightLittleDistal = new UniGLTF.Extensions.VRMC_vrm.HumanBone { Node = i }; break;
}
}
}
/// <summary>
/// 便利関数
/// </summary>
/// <param name="go"></param>
/// <param name="getTextureBytes"></param>
/// <returns></returns>
public static byte[] Export(GameObject go, ITextureSerializer textureSerializer = null, VRM10ObjectMeta vrmMeta = null)
{
using (var arrayManager = new NativeArrayManager())
{
// ヒエラルキーからジオメトリーを収集
var converter = new UniVRM10.ModelExporter();
var model = converter.Export(arrayManager, go);
// 右手系に変換
model.ConvertCoordinate(VrmLib.Coordinates.Vrm1);
// Model と go から VRM-1.0 にExport
var exporter10 = new Vrm10Exporter(textureSerializer ?? new RuntimeTextureSerializer(), new GltfExportSettings());
var option = new VrmLib.ExportArgs
{
};
exporter10.Export(go, model, converter, option, vrmMeta);
return exporter10.Storage.ToGlbBytes();
}
}
}
}