예제 #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   = MemoryMarshal.Cast <byte, ushort>(bytes);
             for (int i = 0; i < src.Length; ++i)
             {
                 dst[i] = (ushort)src[i];
             }
             var accessor = new BufferAccessor(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
        public static VertexBuffer FromGltf(this VrmProtobuf.target 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);
        }
예제 #3
0
        public static VertexBuffer FromGltf(this global::Google.Protobuf.Collections.MapField <string, int> attributes,
                                            Vrm10Storage storage)
        {
            var b = new VertexBuffer();

            foreach (var kv in attributes)
            {
                var accessor = storage.CreateAccessor(kv.Value);
                b.Add(kv.Key, accessor);
            }
            return(b);
        }
예제 #4
0
        public static VrmProtobuf.Image ToGltf(this Image src, Vrm10Storage storage)
        {
            var viewIndex = storage.AppendToBuffer(0, src.Bytes, 1);
            var gltf      = storage.Gltf;

            return(new VrmProtobuf.Image
            {
                Name = src.Name,
                MimeType = src.MimeType,
                BufferView = viewIndex,
            });
        }
예제 #5
0
 static VrmProtobuf.Image GetNormalImage(Vrm10Storage storage, VrmProtobuf.Material m)
 {
     if (m.NormalTexture == null)
     {
         return(null);
     }
     if (!m.NormalTexture.Index.TryGetValidIndex(storage.TextureCount, out int index))
     {
         return(null);
     }
     return(GetTexture(storage, index));
 }
예제 #6
0
        public static MeshGroup FromGltf(this VrmProtobuf.Mesh x,
                                         Vrm10Storage storage, List <Material> materials)
        {
            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.HasValue ? primitive.Material.Value : 0;

                mesh.Submeshes.Add(
                    new Submesh(0, mesh.IndexBuffer.Count, materials[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.HasValue ? primitive.Material.Value : 0;

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

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

                var mesh   = x.SharedBufferFromGltf(storage);
                int offset = 0;
                foreach (var primitive in x.Primitives)
                {
                    var materialIndex = primitive.Material.HasValue ? primitive.Material.Value : 0;
                    var count         = storage.Gltf.Accessors[primitive.Indices.Value].Count.Value;
                    mesh.Submeshes.Add(
                        new Submesh(offset, count, materials[materialIndex]));
                    offset += count;
                }

                group.Meshes.Add(mesh);
            }

            return(group);
        }
예제 #7
0
        public static int AddViewTo(this 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(bufferIndex, slice, stride));
        }
예제 #8
0
        static VrmProtobuf.Image GetTexture(Vrm10Storage storage, int index)
        {
            if (index < 0 || index >= storage.Gltf.Textures.Count)
            {
                return(null);
            }
            var texture = storage.Gltf.Textures[index];

            if (texture.Source.HasValue && texture.Source < 0 || texture.Source >= storage.Gltf.Images.Count)
            {
                return(null);
            }
            return(storage.Gltf.Images[texture.Source.Value]);
        }
예제 #9
0
        static Mesh FromGltf(Vrm10Storage storage, VrmProtobuf.Mesh x, VrmProtobuf.MeshPrimitive primitive, bool isShared)
        {
            var mesh = new Mesh((TopologyType)primitive.Mode.GetValueOrDefault())
            {
                VertexBuffer = primitive.Attributes.FromGltf(storage)
            };

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

            {
                for (int i = 0; i < primitive.Targets.Count; ++i)
                {
                    var    gltfTarget = primitive.Targets[i];
                    string targetName = null;
                    if (primitive.Extras != null &&
                        primitive.Extras.TargetNames != null &&
                        i < primitive.Extras.TargetNames.Count
                        )
                    {
                        targetName = primitive.Extras.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);
        }
예제 #10
0
 static VrmProtobuf.Image GetColorImage(Vrm10Storage storage, VrmProtobuf.Material 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));
 }
예제 #11
0
        private ModelAsset ToUnity(byte[] bytes)
        {
            if (!Glb.TryParse(bytes, out Glb glb, out Exception ex))
            {
                throw ex;
            }

            // Vrm => Model
            var storage = new Vrm10.Vrm10Storage(glb.Json.Bytes, glb.Binary.Bytes);
            var model   = ModelLoader.Load(storage, "test");

            model.ConvertCoordinate(Coordinates.Unity);
            model.RemoveSecondary();

            return(ToUnity(model));
        }
예제 #12
0
        public static int AddAccessorTo(this BufferAccessor self,
                                        Vrm10Storage storage, int viewIndex,
                                        Action <Memory <byte>, VrmProtobuf.Accessor> 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
        public static Image FromGltf(this VrmProtobuf.Image x, Vrm10Storage storage)
        {
            if (!x.BufferView.HasValue)
            {
                // 外部参照?
                throw new Exception();
            }

            var view = storage.Gltf.BufferViews[x.BufferView.Value];

            var buffer = storage.Gltf.Buffers[view.Buffer.Value];

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

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

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

            var memory = storage.GetBufferBytes(buffer);

            return(new Image(x.Name,
                             x.MimeType,
                             usage,
                             memory.Slice(view.ByteOffset.GetValueOrDefault(), view.ByteLength.Value)));
        }
예제 #14
0
        static void ExportMesh(this Mesh mesh, List <Material> materials, Vrm10Storage storage, VrmProtobuf.Mesh 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 <Memory <byte>, VrmProtobuf.Accessor>)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 <Memory <byte>, VrmProtobuf.Accessor>)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 VrmProtobuf.MeshPrimitive
                {
                    Mode     = (int)mesh.Topology,
                    Material = materials.IndexOfNullable(y.Material),
                    Indices  = indicesAccessorIndex,
                };
                gltfMesh.Primitives.Add(prim);

                // attribute
                foreach (var kv in mesh.VertexBuffer)
                {
                    var attributeAccessorIndex = attributeAccessorIndexMap[kv.Key];
                    prim.Attributes.Add(kv.Key, attributeAccessorIndex);
                }

                // morph target
                if (mesh.MorphTargets.Any())
                {
                    foreach (var(t, accessorIndexMap) in
                             Enumerable.Zip(mesh.MorphTargets, morphTargetAccessorIndexMapList, (t, v) => (t, v)))
                    {
                        var target = new VrmProtobuf.target();
                        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();
                            }
                        }
                    }

                    if (mesh.MorphTargets.Any())
                    {
                        prim.Extras = new VrmProtobuf.MeshPrimitive.Types.Extras();
                        foreach (var name in mesh.MorphTargets.Select(z => z.Name))
                        {
                            prim.Extras.TargetNames.Add(name);
                        }
                    }
                }
            }
        }
