예제 #1
0
        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);
        }
예제 #2
0
        /// <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);
        }
예제 #3
0
 public BufferAccessor(INativeArrayManager arrayManager, NativeArray <byte> bytes, AccessorValueType componentType, AccessorVectorType accessorType, int count)
 {
     ArrayManager  = arrayManager;
     Bytes         = bytes;
     ComponentType = componentType;
     AccessorType  = accessorType;
     Count         = count;
 }
예제 #4
0
 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
                               ));
 }
예제 #5
0
        /// <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);
            }
        }
예제 #6
0
        public void Replace(INativeArrayManager arrayManager, Node src, Node dst)
        {
            var removeIndex = Joints.IndexOf(src);

            if (removeIndex >= 0)
            {
                Joints[removeIndex] = dst;

                // エクスポート時に再計算させる
                CalcInverseMatrices(arrayManager);
            }
        }
예제 #7
0
        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);
            }
        }
예제 #8
0
        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);
        }
예제 #9
0
        /// <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);
        }
예제 #10
0
        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);
        }
예제 #11
0
        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);
        }
예제 #12
0
        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);
        }
예제 #13
0
 private static BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, Matrix4x4[] matrixes)
 {
     return(ToBufferAccessor(arrayManager, matrixes, AccessorValueType.FLOAT, AccessorVectorType.MAT4));
 }
예제 #14
0
 private static BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, int[] scalars)
 {
     return(ToBufferAccessor(arrayManager, scalars, AccessorValueType.UNSIGNED_INT, AccessorVectorType.SCALAR));
 }
예제 #15
0
 private static BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, Vector2[] vectors)
 {
     return(ToBufferAccessor(arrayManager, vectors, AccessorValueType.FLOAT, AccessorVectorType.VEC2));
 }
예제 #16
0
 private static BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, Color[] colors)
 {
     return(ToBufferAccessor(arrayManager, colors, AccessorValueType.FLOAT, AccessorVectorType.VEC4));
 }
예제 #17
0
 private static BufferAccessor ToBufferAccessor(INativeArrayManager arrayManager, SkinJoints[] values)
 {
     return(ToBufferAccessor(arrayManager, values, AccessorValueType.UNSIGNED_SHORT, AccessorVectorType.VEC4));
 }
예제 #18
0
        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);
        }
예제 #19
0
        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);
                }
            }
        }