コード例 #1
0
 static int ExportIndices(Vrm10Storage storage, BufferAccessor x, int offset, int count, ExportArgs option)
 {
     if (x.Count <= ushort.MaxValue)
     {
         if (x.ComponentType == AccessorValueType.UNSIGNED_INT)
         {
             // ensure ushort
             var src   = x.GetSpan <UInt32>().Slice(offset, count);
             var bytes = new byte[src.Length * 2];
             var dst   = SpanLike.Wrap <UInt16>(new ArraySegment <byte>(bytes));
             for (int i = 0; i < src.Length; ++i)
             {
                 dst[i] = (ushort)src[i];
             }
             var accessor = new BufferAccessor(new ArraySegment <byte>(bytes), AccessorValueType.UNSIGNED_SHORT, AccessorVectorType.SCALAR, count);
             return(accessor.AddAccessorTo(storage, 0, option.sparse, null, 0, count));
         }
         else
         {
             return(x.AddAccessorTo(storage, 0, option.sparse, null, offset, count));
         }
     }
     else
     {
         return(x.AddAccessorTo(storage, 0, option.sparse, null, offset, count));
     }
 }
コード例 #2
0
ファイル: ModelReader.cs プロジェクト: unitycoder/UniVRM
        public static Model Read(UniGLTF.GltfParser parser)
        {
            var storage = new Vrm10Storage(parser);
            var model   = Load(storage, Path.GetFileName(parser.TargetPath));

            model.ConvertCoordinate(Coordinates.Unity);
            return(model);
        }
コード例 #3
0
        public static Model Read(UniGLTF.GltfData data, Coordinates?coords = default)
        {
            var storage = new Vrm10Storage(data);
            var model   = Load(storage, Path.GetFileName(data.TargetPath), coords.GetValueOrDefault(Coordinates.Vrm1));

            model.ConvertCoordinate(Coordinates.Unity);
            return(model);
        }
コード例 #4
0
        public static Model CreateVrmModel(GltfParser parser)
        {
            var storage = new Vrm10Storage(parser);
            var model   = ModelLoader.Load(storage, Path.GetFileName(parser.TargetPath));

            model.ConvertCoordinate(Coordinates.Unity);
            return(model);
        }
コード例 #5
0
        public static VertexBuffer FromGltf(this gltfMorphTarget target, Vrm10Storage storage)
        {
            var b = new VertexBuffer();

            storage.CreateBufferAccessorAndAdd(target.POSITION, b, VertexBuffer.PositionKey);
            storage.CreateBufferAccessorAndAdd(target.NORMAL, b, VertexBuffer.NormalKey);
            storage.CreateBufferAccessorAndAdd(target.TANGENT, b, VertexBuffer.TangentKey);
            return(b);
        }
コード例 #6
0
        public static glTFImage ToGltf(this VrmLib.Image src, Vrm10Storage storage)
        {
            var viewIndex = storage.AppendToBuffer(0, src.Bytes, 1);
            var gltf      = storage.Gltf;

            return(new glTFImage
            {
                name = src.Name,
                mimeType = src.MimeType,
                bufferView = viewIndex,
            });
        }
コード例 #7
0
 static glTFImage GetNormalImage(Vrm10Storage storage, glTFMaterial m)
 {
     if (m.normalTexture == null)
     {
         return(null);
     }
     if (!m.normalTexture.index.TryGetValidIndex(storage.TextureCount, out int index))
     {
         return(null);
     }
     return(GetTexture(storage, index));
 }
コード例 #8
0
        public static MeshGroup FromGltf(this glTFMesh x, Vrm10Storage storage)
        {
            var group = new MeshGroup(x.name);

            if (x.primitives.Count == 1)
            {
                var primitive     = x.primitives[0];
                var mesh          = primitive.FromGltf(storage, x);
                var materialIndex = primitive.material;

                mesh.Submeshes.Add(
                    new Submesh(0, mesh.IndexBuffer.Count, materialIndex));

                group.Meshes.Add(mesh);
            }
            else if (!x.AllPrimitivesHasSameVertexBuffer())
            {
                int offset = 0;
                foreach (var primitive in x.primitives)
                {
                    var mesh          = primitive.FromGltf(storage, x);
                    var materialIndex = primitive.material;

                    mesh.Submeshes.Add(
                        new Submesh(offset, mesh.IndexBuffer.Count, materialIndex));
                    offset += mesh.IndexBuffer.Count;

                    group.Meshes.Add(mesh);
                }
            }
            else
            {
                //
                // obsolete
                //
                // for VRM

                var mesh   = x.SharedBufferFromGltf(storage);
                int offset = 0;
                foreach (var primitive in x.primitives)
                {
                    var materialIndex = primitive.material;
                    var count         = storage.Gltf.accessors[primitive.indices].count;
                    mesh.Submeshes.Add(
                        new Submesh(offset, count, materialIndex));
                    offset += count;
                }

                group.Meshes.Add(mesh);
            }

            return(group);
        }
