/// <summary> /// submeshのindexが連続した領域に格納されているかを確認する /// </summary> static bool AccessorsIsContinuous(GltfSerialization.GltfStorage storage, int[] accessorIndices) { var gltf = storage.Gltf; var firstAccessor = gltf.accessors[accessorIndices[0]]; var firstView = gltf.bufferViews[firstAccessor.bufferView]; var start = firstView.byteOffset + firstAccessor.byteOffset; var pos = start; foreach (var i in accessorIndices) { var current = gltf.accessors[i]; if (current.type != GltfAccessorType.SCALAR) { throw new ArgumentException($"accessor.type: {current.type}"); } if (firstAccessor.componentType != current.componentType) { return(false); } var view = gltf.bufferViews[current.bufferView]; if (pos != view.byteOffset + current.byteOffset) { return(false); } var begin = view.byteOffset + current.byteOffset; var byteLength = current.componentType.ByteSize() * current.type.TypeCount() * current.count; pos += byteLength; } return(true); }
public static Image FromGltf(this GltfImage x, GltfSerialization.GltfStorage storage) { var view = storage.Gltf.bufferViews[x.bufferView]; var buffer = storage.Gltf.buffers[view.buffer]; var memory = storage.GetBufferBytes(buffer); // テクスチャの用途を調べる 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; } } return(new Image(x.name, x.mimeType, usage, memory.Slice(view.byteOffset, view.byteLength))); }
public static CurveSampler FromGltf(GltfSerialization.GltfStorage storage, int inIndex, int outIndex) { return(new CurveSampler { In = storage.AccessorFromGltf(inIndex), Out = storage.AccessorFromGltf(outIndex), }); }
static GltfImage GetNormalImage(GltfSerialization.GltfStorage storage, GltfMaterial m) { if (m.normalTexture == null) { return(null); } return(GetTexture(storage, m.normalTexture.index)); }
public static void AddCurve(this Animation self, GltfSerialization.GltfStorage storage, Node node, AnimationPathType path, GltfAnimationSampler sampler) { var nodeAnimation = self.GetOrCreateNodeAnimation(node); nodeAnimation.Curves[path] = FromGltf(storage, sampler.input, sampler.output); self.UpdateChannelsAndLastTime(); }
public static VertexBuffer FromGltf(this GltfMorphTarget target, GltfSerialization.GltfStorage storage) { var b = new VertexBuffer(); CreateBufferAccessorAndAdd(storage, target.POSITION, b, VertexBuffer.PositionKey); CreateBufferAccessorAndAdd(storage, target.NORMAL, b, VertexBuffer.NormalKey); CreateBufferAccessorAndAdd(storage, target.TANGENT, b, VertexBuffer.TangentKey); return(b); }
static void CreateBufferAccessorAndAdd(GltfSerialization.GltfStorage storage, int accessorIndex, VertexBuffer b, string key) { var a = storage.AccessorFromGltf(accessorIndex); if (a != null) { b.Add(key, a); } }
static GltfImage GetColorImage(GltfSerialization.GltfStorage storage, GltfMaterial m) { if (m.pbrMetallicRoughness == null) { return(null); } if (m.pbrMetallicRoughness.baseColorTexture == null) { return(null); } return(GetTexture(storage, m.pbrMetallicRoughness.baseColorTexture.index)); }
public static BufferAccessor AccessorFromGltf(this GltfSerialization.GltfStorage storage, int accessorIndex) { if (accessorIndex < 0) { return(null); } var gltf = storage.Gltf; var accessor = gltf.accessors[accessorIndex]; var bytes = storage.GetAccessorBytes(accessorIndex); return(new BufferAccessor(bytes, (AccessorValueType)accessor.componentType, (AccessorVectorType)accessor.type, accessor.count)); }
public static VertexBuffer FromGltf(this GltfAttributes attributes, GltfSerialization.GltfStorage storage) { var b = new VertexBuffer(); b.Add(VertexBuffer.PositionKey, storage.AccessorFromGltf(attributes.POSITION)); CreateBufferAccessorAndAdd(storage, attributes.NORMAL, b, VertexBuffer.NormalKey); CreateBufferAccessorAndAdd(storage, attributes.TEXCOORD_0, b, VertexBuffer.TexCoordKey); CreateBufferAccessorAndAdd(storage, attributes.TANGENT, b, VertexBuffer.TangentKey); CreateBufferAccessorAndAdd(storage, attributes.COLOR_0, b, VertexBuffer.ColorKey); CreateBufferAccessorAndAdd(storage, attributes.JOINTS_0, b, VertexBuffer.JointKey); CreateBufferAccessorAndAdd(storage, attributes.WEIGHTS_0, b, VertexBuffer.WeightKey); return(b); }
static Mesh FromGltf(GltfSerialization.GltfStorage storage, GltfMesh x, GltfPrimitive primitive, bool isShared) { var mesh = new Mesh((TopologyType)primitive.mode) { VertexBuffer = primitive.attributes.FromGltf(storage) }; if (isShared) { // create joined index buffer mesh.IndexBuffer = storage.IndexBufferFromGltf(x.primitives.Select(y => y.indices).ToArray()); } else { mesh.IndexBuffer = storage.AccessorFromGltf(primitive.indices); } if (primitive.targets != null) { 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); }
static GltfImage GetTexture(GltfSerialization.GltfStorage 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]); }
public static Animation FromGltf(this GltfAnimation src, GltfSerialization.GltfStorage storage, List <Node> nodes) { var animation = new Animation(src.name); foreach (var ch in src.channels) { var sampler = src.samplers[ch.sampler]; var target = ch.target; var node = nodes[target.node]; animation.AddCurve(storage, node, (AnimationPathType)target.path, sampler); } return(animation); }
public static MeshGroup FromGltf(this GltfMesh x, GltfSerialization.GltfStorage 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); mesh.Submeshes.Add( new Submesh(0, mesh.IndexBuffer.Count, materials[primitive.material])); group.Meshes.Add(mesh); } else if (!x.AllPrimitivesHasSameVertexBuffer()) { int offset = 0; foreach (var primitive in x.primitives) { var mesh = primitive.FromGltf(storage, x); mesh.Submeshes.Add( new Submesh(offset, mesh.IndexBuffer.Count, materials[primitive.material])); 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 count = storage.Gltf.accessors[primitive.indices].count; mesh.Submeshes.Add( new Submesh(offset, count, materials[primitive.material])); offset += count; } group.Meshes.Add(mesh); } return(group); }
public static Model CreateVrmModel(byte[] bytes, FileInfo path) { if (!Glb.TryParse(bytes, out Glb glb, out Exception ex)) { throw ex; } var flag = VRMVersionCheck.GetVRMExtensionFlag(glb.Json.Bytes); if (flag.HasFlag(VRMExtensionFlags.Vrm10)) { var storage = new Vrm10.Vrm10Storage(glb.Json.Bytes, glb.Binary.Bytes); var model = ModelLoader.Load(storage, path.Name); model.ConvertCoordinate(Coordinates.Unity); return(model); } if (flag.HasFlag(VRMExtensionFlags.Vrm0X)) { var storage = new GltfSerialization.GltfStorage(path, glb.Json.Bytes, glb.Binary.Bytes); var model = ModelLoader.Load(storage, path.Name); // convert meta frm 0x to 10 var meta0x = model.Vrm.Meta.AvatarPermission; model.Vrm.Meta.AvatarPermission = new AvatarPermission { AvatarUsage = meta0x.AvatarUsage, CommercialUsage = meta0x.CommercialUsage, IsAllowedGameUsage = meta0x.IsAllowedGameUsage, IsAllowedPoliticalOrReligiousUsage = meta0x.IsAllowedPoliticalOrReligiousUsage, IsAllowedSexualUsage = meta0x.IsAllowedSexualUsage, IsAllowedViolentUsage = meta0x.IsAllowedViolentUsage, OtherPermissionUrl = meta0x.OtherPermissionUrl, }; model.Vrm.Meta.RedistributionLicense = new RedistributionLicense { OtherLicenseUrl = VRM0X_LICENSE_URL, }; UnityEngine.Debug.LogWarning($"convert {model.Vrm.ExporterVersion} to 1.0. please update meta information"); model.ConvertCoordinate(Coordinates.Unity, ignoreVrm: true); return(model); } throw new NotImplementedException(); }
/// <summary> /// IndexBuffer毎に異なるVertexBufferを参照する /// /// VertexBuffer /// +--------+ +--------+ +--------+ /// |0 | |1 | |2 | /// +--------+ +--------+ +--------+ /// A A A /// | | | /// +---------+--------+--------+ /// | submesh0|submesh1|submesh2| /// +---------+--------+--------+ /// IndexBuffer /// </summary> public static Mesh FromGltf(this GltfPrimitive primitive, GltfSerialization.GltfStorage storage, GltfMesh x) { return(FromGltf(storage, x, primitive, false)); }
/// <summary> /// VertexBufferはひとつでIndexBufferの参照が異なる /// /// VertexBuffer /// +----------------------------------+ /// | | /// +----------------------------------+ /// A A A /// | | | /// +---------+--------+--------+ /// | submesh0|submesh1|submesh2| /// +---------+--------+--------+ /// IndexBuffer /// </summary> public static Mesh SharedBufferFromGltf(this GltfMesh x, GltfSerialization.GltfStorage storage) { // 先頭を使う return(FromGltf(storage, x, x.primitives[0], true)); }
/// <summary> /// Gltfの Primitive[] の indices をひとまとめにした /// IndexBuffer を返す。 /// </summary> public static BufferAccessor IndexBufferFromGltf(this GltfSerialization.GltfStorage storage, int[] accessorIndices) { var gltf = storage.Gltf; var totalCount = accessorIndices.Sum(x => gltf.accessors[x].count); if (AccessorsIsContinuous(storage, accessorIndices)) { // IndexBufferが連続して格納されている => Slice でいける var firstAccessor = gltf.accessors[accessorIndices[0]]; var firstView = gltf.bufferViews[firstAccessor.bufferView]; var start = firstView.byteOffset + firstAccessor.byteOffset; var buffer = gltf.buffers[firstView.buffer]; var bin = storage.GetBufferBytes(buffer); var bytes = bin.Slice(start, totalCount * firstAccessor.GetStride()); return(new BufferAccessor(bytes, (AccessorValueType)firstAccessor.componentType, (AccessorVectorType)firstAccessor.type, totalCount)); } else { // IndexBufferが連続して格納されていない => Int[] を作り直す var indices = new byte[totalCount * Marshal.SizeOf(typeof(int))]; var span = MemoryMarshal.Cast <byte, int>(indices.AsSpan()); var offset = 0; foreach (var accessorIndex in accessorIndices) { var accessor = gltf.accessors[accessorIndex]; if (accessor.type != GltfAccessorType.SCALAR) { throw new ArgumentException($"accessor.type: {accessor.type}"); } var view = gltf.bufferViews[accessor.bufferView]; var buffer = gltf.buffers[view.buffer]; var bin = storage.GetBufferBytes(buffer); var start = view.byteOffset + accessor.byteOffset; var bytes = bin.Slice(start, accessor.count * accessor.GetStride()); var dst = MemoryMarshal.Cast <byte, int>(indices.AsSpan()).Slice(offset, accessor.count); offset += accessor.count; switch (accessor.componentType) { case GltfComponentType.UNSIGNED_BYTE: { var src = bytes.Span; for (int i = 0; i < src.Length; ++i) { // byte to int dst[i] = src[i]; } } break; case GltfComponentType.UNSIGNED_SHORT: { var src = MemoryMarshal.Cast <byte, ushort>(bytes.Span); for (int i = 0; i < src.Length; ++i) { // ushort to int dst[i] = src[i]; } } break; case GltfComponentType.UNSIGNED_INT: { var src = MemoryMarshal.Cast <byte, int>(bytes.Span); // int to int src.CopyTo(dst); } break; default: throw new NotImplementedException($"accessor.componentType: {accessor.componentType}"); } } return(new BufferAccessor(indices, AccessorValueType.UNSIGNED_INT, AccessorVectorType.SCALAR, totalCount)); } }