예제 #15
0
        public static int AddAccessorTo(this BufferAccessor self,
                                        Vrm10Storage storage, int bufferIndex,
                                        // GltfBufferTargetType targetType,
                                        bool useSparse,
                                        Action <Memory <byte>, VrmProtobuf.Accessor> minMax = null,
                                        int offset = 0, int count = 0)
        {
            if (self.ComponentType == AccessorValueType.FLOAT &&
                self.AccessorType == 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 byte[sparseValuesWithIndex.Count * 4].AsMemory();
                    var sparseIndexSpan = MemoryMarshal.Cast <byte, int>(sparseIndexBin.Span);
                    var sparseValueBin  = new byte[sparseValuesWithIndex.Count * 12].AsMemory();
                    var sparseValueSpan = MemoryMarshal.Cast <byte, Vector3>(sparseValueBin.Span);

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

                    var sparseIndexView = storage.AppendToBuffer(bufferIndex, sparseIndexBin, 4);
                    var sparseValueView = storage.AppendToBuffer(bufferIndex, sparseValueBin, 12);

                    var accessorIndex = storage.Gltf.Accessors.Count;
                    var accessor      = new VrmProtobuf.Accessor
                    {
                        ComponentType = (int)self.ComponentType,
                        Type          = EnumUtil.Cast <VrmProtobuf.Accessor.Types.accessorType>(self.AccessorType),
                        Count         = self.Count,
                        Sparse        = new VrmProtobuf.AccessorSparse
                        {
                            Count   = sparseValuesWithIndex.Count,
                            Indices = new VrmProtobuf.AccessorSparseIndices
                            {
                                ComponentType = (int)AccessorValueType.UNSIGNED_INT,
                                BufferView    = sparseIndexView,
                            },
                            Values = new VrmProtobuf.AccessorSparseValues
                            {
                                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));
        }
예제 #16
0
 /// <summary>
 /// VertexBufferはひとつでIndexBufferの参照が異なる
 ///
 ///  VertexBuffer
 ///  +----------------------------------+
 ///  |                                  |
 ///  +----------------------------------+
 ///       A         A        A
 ///       |         |        |
 ///  +---------+--------+--------+
 ///  | submesh0|submesh1|submesh2|
 ///  +---------+--------+--------+
 ///  IndexBuffer
 /// </summary>
 public static Mesh SharedBufferFromGltf(this VrmProtobuf.Mesh x, Vrm10Storage storage)
 {
     // 先頭を使う
     return(FromGltf(storage, x, x.Primitives[0], true));
 }
예제 #17
0
 /// <summary>
 /// IndexBuffer毎に異なるVertexBufferを参照する
 ///
 ///  VertexBuffer
 ///  +--------+ +--------+ +--------+
 ///  |0       | |1       | |2       |
 ///  +--------+ +--------+ +--------+
 ///       A         A        A
 ///       |         |        |
 ///  +---------+--------+--------+
 ///  | submesh0|submesh1|submesh2|
 ///  +---------+--------+--------+
 ///  IndexBuffer
 /// </summary>
 public static Mesh FromGltf(this VrmProtobuf.MeshPrimitive primitive, Vrm10Storage storage, VrmProtobuf.Mesh x)
 {
     return(FromGltf(storage, x, primitive, false));
 }
예제 #18
0
        public static VrmProtobuf.Mesh ExportMeshGroup(this MeshGroup src, List <Material> materials, Vrm10Storage storage, ExportArgs option)
        {
            var mesh = new VrmProtobuf.Mesh
            {
                Name = src.Name
            };

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

            return(mesh);
        }