コード例 #9
0
        public static int AddViewTo(this VrmLib.BufferAccessor self,
                                    Vrm10Storage storage, int bufferIndex,
                                    int offset = 0, int count = 0)
        {
            var stride = self.Stride;

            if (count == 0)
            {
                count = self.Count;
            }
            var slice = self.Bytes.Slice(offset * stride, count * stride);

            return(storage.AppendToBuffer(slice));
        }
コード例 #10
0
        static glTFImage GetTexture(Vrm10Storage storage, int index)
        {
            if (index < 0 || index >= storage.Gltf.textures.Count)
            {
                return(null);
            }
            var texture = storage.Gltf.textures[index];

            if (texture.source < 0 || texture.source >= storage.Gltf.images.Count)
            {
                return(null);
            }
            return(storage.Gltf.images[texture.source]);
        }
コード例 #11
0
        static Mesh FromGltf(Vrm10Storage storage, glTFMesh x, glTFPrimitives primitive, bool isShared)
        {
            var mesh = new Mesh((TopologyType)primitive.mode)
            {
                VertexBuffer = primitive.attributes.FromGltf(storage)
            };

            if (isShared)
            {
                // create joined index buffer
                mesh.IndexBuffer = storage.CreateAccessor(x.primitives.Select(y => y.indices).ToArray());
            }
            else
            {
                mesh.IndexBuffer = storage.CreateAccessor(primitive.indices);
            }

            {
                gltf_mesh_extras_targetNames.TryGet(x, out List <string> targetNames);

                for (int i = 0; i < primitive.targets.Count; ++i)
                {
                    var gltfTarget = primitive.targets[i];

                    string targetName = null;
                    {
                        targetName = targetNames[i];
                    }
                    var target = new MorphTarget(targetName)
                    {
                        VertexBuffer = gltfTarget.FromGltf(storage)
                    };

                    // validate count
                    foreach (var kv in target.VertexBuffer)
                    {
                        if (kv.Value.Count != mesh.VertexBuffer.Count)
                        {
                            throw new Exception();
                        }
                    }

                    mesh.MorphTargets.Add(target);
                }
            }

            return(mesh);
        }
コード例 #12
0
        public static int AddAccessorTo(this VrmLib.BufferAccessor self,
                                        Vrm10Storage storage, int viewIndex,
                                        Action <ArraySegment <byte>, glTFAccessor> minMax = null,
                                        int offset = 0, int count = 0)
        {
            var gltf          = storage.Gltf;
            var accessorIndex = gltf.accessors.Count;
            var accessor      = self.CreateGltfAccessor(viewIndex, count, offset * self.Stride);

            if (minMax != null)
            {
                minMax(self.Bytes, accessor);
            }
            gltf.accessors.Add(accessor);
            return(accessorIndex);
        }
コード例 #13
0
 static glTFImage GetColorImage(Vrm10Storage storage, glTFMaterial m)
 {
     if (m.pbrMetallicRoughness == null)
     {
         return(null);
     }
     if (m.pbrMetallicRoughness.baseColorTexture == null)
     {
         return(null);
     }
     if (!m.pbrMetallicRoughness.baseColorTexture.index.TryGetValidIndex(storage.TextureCount, out int index))
     {
         return(null);
     }
     return(GetTexture(storage, index));
 }
