void Apply(INativeArrayManager arrayManager, VertexBuffer vertexBuffer) { var dstPosition = vertexBuffer.Positions.Bytes.Reinterpret <Vector3>(1); // Span<Vector3> emptyNormal = stackalloc Vector3[0]; Apply(arrayManager, vertexBuffer, dstPosition, vertexBuffer.Normals != null ? vertexBuffer.Normals.Bytes.Reinterpret <Vector3>(1) : default); }
/// <summary> /// GameObject to VrmLib.Model /// </summary> /// <param name="root"></param> /// <returns></returns> public VrmLib.Model Export(INativeArrayManager arrayManager, GameObject root) { Model = new VrmLib.Model(VrmLib.Coordinates.Unity); _Export(arrayManager, root); // humanoid { var humanoid = root.GetComponent <UniHumanoid.Humanoid>(); if (humanoid is null) { humanoid = root.AddComponent <UniHumanoid.Humanoid>(); humanoid.AssignBonesFromAnimator(); } foreach (HumanBodyBones humanBoneType in Enum.GetValues(typeof(HumanBodyBones))) { var transform = humanoid.GetBoneTransform(humanBoneType); if (transform != null && Nodes.TryGetValue(transform.gameObject, out VrmLib.Node node)) { node.HumanoidBone = (VrmLib.HumanoidBones)Enum.Parse(typeof(VrmLib.HumanoidBones), humanBoneType.ToString(), true); } } } return(Model); }
public BufferAccessor(INativeArrayManager arrayManager, NativeArray <byte> bytes, AccessorValueType componentType, AccessorVectorType accessorType, int count) { ArrayManager = arrayManager; Bytes = bytes; ComponentType = componentType; AccessorType = accessorType; Count = count; }
private static BufferAccessor ToBufferAccessor <T>(INativeArrayManager arrayManager, T[] value, AccessorValueType valueType, AccessorVectorType vectorType) where T : struct { return(new BufferAccessor(arrayManager, arrayManager.CreateNativeArray(value).Reinterpret <byte>(Marshal.SizeOf <T>()), valueType, vectorType, value.Length )); }
/// <summary> /// BoneSkinningもしくはMorphTargetの適用 /// <summary> public void Skinning(INativeArrayManager arrayManager, VertexBuffer vertexBuffer = null) { m_indexOfRoot = (ushort)Joints.IndexOf(Root); var addRoot = Root != null && m_indexOfRoot == ushort.MaxValue; if (addRoot) { m_indexOfRoot = (ushort)Joints.Count; Joints.Add(Root); } if (m_matrices == null) { m_matrices = new Matrix4x4[Joints.Count]; } if (InverseMatrices == null) { CalcInverseMatrices(arrayManager); } else { if (addRoot) { var inverseArray = InverseMatrices.Bytes.Reinterpret <Matrix4x4>(1); var concat = inverseArray.Concat(new[] { Root.InverseMatrix }).ToArray(); InverseMatrices.Assign(concat); } } var inverse = InverseMatrices.GetSpan <Matrix4x4>(); // if (Root != null) // { // var rootInverse = Root.InverseMatrix; // var root = Root.Matrix; // for (int i = 0; i < m_matrices.Length; ++i) // { // m_matrices[i] = inverse[i] * Joints[i].Matrix * rootInverse; // } // } // else { for (int i = 0; i < m_matrices.Length; ++i) { var inv = i < inverse.Length ? inverse[i] : Joints[i].InverseMatrix; m_matrices[i] = inv * Joints[i].Matrix; } } if (vertexBuffer != null) { Apply(arrayManager, vertexBuffer); } }
public void Replace(INativeArrayManager arrayManager, Node src, Node dst) { var removeIndex = Joints.IndexOf(src); if (removeIndex >= 0) { Joints[removeIndex] = dst; // エクスポート時に再計算させる CalcInverseMatrices(arrayManager); } }
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); } }
private static VrmLib.Skin CreateSkin(INativeArrayManager arrayManager, SkinnedMeshRenderer skinnedMeshRenderer, Dictionary <GameObject, VrmLib.Node> nodes, GameObject root) { if (skinnedMeshRenderer.bones == null || skinnedMeshRenderer.bones.Length == 0) { return(null); } var skin = new VrmLib.Skin(); skin.InverseMatrices = ToBufferAccessor(arrayManager, skinnedMeshRenderer.sharedMesh.bindposes); if (skinnedMeshRenderer.rootBone != null) { skin.Root = nodes[skinnedMeshRenderer.rootBone.gameObject]; } skin.Joints = skinnedMeshRenderer.bones.Select(x => nodes[x.gameObject]).ToList(); return(skin); }
/// <summary> /// GameObject to VrmLib.Model /// </summary> /// <param name="root"></param> /// <returns></returns> public VrmLib.Model Export(INativeArrayManager arrayManager, GameObject root) { Model = new VrmLib.Model(VrmLib.Coordinates.Unity); _Export(arrayManager, root); // humanoid { var humanoid = root.GetComponent <UniHumanoid.Humanoid>(); if (humanoid is null) { humanoid = root.AddComponent <UniHumanoid.Humanoid>(); humanoid.AssignBonesFromAnimator(); } foreach (HumanBodyBones humanBoneType in Enum.GetValues(typeof(HumanBodyBones))) { var transform = humanoid.GetBoneTransform(humanBoneType); if (transform != null && Nodes.TryGetValue(transform.gameObject, out VrmLib.Node node)) { switch (humanBoneType) { // https://github.com/vrm-c/vrm-specification/issues/380 case HumanBodyBones.LeftThumbProximal: node.HumanoidBone = VrmLib.HumanoidBones.leftThumbMetacarpal; break; case HumanBodyBones.LeftThumbIntermediate: node.HumanoidBone = VrmLib.HumanoidBones.leftThumbProximal; break; case HumanBodyBones.RightThumbProximal: node.HumanoidBone = VrmLib.HumanoidBones.rightThumbMetacarpal; break; case HumanBodyBones.RightThumbIntermediate: node.HumanoidBone = VrmLib.HumanoidBones.rightThumbProximal; break; default: node.HumanoidBone = (VrmLib.HumanoidBones)Enum.Parse(typeof(VrmLib.HumanoidBones), humanBoneType.ToString(), true); break; } } } } return(Model); }
static NativeArray <byte> RestoreSparseAccessorUInt16 <T>(INativeArrayManager arrayManager, NativeArray <byte> bytes, int accessorCount, NativeArray <byte> indicesBytes, NativeArray <byte> valuesBytes) where T : struct { var stride = Marshal.SizeOf(typeof(T)); if (bytes.Length == 0) { bytes = arrayManager.CreateNativeArray <byte>(accessorCount * stride); } var dst = bytes.Reinterpret <T>(1); var indices = indicesBytes.Reinterpret <UInt16>(1); var values = valuesBytes.Reinterpret <T>(1); for (int i = 0; i < indices.Length; ++i) { var index = indices[i]; var value = values[i]; dst[index] = value; } return(bytes); }
public void CalcInverseMatrices(INativeArrayManager arrayManager) { // var root = Root; // if (root == null) // { // root = Joints[0].Ancestors().Last(); // } // root.CalcWorldMatrix(Matrix4x4.identity, true); // calc inverse bind matrices var matricesBytes = arrayManager.CreateNativeArray <Byte>(Marshal.SizeOf(typeof(Matrix4x4)) * Joints.Count); var matrices = matricesBytes.Reinterpret <Matrix4x4>(1); for (int i = 0; i < Joints.Count; ++i) { // var w = Joints[i].Matrix; // Matrix4x4.Invert(w, out Matrix4x4 inv); if (Joints[i] != null) { matrices[i] = Joints[i].InverseMatrix; } } InverseMatrices = new BufferAccessor(arrayManager, matricesBytes, AccessorValueType.FLOAT, AccessorVectorType.MAT4, Joints.Count); }
VrmLib.Model _Export(INativeArrayManager arrayManager, GameObject root) { if (Model == null) { Model = new VrmLib.Model(VrmLib.Coordinates.Unity); } // node { Model.Root.Name = root.name; CreateNodes(root.transform, Model.Root, Nodes); Model.Nodes = Nodes .Where(x => x.Value != Model.Root) .Select(x => x.Value).ToList(); } // material and textures var rendererComponents = root.GetComponentsInChildren <Renderer>(); { foreach (var renderer in rendererComponents) { var materials = renderer.sharedMaterials; // avoid copy foreach (var material in materials) { if (Materials.Contains(material)) { continue; } Model.Materials.Add(material); Materials.Add(material); } } } // mesh { foreach (var renderer in rendererComponents) { if (renderer is SkinnedMeshRenderer skinnedMeshRenderer) { if (MeshCanExport(skinnedMeshRenderer.sharedMesh)) { var mesh = CreateMesh(arrayManager, skinnedMeshRenderer.sharedMesh, skinnedMeshRenderer, Materials); var skin = CreateSkin(arrayManager, skinnedMeshRenderer, Nodes, root); if (skin != null) { // blendshape only で skinning が無いやつがある mesh.Skin = skin; Model.Skins.Add(mesh.Skin); } Model.MeshGroups.Add(mesh); Nodes[renderer.gameObject].MeshGroup = mesh; Meshes.Add(skinnedMeshRenderer.sharedMesh, mesh); } } else if (renderer is MeshRenderer meshRenderer) { var filter = meshRenderer.gameObject.GetComponent <MeshFilter>(); if (filter != null && MeshCanExport(filter.sharedMesh)) { var mesh = CreateMesh(arrayManager, filter.sharedMesh, meshRenderer, Materials); Model.MeshGroups.Add(mesh); Nodes[renderer.gameObject].MeshGroup = mesh; if (!Meshes.ContainsKey(filter.sharedMesh)) { Meshes.Add(filter.sharedMesh, mesh); } } } } } return(Model); }
private static BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, Matrix4x4[] matrixes) { return(ToBufferAccessor(arrayManager, matrixes, AccessorValueType.FLOAT, AccessorVectorType.MAT4)); }
private static BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, int[] scalars) { return(ToBufferAccessor(arrayManager, scalars, AccessorValueType.UNSIGNED_INT, AccessorVectorType.SCALAR)); }
private static BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, Vector2[] vectors) { return(ToBufferAccessor(arrayManager, vectors, AccessorValueType.FLOAT, AccessorVectorType.VEC2)); }
private static BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, Color[] colors) { return(ToBufferAccessor(arrayManager, colors, AccessorValueType.FLOAT, AccessorVectorType.VEC4)); }
private static BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, SkinJoints[] values) { return(ToBufferAccessor(arrayManager, values, AccessorValueType.UNSIGNED_SHORT, AccessorVectorType.VEC4)); }
private static VrmLib.MeshGroup CreateMesh(INativeArrayManager arrayManager, UnityEngine.Mesh mesh, Renderer renderer, List <UnityEngine.Material> materials) { var meshGroup = new VrmLib.MeshGroup(mesh.name); var vrmMesh = new VrmLib.Mesh(); vrmMesh.VertexBuffer = new VrmLib.VertexBuffer(); vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.PositionKey, ToBufferAccessor(arrayManager, mesh.vertices)); if (mesh.boneWeights.Length == mesh.vertexCount) { vrmMesh.VertexBuffer.Add( VrmLib.VertexBuffer.WeightKey, ToBufferAccessor(arrayManager, mesh.boneWeights.Select(x => new Vector4(x.weight0, x.weight1, x.weight2, x.weight3)).ToArray() )); vrmMesh.VertexBuffer.Add( VrmLib.VertexBuffer.JointKey, ToBufferAccessor(arrayManager, mesh.boneWeights.Select(x => new SkinJoints((ushort)x.boneIndex0, (ushort)x.boneIndex1, (ushort)x.boneIndex2, (ushort)x.boneIndex3)).ToArray() )); } if (mesh.uv.Length == mesh.vertexCount) { vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.TexCoordKey, ToBufferAccessor(arrayManager, mesh.uv)); } if (mesh.normals.Length == mesh.vertexCount) { vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.NormalKey, ToBufferAccessor(arrayManager, mesh.normals)); } if (mesh.colors.Length == mesh.vertexCount) { vrmMesh.VertexBuffer.Add(VrmLib.VertexBuffer.ColorKey, ToBufferAccessor(arrayManager, mesh.colors)); } vrmMesh.IndexBuffer = ToBufferAccessor(arrayManager, mesh.triangles); int offset = 0; for (int i = 0; i < mesh.subMeshCount; i++) { #if UNITY_2019 var subMesh = mesh.GetSubMesh(i); try { vrmMesh.Submeshes.Add(new VrmLib.Submesh(offset, subMesh.indexCount, materials.IndexOf(renderer.sharedMaterials[i]))); } catch (Exception ex) { Debug.LogError(ex); } offset += subMesh.indexCount; #else var triangles = mesh.GetTriangles(i); try { vrmMesh.Submeshes.Add(new VrmLib.Submesh(offset, triangles.Length, materials.IndexOf(renderer.sharedMaterials[i]))); } catch (Exception ex) { Debug.LogError(ex); } offset += triangles.Length; #endif } for (int i = 0; i < mesh.blendShapeCount; i++) { var blendShapeVertices = mesh.vertices; var usePosition = blendShapeVertices != null && blendShapeVertices.Length > 0; var blendShapeNormals = mesh.normals; var useNormal = usePosition && blendShapeNormals != null && blendShapeNormals.Length == blendShapeVertices.Length; // var useNormal = usePosition && blendShapeNormals != null && blendShapeNormals.Length == blendShapeVertices.Length && !exportOnlyBlendShapePosition; var blendShapeTangents = mesh.tangents.Select(y => (Vector3)y).ToArray(); //var useTangent = usePosition && blendShapeTangents != null && blendShapeTangents.Length == blendShapeVertices.Length; // var useTangent = false; var frameCount = mesh.GetBlendShapeFrameCount(i); mesh.GetBlendShapeFrameVertices(i, frameCount - 1, blendShapeVertices, blendShapeNormals, null); if (usePosition) { var morphTarget = new VrmLib.MorphTarget(mesh.GetBlendShapeName(i)); morphTarget.VertexBuffer = new VrmLib.VertexBuffer(); morphTarget.VertexBuffer.Add(VrmLib.VertexBuffer.PositionKey, ToBufferAccessor(arrayManager, blendShapeVertices)); vrmMesh.MorphTargets.Add(morphTarget); } } meshGroup.Meshes.Add(vrmMesh); return(meshGroup); }
public void Apply(INativeArrayManager arrayManager, VertexBuffer vertexBuffer, NativeArray <Vector3> dstPosition, NativeArray <Vector3> dstNormal) { var jointsBuffer = vertexBuffer.Joints; var joints = (jointsBuffer != null || jointsBuffer.Count == 0) ? jointsBuffer.GetAsSkinJointsArray() : arrayManager.CreateNativeArray <SkinJoints>(vertexBuffer.Count) // when MorphTarget only ; var weightsBuffer = vertexBuffer.Weights; var weights = (weightsBuffer != null || weightsBuffer.Count == 0) ? weightsBuffer.GetAsVector4Array() : arrayManager.CreateNativeArray <Vector4>(vertexBuffer.Count) // when MorphTarget only ; var positionBuffer = vertexBuffer.Positions; var position = positionBuffer.Bytes.Reinterpret <Vector3>(1); bool useNormal = false; if (dstNormal.Length > 0) { useNormal = vertexBuffer.Normals != null && dstNormal.Length == dstPosition.Length; } for (int i = 0; i < position.Length; ++i) { var j = joints[i]; var w = weights[i]; var sum = (w.x + w.y + w.z + w.w); float factor; if (sum > 0) { factor = 1.0f / sum; } else { factor = 1.0f; j = new SkinJoints(m_indexOfRoot, 0, 0, 0); w = new Vector4(1, 0, 0, 0); } if (j.Joint0 == ushort.MaxValue) { w.x = 0; } if (j.Joint1 == ushort.MaxValue) { w.y = 0; } if (j.Joint2 == ushort.MaxValue) { w.z = 0; } if (j.Joint3 == ushort.MaxValue) { w.w = 0; } { var src = position[i]; // 位置ベクトル var dst = Vector3.zero; if (w.x > 0) { dst += m_matrices[j.Joint0].MultiplyPoint(src) * w.x * factor; } if (w.y > 0) { dst += m_matrices[j.Joint1].MultiplyPoint(src) * w.y * factor; } if (w.z > 0) { dst += m_matrices[j.Joint2].MultiplyPoint(src) * w.z * factor; } if (w.w > 0) { dst += m_matrices[j.Joint3].MultiplyPoint(src) * w.w * factor; } dstPosition[i] = new Vector3(dst.x, dst.y, dst.z); } if (useNormal) { var normalBuffer = vertexBuffer.Normals; var normal = normalBuffer != null?normalBuffer.Bytes.Reinterpret <Vector3>(1) : dstNormal; var src = normal[i]; // 方向ベクトル var dst = Vector3.zero; if (w.x > 0) { dst += m_matrices[j.Joint0].MultiplyVector(src) * w.x * factor; } if (w.y > 0) { dst += m_matrices[j.Joint1].MultiplyVector(src) * w.y * factor; } if (w.z > 0) { dst += m_matrices[j.Joint2].MultiplyVector(src) * w.z * factor; } if (w.w > 0) { dst += m_matrices[j.Joint3].MultiplyVector(src) * w.w * factor; } dstNormal[i] = new Vector3(dst.x, dst.y, dst.z); } } }