Exemplo n.º 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));
     }
 }
Exemplo n.º 2
0
        private static VrmLib.BufferAccessor ToBufferAccessor <T>(T[] value, VrmLib.AccessorValueType valueType, VrmLib.AccessorVectorType vectorType) where T : struct
        {
            var span = SpanLike.CopyFrom(value);

            return(new VrmLib.BufferAccessor(
                       span.Bytes,
                       valueType,
                       vectorType,
                       value.Length
                       ));
        }
Exemplo n.º 3
0
        static void Vec3MinMax(ArraySegment <byte> bytes, glTFAccessor accessor)
        {
            var positions = SpanLike.Wrap <Vector3>(bytes);
            var min       = new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
            var max       = new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);

            foreach (var p in positions)
            {
                min = Vector3.Min(min, p);
                max = Vector3.Max(max, p);
            }
            accessor.min = min.ToFloat3();
            accessor.max = max.ToFloat3();
        }
Exemplo n.º 4
0
        int AddAccessor <T>(SpanLike <T> span) where T : struct
        {
            var bufferViewIndex = AddBuffer(span.Bytes);
            var accessor        = new glTFAccessor
            {
                bufferView    = bufferViewIndex,
                count         = span.Length,
                byteOffset    = 0,
                componentType = glTFExtensions.GetComponentType <T>(),
                type          = glTFExtensions.GetAccessorType <T>(),
            };
            var index = _accessors.Count;

            _accessors.Add(accessor);
            return(index);
        }
Exemplo n.º 5
0
        public void Vector4Test()
        {
            var bytes = new byte[4 * 4];
            {
                var span = SpanLike.Wrap <Single>(new ArraySegment <byte>(bytes));
                span[0] = 1.0f;
            }

            {
                var span = SpanLike.Wrap <Vector4>(new ArraySegment <byte>(bytes));
                Assert.AreEqual(1.0f, span[0].X);
            }

            {
                var span = SpanLike.Wrap <Quaternion>(new ArraySegment <byte>(bytes));
                Assert.AreEqual(1.0f, span[0].X);
            }
        }
Exemplo n.º 6
0
        static (int, int) GetVertexRange(SpanLike <int> indices)
        {
            var min = int.MaxValue;;
            var max = 0;

            foreach (var i in indices)
            {
                if (i < min)
                {
                    min = i;
                }
                if (i > max)
                {
                    max = i;
                }
            }
            return(min, max);
        }
Exemplo n.º 7
0
        static ArraySegment <byte> RestoreSparseAccessorUInt16 <T>(ArraySegment <byte> bytes, int accessorCount, ArraySegment <byte> indicesBytes, ArraySegment <byte> valuesBytes)
            where T : struct
        {
            var stride = Marshal.SizeOf(typeof(T));

            if (bytes.Count == 0)
            {
                bytes = new ArraySegment <byte>(new byte[accessorCount * stride]);
            }
            var dst = SpanLike.Wrap <T>(bytes);

            var indices = SpanLike.Wrap <UInt16>(indicesBytes);
            var values  = SpanLike.Wrap <T>(valuesBytes);

            for (int i = 0; i < indices.Length; ++i)
            {
                var index = indices[i];
                var value = values[i];
                dst[index] = value;
            }

            return(bytes);
        }
Exemplo n.º 8
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);
            }
        }
Exemplo n.º 9
0
        /// <summary>
        /// Gltfの Primitive[] の indices をひとまとめにした
        /// IndexBuffer を返す。
        /// </summary>
        public BufferAccessor CreateAccessor(int[] accessorIndices)
        {
            var totalCount = accessorIndices.Sum(x => Gltf.accessors[x].count);

            if (AccessorsIsContinuous(accessorIndices))
            {
                // IndexBufferが連続して格納されている => Slice でいける
                var firstAccessor = Gltf.accessors[accessorIndices[0]];
                var firstView     = Gltf.bufferViews[firstAccessor.bufferView];
                var start         = firstView.byteOffset + firstAccessor.byteOffset;
                if (!firstView.buffer.TryGetValidIndex(Gltf.buffers.Count, out int firstViewBufferIndex))
                {
                    throw new Exception();
                }
                var buffer = Gltf.buffers[firstViewBufferIndex];
                var bin    = GetBufferBytes(buffer);
                var bytes  = bin.Slice(start, totalCount * firstAccessor.GetStride());
                return(new BufferAccessor(bytes,
                                          (AccessorValueType)firstAccessor.componentType,
                                          EnumUtil.Parse <AccessorVectorType>(firstAccessor.type),
                                          totalCount));
            }
            else
            {
                // IndexBufferが連続して格納されていない => Int[] を作り直す
                var indices = new byte[totalCount * Marshal.SizeOf(typeof(int))];
                var span    = SpanLike.Wrap <Int32>(new ArraySegment <byte>(indices));
                var offset  = 0;
                foreach (var accessorIndex in accessorIndices)
                {
                    var accessor = Gltf.accessors[accessorIndex];
                    if (accessor.type != "SCALAR")
                    {
                        throw new ArgumentException($"accessor.type: {accessor.type}");
                    }
                    var view = Gltf.bufferViews[accessor.bufferView];
                    if (!view.buffer.TryGetValidIndex(Gltf.buffers.Count, out int viewBufferIndex))
                    {
                        throw new Exception();
                    }
                    var buffer = Gltf.buffers[viewBufferIndex];
                    var bin    = GetBufferBytes(buffer);
                    var start  = view.byteOffset + accessor.byteOffset;
                    var bytes  = bin.Slice(start, accessor.count * accessor.GetStride());
                    var dst    = SpanLike.Wrap <Int32>(new ArraySegment <byte>(indices)).Slice(offset, accessor.count);
                    offset += accessor.count;
                    switch ((AccessorValueType)accessor.componentType)
                    {
                    case AccessorValueType.UNSIGNED_BYTE:
                    {
                        var src = SpanLike.Wrap <Byte>(bytes);
                        for (int i = 0; i < src.Length; ++i)
                        {
                            // byte to int
                            dst[i] = src[i];
                        }
                    }
                    break;

                    case AccessorValueType.UNSIGNED_SHORT:
                    {
                        var src = SpanLike.Wrap <UInt16>(bytes);
                        for (int i = 0; i < src.Length; ++i)
                        {
                            // ushort to int
                            dst[i] = src[i];
                        }
                    }
                    break;

                    case AccessorValueType.UNSIGNED_INT:
                    {
                        Buffer.BlockCopy(bytes.Array, bytes.Offset, dst.Bytes.Array, dst.Bytes.Offset, bytes.Count);
                    }
                    break;

                    default:
                        throw new NotImplementedException($"accessor.componentType: {accessor.componentType}");
                    }
                }
                return(new BufferAccessor(new ArraySegment <byte>(indices), AccessorValueType.UNSIGNED_INT, AccessorVectorType.SCALAR, totalCount));
            }
        }
Exemplo n.º 10
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));
        }