コード例 #14
0
        private Model CreateGlbModel(string path)
        {
            var bytes = File.ReadAllBytes(path);

            if (!VrmLib.Glb.TryParse(bytes, out VrmLib.Glb glb, out Exception ex))
            {
                throw ex;
            }

            VrmLib.Model       model = null;
            VrmLib.IVrmStorage storage;
            storage = new Vrm10Storage(glb.Json.Bytes, glb.Binary.Bytes);
            model   = VrmLib.ModelLoader.Load(storage, Path.GetFileNameWithoutExtension(path));
            model.ConvertCoordinate(VrmLib.Coordinates.Unity);

            return(model);
        }
コード例 #15
0
        public static VertexBuffer FromGltf(this glTFAttributes attributes,
                                            Vrm10Storage storage)
        {
            var b = new VertexBuffer();

            if (storage.TryCreateAccessor(attributes.POSITION, out BufferAccessor position))
            {
                b.Add(VertexBuffer.PositionKey, position);
            }
            else
            {
                // position required
                throw new Exception();
            }

            if (storage.TryCreateAccessor(attributes.NORMAL, out BufferAccessor normal))
            {
                b.Add(VertexBuffer.NormalKey, normal);
            }
            if (storage.TryCreateAccessor(attributes.COLOR_0, out BufferAccessor color))
            {
                b.Add(VertexBuffer.ColorKey, color);
            }
            if (storage.TryCreateAccessor(attributes.TEXCOORD_0, out BufferAccessor tex0))
            {
                b.Add(VertexBuffer.TexCoordKey, tex0);
            }
            if (storage.TryCreateAccessor(attributes.TEXCOORD_1, out BufferAccessor tex1))
            {
                b.Add(VertexBuffer.TexCoordKey2, tex1);
            }
            // if(storage.TryCreateAccessor(attributes.TANGENT, out BufferAccessor tangent))b.Add(VertexBuffer.TangentKey, tangent);
            if (storage.TryCreateAccessor(attributes.WEIGHTS_0, out BufferAccessor weights))
            {
                b.Add(VertexBuffer.WeightKey, weights);
            }
            if (storage.TryCreateAccessor(attributes.JOINTS_0, out BufferAccessor joints))
            {
                b.Add(VertexBuffer.JointKey, joints);
            }

            return(b);
        }
コード例 #16
0
        public static VrmLib.Image FromGltf(this glTFImage x, Vrm10Storage storage)
        {
            if (x.bufferView == -1)
            {
                // 外部参照?
                throw new Exception();
            }

            var view = storage.Gltf.bufferViews[x.bufferView];

            var buffer = storage.Gltf.buffers[view.buffer];

            // テクスチャの用途を調べる
            var usage = default(VrmLib.ImageUsage);

            foreach (var material in storage.Gltf.materials)
            {
                var colorImage = GetColorImage(storage, material);
                if (colorImage == x)
                {
                    usage |= VrmLib.ImageUsage.Color;
                }

                var normalImage = GetNormalImage(storage, material);
                if (normalImage == x)
                {
                    usage |= VrmLib.ImageUsage.Normal;
                }
            }

            var memory = storage.GetBufferBytes(buffer);

            return(new VrmLib.Image(x.name,
                                    x.mimeType,
                                    usage,
                                    memory.Slice(view.byteOffset, view.byteLength)));
        }
コード例 #17
0
ファイル: VrmLoader.cs プロジェクト: instantrahmen/UniVRM
        public static Model CreateVrmModel(byte[] bytes, FileInfo path)
        {
            if (!Glb.TryParse(bytes, out Glb glb, out Exception ex))
            {
                throw ex;
            }

            var json = glb.Json.Bytes.ParseAsJson();

            var extensions = json["extensions"];

            foreach (var kv in extensions.ObjectItems())
            {
                switch (kv.Key.GetString())
                {
                // case "VRM":
                //     {
                //         var storage = new Vrm10Storage(glb.Json.Bytes, glb.Binary.Bytes);
                //         var model = ModelLoader.Load(storage, path.Name);
                //         model.ConvertCoordinate(Coordinates.Unity);
                //         return model;
                //     }

                case "VRMC_vrm":
                {
                    var storage = new Vrm10Storage(glb.Json.Bytes, glb.Binary.Bytes);
                    var model   = ModelLoader.Load(storage, path.Name);
                    model.ConvertCoordinate(Coordinates.Unity);
                    return(model);
                }
                }
            }

            // this is error
            // throw new NotImplementedException();
            return(null);
        }
コード例 #18
0
        /// <summary>
        /// ModelExporter.Export で作られた Model.MeshGroups[*] を GLTF 化する
        /// </summary>
        /// <param name="src"></param>
        /// <param name="materials"></param>
        /// <param name="storage"></param>
        /// <param name="option"></param>
        /// <returns></returns>
        public static glTFMesh ExportMeshGroup(this MeshGroup src, List <object> materials, Vrm10Storage storage, ExportArgs option)
        {
            var gltfMesh = new glTFMesh
            {
                name = src.Name
            };

            if (src.Meshes.Count != 1)
            {
                throw new NotImplementedException();
            }

            foreach (var prim in src.Meshes[0].ExportMeshDivided(materials, storage, option))
            {
                gltfMesh.primitives.Add(prim);
            }

            var targetNames = src.Meshes[0].MorphTargets.Select(x => x.Name).ToArray();

            gltf_mesh_extras_targetNames.Serialize(gltfMesh, targetNames);

            return(gltfMesh);
        }
コード例 #19
0
        static Model Load(Vrm10Storage storage, string rootName, Coordinates coords)
        {
            if (storage == null)
            {
                return(null);
            }

            var model = new Model(coords)
            {
                AssetVersion    = storage.AssetVersion,
                AssetGenerator  = storage.AssetGenerator,
                AssetCopyright  = storage.AssetCopyright,
                AssetMinVersion = storage.AssetMinVersion,
                Coordinates     = coords,
            };

            // node
            model.Root.Name = rootName;
            for (var i = 0; i < storage.NodeCount; ++i)
            {
                var node = storage.CreateNode(i);
                model.Nodes.Add(node);
            }
            for (var i = 0; i < model.Nodes.Count; ++i)
            {
                var parent = model.Nodes[i];
                foreach (var j in storage.GetChildNodeIndices(i))
                {
                    var child = model.Nodes[j];
                    parent.Add(child);
                }
            }
            foreach (var x in model.Nodes)
            {
                if (x.Parent == null)
                {
                    model.Root.Add(x);
                }
            }

            // skin
            model.Skins.AddRange(Enumerable.Range(0, storage.SkinCount).Select(x => storage.CreateSkin(x, model.Nodes)));

            // mesh
            model.MeshGroups.AddRange(Enumerable.Range(0, storage.MeshCount).Select(x => storage.CreateMesh(x)));

            // skin
            for (int i = 0; i < storage.NodeCount; ++i)
            {
                var(meshIndex, skinIndex) = storage.GetNodeMeshSkin(i);
                if (meshIndex >= 0 && meshIndex < model.MeshGroups.Count)
                {
                    var node = model.Nodes[i];
                    var mesh = model.MeshGroups[meshIndex];
                    node.MeshGroup = mesh;
                    if (skinIndex >= 0 && skinIndex < model.Skins.Count)
                    {
                        var skin = model.Skins[skinIndex];
                        mesh.Skin = skin;
                    }
                }
            }

            return(model);
        }
コード例 #20
0
 /// <summary>
 /// VertexBufferはひとつでIndexBufferの参照が異なる
 ///
 ///  VertexBuffer
 ///  +----------------------------------+
 ///  |                                  |
 ///  +----------------------------------+
 ///       A         A        A
 ///       |         |        |
 ///  +---------+--------+--------+
 ///  | submesh0|submesh1|submesh2|
 ///  +---------+--------+--------+
 ///  IndexBuffer
 /// </summary>
 public static Mesh SharedBufferFromGltf(this glTFMesh x, Vrm10Storage storage)
 {
     // 先頭を使う
     return(FromGltf(storage, x, x.primitives[0], true));
 }
コード例 #21
0
        public static glTFMesh ExportMeshGroup(this MeshGroup src, List <object> materials, Vrm10Storage storage, ExportArgs option)
        {
            var mesh = new glTFMesh
            {
                name = src.Name
            };

            foreach (var x in src.Meshes)
            {
                // MeshとSubmeshがGltfのPrimitiveに相当する?
                x.ExportMesh(materials, storage, mesh, option);
            }

            return(mesh);
        }
コード例 #22
0
        public static int AddAccessorTo(this VrmLib.BufferAccessor self,
                                        Vrm10Storage storage, int bufferIndex,
                                        // GltfBufferTargetType targetType,
                                        bool useSparse,
                                        Action <ArraySegment <byte>, glTFAccessor> minMax = null,
                                        int offset = 0, int count = 0)
        {
            if (self.ComponentType == VrmLib.AccessorValueType.FLOAT &&
                self.AccessorType == VrmLib.AccessorVectorType.VEC3
                )
            {
                var values = self.GetSpan <Vector3>();
                // 巨大ポリゴンのモデル対策にValueTupleの型をushort -> uint へ
                var sparseValuesWithIndex = new List <ValueTuple <int, Vector3> >();
                for (int i = 0; i < values.Length; ++i)
                {
                    var v = values[i];
                    if (v != Vector3.Zero)
                    {
                        sparseValuesWithIndex.Add((i, v));
                    }
                }

                //var status = $"{sparseIndices.Count * 14}/{values.Length * 12}";
                if (useSparse &&
                    sparseValuesWithIndex.Count > 0 && // avoid empty sparse
                    sparseValuesWithIndex.Count * 16 < values.Length * 12)
                {
                    // use sparse
                    var sparseIndexBin  = new ArraySegment <byte>(new byte[sparseValuesWithIndex.Count * 4]);
                    var sparseIndexSpan = SpanLike.Wrap <Int32>(sparseIndexBin);
                    var sparseValueBin  = new ArraySegment <byte>(new byte[sparseValuesWithIndex.Count * 12]);
                    var sparseValueSpan = SpanLike.Wrap <Vector3>(sparseValueBin);

                    for (int i = 0; i < sparseValuesWithIndex.Count; ++i)
                    {
                        var(index, value)  = sparseValuesWithIndex[i];
                        sparseIndexSpan[i] = index;
                        sparseValueSpan[i] = value;
                    }

                    var sparseIndexView = storage.AppendToBuffer(sparseIndexBin);
                    var sparseValueView = storage.AppendToBuffer(sparseValueBin);

                    var accessorIndex = storage.Gltf.accessors.Count;
                    var accessor      = new glTFAccessor
                    {
                        componentType = (glComponentType)self.ComponentType,
                        type          = self.AccessorType.ToString(),
                        count         = self.Count,
                        byteOffset    = -1,
                        sparse        = new glTFSparse
                        {
                            count   = sparseValuesWithIndex.Count,
                            indices = new glTFSparseIndices
                            {
                                componentType = (glComponentType)VrmLib.AccessorValueType.UNSIGNED_INT,
                                bufferView    = sparseIndexView,
                            },
                            values = new glTFSparseValues
                            {
                                bufferView = sparseValueView,
                            },
                        }
                    };
                    if (minMax != null)
                    {
                        minMax(sparseValueBin, accessor);
                    }
                    storage.Gltf.accessors.Add(accessor);
                    return(accessorIndex);
                }
            }

            var viewIndex = self.AddViewTo(storage, bufferIndex, offset, count);

            return(self.AddAccessorTo(storage, viewIndex, minMax, 0, count));
        }
コード例 #23
0
 /// <summary>
 /// IndexBuffer毎に異なるVertexBufferを参照する
 ///
 ///  VertexBuffer
 ///  +--------+ +--------+ +--------+
 ///  |0       | |1       | |2       |
 ///  +--------+ +--------+ +--------+
 ///       A         A        A
 ///       |         |        |
 ///  +---------+--------+--------+
 ///  | submesh0|submesh1|submesh2|
 ///  +---------+--------+--------+
 ///  IndexBuffer
 /// </summary>
 public static Mesh FromGltf(this glTFPrimitives primitive, Vrm10Storage storage, glTFMesh x)
 {
     return(FromGltf(storage, x, primitive, false));
 }
コード例 #24
0
ファイル: Vrm10Exporter.cs プロジェクト: Santarh/UniVRM
        public static IEnumerable <(glTFNode, glTFSkin)> ExportNodes(List <Node> nodes, List <MeshGroup> groups, Vrm10Storage storage, 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();
                        }
                        if (skin.InverseMatrices != null)
                        {
                            gltfSkin.inverseBindMatrices = skin.InverseMatrices.AddAccessorTo(storage, 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);
            }
        }
コード例 #25
0
        /// <summary>
        /// https://github.com/vrm-c/UniVRM/issues/800
        ///
        /// SubMesh 単位に分割する。
        /// SubMesh を Gltf の Primitive に対応させる。
        /// </summary>
        /// <param name="mesh"></param>
        /// <param name="materials"></param>
        /// <param name="storage"></param>
        /// <param name="gltfMesh"></param>
        /// <param name="option"></param>
        static IEnumerable <glTFPrimitives> ExportMeshDivided(this VrmLib.Mesh mesh, List <object> materials, Vrm10Storage storage, ExportArgs option)
        {
            var             bufferIndex   = 0;
            var             usedIndices   = new List <int>();
            var             meshIndices   = SpanLike.CopyFrom(mesh.IndexBuffer.GetAsIntArray());
            var             positions     = mesh.VertexBuffer.Positions.GetSpan <UnityEngine.Vector3>().ToArray();
            var             normals       = mesh.VertexBuffer.Normals.GetSpan <UnityEngine.Vector3>().ToArray();
            var             uv            = mesh.VertexBuffer.TexCoords.GetSpan <UnityEngine.Vector2>().ToArray();
            var             hasSkin       = mesh.VertexBuffer.Weights != null;
            var             weights       = mesh.VertexBuffer.Weights?.GetSpan <UnityEngine.Vector4>().ToArray();
            var             joints        = mesh.VertexBuffer.Joints?.GetSpan <SkinJoints>().ToArray();
            Func <int, int> getJointIndex = default;

            if (hasSkin)
            {
                getJointIndex = i =>
                {
                    return(i);
                };
            }

            foreach (var submesh in mesh.Submeshes)
            {
                var indices = meshIndices.Slice(submesh.Offset, submesh.DrawCount).ToArray();
                var hash    = new HashSet <int>(indices);

                // mesh
                // index の順に attributes を蓄える
                var buffer = new MeshExportUtil.VertexBuffer(indices.Length, getJointIndex);
                usedIndices.Clear();
                for (int k = 0; k < positions.Length; ++k)
                {
                    if (hash.Contains(k))
                    {
                        // indices から参照される頂点だけを蓄える
                        usedIndices.Add(k);
                        buffer.Push(k, positions[k], normals[k], uv[k]);
                        if (getJointIndex != null)
                        {
                            var j          = joints[k];
                            var w          = weights[k];
                            var boneWeight = new UnityEngine.BoneWeight
                            {
                                boneIndex0 = j.Joint0,
                                boneIndex1 = j.Joint1,
                                boneIndex2 = j.Joint2,
                                boneIndex3 = j.Joint3,
                                weight0    = w.x,
                                weight1    = w.y,
                                weight2    = w.z,
                                weight3    = w.w,
                            };
                            buffer.Push(boneWeight);
                        }
                    }
                }
                var materialIndex = submesh.Material;
                var gltfPrimitive = buffer.ToGltfPrimitive(storage.Gltf, bufferIndex, materialIndex, indices);

                // blendShape
                for (int j = 0; j < mesh.MorphTargets.Count; ++j)
                {
                    var blendShape = new MeshExportUtil.BlendShapeBuffer(indices.Length);

                    // index の順に attributes を蓄える
                    var morph = mesh.MorphTargets[j];
                    var blendShapePositions = morph.VertexBuffer.Positions.GetSpan <UnityEngine.Vector3>();
                    SpanLike <UnityEngine.Vector3>?blendShapeNormals = default;
                    if (morph.VertexBuffer.Normals != null)
                    {
                        blendShapeNormals = morph.VertexBuffer.Normals.GetSpan <UnityEngine.Vector3>();
                    }
                    foreach (var k in usedIndices)
                    {
                        blendShape.Push(
                            blendShapePositions[k],
                            blendShapeNormals.HasValue ? blendShapeNormals.Value[k] : UnityEngine.Vector3.zero
                            );
                    }

                    gltfPrimitive.targets.Add(blendShape.ToGltf(storage.Gltf, bufferIndex, !option.removeMorphNormal));
                }

                yield return(gltfPrimitive);
            }
        }
コード例 #26
0
        static void ExportMesh(this Mesh mesh, List <object> materials, Vrm10Storage storage, glTFMesh gltfMesh, ExportArgs option)
        {
            //
            // primitive share vertex buffer
            //
            var attributeAccessorIndexMap = mesh.VertexBuffer
                                            .ToDictionary(
                kv => kv.Key,
                kv => kv.Value.AddAccessorTo(
                    storage, 0, option.sparse,
                    kv.Key == VertexBuffer.PositionKey ? (Action <ArraySegment <byte>, glTFAccessor>)Vec3MinMax : null
                    )
                );

            List <Dictionary <string, int> > morphTargetAccessorIndexMapList = null;

            if (mesh.MorphTargets.Any())
            {
                morphTargetAccessorIndexMapList = new List <Dictionary <string, int> >();
                foreach (var morphTarget in mesh.MorphTargets)
                {
                    var dict = new Dictionary <string, int>();

                    foreach (var kv in morphTarget.VertexBuffer)
                    {
                        if (option.removeTangent && kv.Key == VertexBuffer.TangentKey)
                        {
                            // remove tangent
                            continue;
                        }
                        if (option.removeMorphNormal && kv.Key == VertexBuffer.NormalKey)
                        {
                            // normal normal
                            continue;
                        }
                        if (kv.Value.Count != mesh.VertexBuffer.Count)
                        {
                            throw new Exception("inavlid data");
                        }
                        var accessorIndex = kv.Value.AddAccessorTo(storage, 0,
                                                                   option.sparse,
                                                                   kv.Key == VertexBuffer.PositionKey ? (Action <ArraySegment <byte>, glTFAccessor>)Vec3MinMax : null);
                        dict.Add(kv.Key, accessorIndex);
                    }

                    morphTargetAccessorIndexMapList.Add(dict);
                }
            }

            var drawCountOffset = 0;

            foreach (var y in mesh.Submeshes)
            {
                // index
                // slide index buffer accessor
                var indicesAccessorIndex = ExportIndices(storage, mesh.IndexBuffer, drawCountOffset, y.DrawCount, option);
                drawCountOffset += y.DrawCount;

                var prim = new glTFPrimitives
                {
                    mode       = (int)mesh.Topology,
                    material   = y.Material,
                    indices    = indicesAccessorIndex,
                    attributes = new glTFAttributes(),
                };
                gltfMesh.primitives.Add(prim);

                // attribute
                foreach (var kv in mesh.VertexBuffer)
                {
                    var attributeAccessorIndex = attributeAccessorIndexMap[kv.Key];

                    switch (kv.Key)
                    {
                    case VertexBuffer.PositionKey: prim.attributes.POSITION = attributeAccessorIndex; break;

                    case VertexBuffer.NormalKey: prim.attributes.NORMAL = attributeAccessorIndex; break;

                    case VertexBuffer.ColorKey: prim.attributes.COLOR_0 = attributeAccessorIndex; break;

                    case VertexBuffer.TexCoordKey: prim.attributes.TEXCOORD_0 = attributeAccessorIndex; break;

                    case VertexBuffer.TexCoordKey2: prim.attributes.TEXCOORD_1 = attributeAccessorIndex; break;

                    case VertexBuffer.JointKey: prim.attributes.JOINTS_0 = attributeAccessorIndex; break;

                    case VertexBuffer.WeightKey: prim.attributes.WEIGHTS_0 = attributeAccessorIndex; break;
                    }
                }

                // morph target
                if (mesh.MorphTargets.Any())
                {
                    foreach (var(t, accessorIndexMap) in
                             Enumerable.Zip(mesh.MorphTargets, morphTargetAccessorIndexMapList, (t, v) => (t, v)))
                    {
                        var target = new gltfMorphTarget();
                        prim.targets.Add(target);

                        foreach (var kv in t.VertexBuffer)
                        {
                            if (!accessorIndexMap.TryGetValue(kv.Key, out int targetAccessorIndex))
                            {
                                continue;
                            }
                            switch (kv.Key)
                            {
                            case VertexBuffer.PositionKey:
                                target.POSITION = targetAccessorIndex;
                                break;

                            case VertexBuffer.NormalKey:
                                target.NORMAL = targetAccessorIndex;
                                break;

                            case VertexBuffer.TangentKey:
                                target.TANGENT = targetAccessorIndex;
                                break;

                            default:
                                throw new NotImplementedException();
                            }
                        }
                    }
                }
            }

            // target name
            if (mesh.MorphTargets.Any())
            {
                gltf_mesh_extras_targetNames.Serialize(gltfMesh, mesh.MorphTargets.Select(z => z.Name));
            }
        }