public static async Awaitable <Material> CreateAsync(glTF gltf, int i, GetTextureAsyncFunc getTexture, bool hasVertexColor) { if (getTexture == null) { getTexture = (_x, _y) => Awaitable.FromResult <Texture2D>(default);
public static IEnumerable <(Mesh, glTFMesh, Dictionary <int, int>)> ExportMeshes(glTF gltf, int bufferIndex, List <MeshWithRenderer> unityMeshes, List <Material> unityMaterials, MeshExportSettings settings) { foreach (var unityMesh in unityMeshes) { var gltfMesh = ExportPrimitives(gltf, bufferIndex, unityMesh, unityMaterials); var targetNames = new List <string>(); var blendShapeIndexMap = new Dictionary <int, int>(); int exportBlendShapes = 0; for (int j = 0; j < unityMesh.Mesh.blendShapeCount; ++j) { var morphTarget = ExportMorphTarget(gltf, bufferIndex, unityMesh.Mesh, j, settings.UseSparseAccessorForMorphTarget, settings.ExportOnlyBlendShapePosition); if (morphTarget.POSITION < 0 && morphTarget.NORMAL < 0 && morphTarget.TANGENT < 0) { continue; } // maybe skip var blendShapeName = unityMesh.Mesh.GetBlendShapeName(j); blendShapeIndexMap.Add(j, exportBlendShapes++); targetNames.Add(blendShapeName); // // all primitive has same blendShape // for (int k = 0; k < gltfMesh.primitives.Count; ++k) { gltfMesh.primitives[k].targets.Add(morphTarget); } } gltf_mesh_extras_targetNames.Serialize(gltfMesh, targetNames); yield return(unityMesh.Mesh, gltfMesh, blendShapeIndexMap); } }
static glTFMesh ExportPrimitives(glTF gltf, int bufferIndex, Mesh mesh, Material[] materials, List <Material> unityMaterials) { var positions = mesh.vertices.Select(y => y.ReverseZ()).ToArray(); var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, positions, glBufferTarget.ARRAY_BUFFER); gltf.accessors[positionAccessorIndex].min = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray(); gltf.accessors[positionAccessorIndex].max = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray(); var normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.normals.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER); var tangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.tangents.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER); var uvAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.uv.Select(y => y.ReverseY()).ToArray(), glBufferTarget.ARRAY_BUFFER); var colorAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.colors, glBufferTarget.ARRAY_BUFFER); var boneweights = mesh.boneWeights; var weightAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y => new Vector4(y.weight0, y.weight1, y.weight2, y.weight3)).ToArray(), glBufferTarget.ARRAY_BUFFER); var jointsAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y => new UShort4((ushort)y.boneIndex0, (ushort)y.boneIndex1, (ushort)y.boneIndex2, (ushort)y.boneIndex3)).ToArray(), glBufferTarget.ARRAY_BUFFER); var attributes = new glTFAttributes { POSITION = positionAccessorIndex, }; if (normalAccessorIndex != -1) { attributes.NORMAL = normalAccessorIndex; } if (tangentAccessorIndex != -1) { attributes.TANGENT = tangentAccessorIndex; } if (uvAccessorIndex != -1) { attributes.TEXCOORD_0 = uvAccessorIndex; } if (colorAccessorIndex != -1) { attributes.COLOR_0 = colorAccessorIndex; } if (weightAccessorIndex != -1) { attributes.WEIGHTS_0 = weightAccessorIndex; } if (jointsAccessorIndex != -1) { attributes.JOINTS_0 = jointsAccessorIndex; } var gltfMesh = new glTFMesh(mesh.name); for (int j = 0; j < mesh.subMeshCount; ++j) { var indices = TriangleUtil.FlipTriangle(mesh.GetIndices(j)).Select(y => (uint)y).ToArray(); var indicesAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, indices, glBufferTarget.ELEMENT_ARRAY_BUFFER); gltfMesh.primitives.Add(new glTFPrimitives { attributes = attributes, indices = indicesAccessorIndex, mode = 4, // triangels ? material = unityMaterials.IndexOf(materials[j]) }); } return(gltfMesh); }
public static Exported FromGameObject(glTF gltf, GameObject go) { var bytesBuffer = new ArrayByteBuffer(); var bufferIndex = gltf.AddBuffer(bytesBuffer); var unityNodes = go.transform.Traverse() .Skip(1) // exclude root object for the symmetry with the importer .ToList(); #region Material var unityMaterials = unityNodes.SelectMany(x => x.GetSharedMaterials()).Where(x => x != null).Distinct().ToList(); var unityTextures = unityMaterials.SelectMany(x => x.GetTextures()).Where(x => x != null).Distinct().ToList(); for (int i = 0; i < unityTextures.Count; ++i) { var texture = unityTextures[i]; var bytesWithPath = new BytesWithPath(texture);; // add view var view = gltf.buffers[bufferIndex].Storage.Extend(bytesWithPath.Bytes, glBufferTarget.NONE); var viewIndex = gltf.AddBufferView(view); // add image var imageIndex = gltf.images.Count; gltf.images.Add(new glTFImage { bufferView = viewIndex, mimeType = bytesWithPath.Mime, }); // add sampler var filter = default(glFilter); switch (texture.filterMode) { case FilterMode.Point: filter = glFilter.NEAREST; break; default: filter = glFilter.LINEAR; break; } var wrap = default(glWrap); switch (texture.wrapMode) { case TextureWrapMode.Clamp: wrap = glWrap.CLAMP_TO_EDGE; break; case TextureWrapMode.Repeat: wrap = glWrap.REPEAT; break; #if UNITY_2017_OR_NEWER case TextureWrapMode.Mirror: wrap = glWrap.MIRRORED_REPEAT; break; #endif default: throw new NotImplementedException(); } var samplerIndex = gltf.samplers.Count; gltf.samplers.Add(new glTFTextureSampler { magFilter = filter, minFilter = filter, wrapS = wrap, wrapT = wrap, }); // add texture gltf.textures.Add(new glTFTexture { sampler = samplerIndex, source = imageIndex, }); } gltf.materials = unityMaterials.Select(x => ExportMaterial(x, unityTextures)).ToList(); #endregion #region Meshes var unityMeshes = unityNodes .Select(x => new MeshWithRenderer { Mesh = x.GetSharedMesh(), Rendererer = x.GetComponent <Renderer>(), }) .Where(x => x.Mesh != null) .ToList(); for (int i = 0; i < unityMeshes.Count; ++i) { var x = unityMeshes[i]; var mesh = x.Mesh; var materials = x.Rendererer.sharedMaterials; var positions = mesh.vertices.Select(y => y.ReverseZ()).ToArray(); var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, positions, glBufferTarget.ARRAY_BUFFER); gltf.accessors[positionAccessorIndex].min = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray(); gltf.accessors[positionAccessorIndex].max = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray(); var normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.normals.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER); var tangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.tangents.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER); var colorAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.colors.Select(y => (Vector4)y).ToArray(), glBufferTarget.ARRAY_BUFFER); var uvAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.uv.Select(y => y.ReverseY()).ToArray(), glBufferTarget.ARRAY_BUFFER); var boneweights = mesh.boneWeights; var weightAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y => new Vector4(y.weight0, y.weight1, y.weight2, y.weight3)).ToArray(), glBufferTarget.ARRAY_BUFFER); var jointsAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y => new UShort4((ushort)y.boneIndex0, (ushort)y.boneIndex1, (ushort)y.boneIndex2, (ushort)y.boneIndex3)).ToArray(), glBufferTarget.ARRAY_BUFFER); var attributes = new glTFAttributes { POSITION = positionAccessorIndex, }; if (normalAccessorIndex != -1) { attributes.NORMAL = normalAccessorIndex; } if (tangentAccessorIndex != -1) { attributes.TANGENT = tangentAccessorIndex; } if (colorAccessorIndex != -1) { attributes.COLOR_0 = colorAccessorIndex; } if (uvAccessorIndex != -1) { attributes.TEXCOORD_0 = uvAccessorIndex; } if (weightAccessorIndex != -1) { attributes.WEIGHTS_0 = weightAccessorIndex; } if (jointsAccessorIndex != -1) { attributes.JOINTS_0 = jointsAccessorIndex; } gltf.meshes.Add(new glTFMesh(mesh.name)); for (int j = 0; j < mesh.subMeshCount; ++j) { var indices = TriangleUtil.FlipTriangle(mesh.GetIndices(j)).Select(y => (uint)y).ToArray(); var indicesAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, indices, glBufferTarget.ELEMENT_ARRAY_BUFFER); gltf.meshes.Last().primitives.Add(new glTFPrimitives { attributes = attributes, indices = indicesAccessorIndex, mode = 4, // triangels ? //material = unityMaterials.IndexOf(materials[j]) material = unityMaterials.IndexOf(materials[0]) // JIA change for Maquette image entity }); } if (mesh.blendShapeCount > 0) { for (int j = 0; j < mesh.blendShapeCount; ++j) { var blendShapeVertices = mesh.vertices; var blendShpaeNormals = mesh.normals; var blendShapeTangents = mesh.tangents.Select(y => (Vector3)y).ToArray(); var blendShapeColors = mesh.colors.Select(y => (Vector4)y).ToArray(); var k = mesh.GetBlendShapeFrameCount(j); mesh.GetBlendShapeFrameVertices(j, k - 1, blendShapeVertices, blendShpaeNormals, null); var blendShapePositionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, blendShapeVertices.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER); var blendShapeNormalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, blendShpaeNormals.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER); var blendShapeTangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, blendShapeTangents.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER); var blendShapeColorAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, blendShapeColors.ToArray(), glBufferTarget.ARRAY_BUFFER); // // first primitive has whole blendShape // gltf.meshes.Last().primitives[0].targets.Add(new glTFAttributes { POSITION = blendShapePositionAccessorIndex, NORMAL = blendShapeNormalAccessorIndex, TANGENT = blendShapeTangentAccessorIndex, COLOR_0 = blendShapeColorAccessorIndex, }); } } } #endregion #region Skins var unitySkins = unityNodes .Select(x => x.GetComponent <SkinnedMeshRenderer>()).Where(x => x != null) .ToList(); gltf.nodes = unityNodes.Select(x => ExportNode(x, unityNodes, unityMeshes.Select(y => y.Mesh).ToList(), unitySkins)).ToList(); gltf.scenes = new List <gltfScene> { new gltfScene { nodes = go.transform.GetChildren().Select(x => unityNodes.IndexOf(x)).ToArray(), } }; foreach (var x in unitySkins) { var matrices = x.sharedMesh.bindposes.Select(y => y.ReverseZ()).ToArray(); var accessor = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, matrices, glBufferTarget.NONE); var skin = new glTFSkin { inverseBindMatrices = accessor, joints = x.bones.Select(y => unityNodes.IndexOf(y)).ToArray(), skeleton = unityNodes.IndexOf(x.rootBone), }; var skinIndex = gltf.skins.Count; gltf.skins.Add(skin); foreach (var z in unityNodes.Where(y => y.Has(x))) { var nodeIndex = unityNodes.IndexOf(z); gltf.nodes[nodeIndex].skin = skinIndex; } } #endregion #if UNITY_EDITOR #region Animations var animation = go.GetComponent <Animation>(); if (animation != null) { foreach (AnimationState state in animation) { var animationWithCurve = ExportAnimation(state.clip, go.transform, unityNodes); foreach (var kv in animationWithCurve.SamplerMap) { var sampler = animationWithCurve.Animation.samplers[kv.Key]; var inputAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, kv.Value.Input); sampler.input = inputAccessorIndex; var outputAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, kv.Value.Output); sampler.output = outputAccessorIndex; // modify accessors var outputAccessor = gltf.accessors[outputAccessorIndex]; var channel = animationWithCurve.Animation.channels.First(x => x.sampler == kv.Key); switch (glTFAnimationTarget.GetElementCount(channel.target.path)) { case 3: outputAccessor.type = "VEC3"; outputAccessor.count /= 3; break; case 4: outputAccessor.type = "VEC4"; outputAccessor.count /= 4; break; default: throw new NotImplementedException(); } } gltf.animations.Add(animationWithCurve.Animation); } } #endregion #endif // glb buffer gltf.buffers[bufferIndex].UpdateByteLength(); return(new Exported { Meshes = unityMeshes, Nodes = unityNodes.Select(x => x.transform).ToList(), Materials = unityMaterials, Textures = unityTextures, }); }
static gltfMorphTarget ExportMorphTarget(glTF gltf, int bufferIndex, Mesh mesh, int j, bool useSparseAccessorForMorphTarget, bool exportOnlyBlendShapePosition) { 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(j); mesh.GetBlendShapeFrameVertices(j, frameCount - 1, blendShapeVertices, blendShapeNormals, null); var blendShapePositionAccessorIndex = -1; var blendShapeNormalAccessorIndex = -1; var blendShapeTangentAccessorIndex = -1; if (useSparseAccessorForMorphTarget) { var accessorCount = blendShapeVertices.Length; var sparseIndices = Enumerable.Range(0, blendShapeVertices.Length) .Where(x => UseSparse( usePosition, blendShapeVertices[x], useNormal, blendShapeNormals[x], useTangent, blendShapeTangents[x])) .ToArray() ; if (sparseIndices.Length == 0) { usePosition = false; useNormal = false; useTangent = false; } else { Debug.LogFormat("Sparse {0}/{1}", sparseIndices.Length, mesh.vertexCount); } /* * var vertexSize = 12; * if (useNormal) vertexSize += 12; * if (useTangent) vertexSize += 24; * var sparseBytes = (4 + vertexSize) * sparseIndices.Length; * var fullBytes = (vertexSize) * blendShapeVertices.Length; * Debug.LogFormat("Export sparse: {0}/{1}bytes({2}%)", * sparseBytes, fullBytes, (int)((float)sparseBytes / fullBytes) * ); */ var sparseIndicesViewIndex = -1; if (usePosition) { sparseIndicesViewIndex = gltf.ExtendBufferAndGetViewIndex(bufferIndex, sparseIndices); blendShapeVertices = sparseIndices.Select(x => blendShapeVertices[x].ReverseZ()).ToArray(); blendShapePositionAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount, blendShapeVertices, sparseIndices, sparseIndicesViewIndex, glBufferTarget.NONE); } if (useNormal) { blendShapeNormals = sparseIndices.Select(x => blendShapeNormals[x].ReverseZ()).ToArray(); blendShapeNormalAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount, blendShapeNormals, sparseIndices, sparseIndicesViewIndex, glBufferTarget.NONE); } if (useTangent) { blendShapeTangents = sparseIndices.Select(x => blendShapeTangents[x].ReverseZ()).ToArray(); blendShapeTangentAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount, blendShapeTangents, sparseIndices, sparseIndicesViewIndex, glBufferTarget.NONE); } } else { for (int i = 0; i < blendShapeVertices.Length; ++i) { blendShapeVertices[i] = blendShapeVertices[i].ReverseZ(); } if (usePosition) { blendShapePositionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, blendShapeVertices, glBufferTarget.ARRAY_BUFFER); } if (useNormal) { for (int i = 0; i < blendShapeNormals.Length; ++i) { blendShapeNormals[i] = blendShapeNormals[i].ReverseZ(); } blendShapeNormalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, blendShapeNormals, glBufferTarget.ARRAY_BUFFER); } if (useTangent) { for (int i = 0; i < blendShapeTangents.Length; ++i) { blendShapeTangents[i] = blendShapeTangents[i].ReverseZ(); } blendShapeTangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, blendShapeTangents, glBufferTarget.ARRAY_BUFFER); } } if (blendShapePositionAccessorIndex != -1) { gltf.accessors[blendShapePositionAccessorIndex].min = blendShapeVertices.Aggregate(blendShapeVertices[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray(); gltf.accessors[blendShapePositionAccessorIndex].max = blendShapeVertices.Aggregate(blendShapeVertices[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray(); } return(new gltfMorphTarget { POSITION = blendShapePositionAccessorIndex, NORMAL = blendShapeNormalAccessorIndex, TANGENT = blendShapeTangentAccessorIndex, }); }
public void ProcessOnAnyThread(glTF gltf, IStorage storage) { var imageIndex = gltf.GetImageIndexFromTextureIndex(m_textureIndex); m_segments = gltf.GetImageBytes(storage, imageIndex, out m_textureName); }
public void GlTFToJsonTest() { var gltf = new glTF(); using (var exporter = new gltfExporter(gltf)) { exporter.Prepare(CreateSimpleScene()); exporter.Export(MeshExportSettings.Default, AssetTextureUtil.IsTextureEditorAsset, AssetTextureUtil.GetTextureBytesWithMime); } var expected = gltf.ToJson().ParseAsJson(); expected.AddKey(Utf8String.From("meshes")); expected.AddValue(default(ArraySegment <byte>), ValueNodeType.Array); expected["meshes"].AddValue(default(ArraySegment <byte>), ValueNodeType.Object); var mesh = expected["meshes"][0]; mesh.AddKey(Utf8String.From("name")); mesh.AddValue(Utf8String.From(JsonString.Quote("test")).Bytes, ValueNodeType.String); mesh.AddKey(Utf8String.From("primitives")); mesh.AddValue(default(ArraySegment <byte>), ValueNodeType.Array); mesh["primitives"].AddValue(default(ArraySegment <byte>), ValueNodeType.Object); var primitive = mesh["primitives"][0]; primitive.AddKey(Utf8String.From("mode")); primitive.AddValue(Utf8String.From("0").Bytes, ValueNodeType.Integer); primitive.AddKey(Utf8String.From("indices")); primitive.AddValue(Utf8String.From("0").Bytes, ValueNodeType.Integer); primitive.AddKey(Utf8String.From("material")); primitive.AddValue(Utf8String.From("0").Bytes, ValueNodeType.Integer); primitive.AddKey(Utf8String.From("attributes")); primitive.AddValue(default(ArraySegment <byte>), ValueNodeType.Object); primitive["attributes"].AddKey(Utf8String.From("POSITION")); primitive["attributes"].AddValue(Utf8String.From("0").Bytes, ValueNodeType.Integer); primitive.AddKey(Utf8String.From("targets")); primitive.AddValue(default(ArraySegment <byte>), ValueNodeType.Array); primitive["targets"].AddValue(default(ArraySegment <byte>), ValueNodeType.Object); primitive["targets"][0].AddKey(Utf8String.From("POSITION")); primitive["targets"][0].AddValue(Utf8String.From("1").Bytes, ValueNodeType.Integer); primitive["targets"].AddValue(default(ArraySegment <byte>), ValueNodeType.Object); primitive["targets"][1].AddKey(Utf8String.From("POSITION")); primitive["targets"][1].AddValue(Utf8String.From("2").Bytes, ValueNodeType.Integer); primitive["targets"][1].AddKey(Utf8String.From("TANGENT")); primitive["targets"][1].AddValue(Utf8String.From("0").Bytes, ValueNodeType.Integer); gltf.meshes.Add(new glTFMesh("test") { primitives = new List <glTFPrimitives> { new glTFPrimitives { indices = 0, attributes = new glTFAttributes { POSITION = 0, TANGENT = -1 // should be removed }, targets = new List <gltfMorphTarget> { new gltfMorphTarget { POSITION = 1, TANGENT = -1 // should be removed }, new gltfMorphTarget { POSITION = 2, TANGENT = 0 } } } } }); var actual = gltf.ToJson().ParseAsJson(); Assert.AreEqual(expected, actual); }
public static Exported FromGameObject(glTF gltf, GameObject go, bool useSparseAccessorForMorphTarget = false) { var bytesBuffer = new ArrayByteBuffer(new byte[50 * 1024 * 1024]); var bufferIndex = gltf.AddBuffer(bytesBuffer); if (go.transform.childCount == 0) { throw new UniGLTFException("empty root GameObject required"); } var unityNodes = go.transform.Traverse() .Skip(1) // exclude root object for the symmetry with the importer .ToList(); #region Materials and Textures var unityMaterials = unityNodes.SelectMany(x => x.GetSharedMaterials()).Where(x => x != null).Distinct().ToList(); var unityTextures = unityMaterials.SelectMany(x => x.GetTextures()).Where(x => x != null).Distinct().ToList(); for (int i = 0; i < unityTextures.Count; ++i) { var texture = unityTextures[i]; TextureIO.ExportTexture(gltf, bufferIndex, texture); } gltf.materials = unityMaterials.Select(x => MaterialIO.ExportMaterial(x, unityTextures)).ToList(); #endregion #region Meshes var unityMeshes = unityNodes .Select(x => new MeshWithRenderer { Mesh = x.GetSharedMesh(), Rendererer = x.GetComponent <Renderer>(), }) .Where(x => { if (x.Mesh == null) { return(false); } if (x.Rendererer.sharedMaterials == null || x.Rendererer.sharedMaterials.Length == 0) { return(false); } return(true); }) .ToList(); ExportMeshes(gltf, bufferIndex, unityMeshes, unityMaterials, useSparseAccessorForMorphTarget); #endregion #region Skins var unitySkins = unityNodes .Select(x => x.GetComponent <SkinnedMeshRenderer>()).Where(x => x != null) .ToList(); gltf.nodes = unityNodes.Select(x => ExportNode(x, unityNodes, unityMeshes.Select(y => y.Mesh).ToList(), unitySkins)).ToList(); gltf.scenes = new List <gltfScene> { new gltfScene { nodes = go.transform.GetChildren().Select(x => unityNodes.IndexOf(x)).ToArray(), } }; foreach (var x in unitySkins) { var matrices = x.sharedMesh.bindposes.Select(y => y.ReverseZ()).ToArray(); var accessor = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, matrices, glBufferTarget.NONE); var skin = new glTFSkin { inverseBindMatrices = accessor, joints = x.bones.Select(y => unityNodes.IndexOf(y)).ToArray(), skeleton = unityNodes.IndexOf(x.rootBone), }; var skinIndex = gltf.skins.Count; gltf.skins.Add(skin); foreach (var z in unityNodes.Where(y => y.Has(x))) { var nodeIndex = unityNodes.IndexOf(z); var node = gltf.nodes[nodeIndex]; node.skin = skinIndex; } } #endregion #if UNITY_EDITOR #region Animations var animation = go.GetComponent <Animation>(); if (animation != null) { foreach (AnimationState state in animation) { var animationWithCurve = ExportAnimation(state.clip, go.transform, unityNodes); foreach (var kv in animationWithCurve.SamplerMap) { var sampler = animationWithCurve.Animation.samplers[kv.Key]; var inputAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, kv.Value.Input); sampler.input = inputAccessorIndex; var outputAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, kv.Value.Output); sampler.output = outputAccessorIndex; // modify accessors var outputAccessor = gltf.accessors[outputAccessorIndex]; var channel = animationWithCurve.Animation.channels.First(x => x.sampler == kv.Key); switch (glTFAnimationTarget.GetElementCount(channel.target.path)) { case 3: outputAccessor.type = "VEC3"; outputAccessor.count /= 3; break; case 4: outputAccessor.type = "VEC4"; outputAccessor.count /= 4; break; default: throw new NotImplementedException(); } } gltf.animations.Add(animationWithCurve.Animation); } } #endregion #endif return(new Exported { Meshes = unityMeshes, Nodes = unityNodes.Select(x => x.transform).ToList(), Materials = unityMaterials, Textures = unityTextures, }); }
public static GetTextureParam BaseColorTexture(glTF gltf, glTFMaterial src) { return(GetTextureParam.CreateSRGB(gltf, src.pbrMetallicRoughness.baseColorTexture.index)); }
static glTFMesh ExportPrimitives(glTF gltf, int bufferIndex, string rendererName, Mesh mesh, Material[] materials, List <Material> unityMaterials) { var positions = mesh.vertices.Select(y => y.ReverseZ()).ToArray(); var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, positions, glBufferTarget.ARRAY_BUFFER); gltf.accessors[positionAccessorIndex].min = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray(); gltf.accessors[positionAccessorIndex].max = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray(); var normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.normals.Select(y => y.normalized.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER); #if GLTF_EXPORT_TANGENTS var tangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.tangents.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER); #endif var uvAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.uv.Select(y => y.ReverseUV()).ToArray(), glBufferTarget.ARRAY_BUFFER); var colorAccessorIndex = -1; var vColorState = MeshExportInfo.DetectVertexColor(mesh, materials); if (vColorState == MeshExportInfo.VertexColorState.ExistsAndIsUsed || // VColor使っている vColorState == MeshExportInfo.VertexColorState.ExistsAndMixed // VColorを使っているところと使っていないところが混在(とりあえずExportする) ) { // UniUnlit で Multiply 設定になっている colorAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.colors, glBufferTarget.ARRAY_BUFFER); } var boneweights = mesh.boneWeights; var weightAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y => new Vector4(y.weight0, y.weight1, y.weight2, y.weight3)).ToArray(), glBufferTarget.ARRAY_BUFFER); var jointsAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y => new UShort4((ushort)y.boneIndex0, (ushort)y.boneIndex1, (ushort)y.boneIndex2, (ushort)y.boneIndex3)).ToArray(), glBufferTarget.ARRAY_BUFFER); var attributes = new glTFAttributes { POSITION = positionAccessorIndex, }; if (normalAccessorIndex != -1) { attributes.NORMAL = normalAccessorIndex; } #if GLTF_EXPORT_TANGENTS if (tangentAccessorIndex != -1) { attributes.TANGENT = tangentAccessorIndex; } #endif if (uvAccessorIndex != -1) { attributes.TEXCOORD_0 = uvAccessorIndex; } if (colorAccessorIndex != -1) { attributes.COLOR_0 = colorAccessorIndex; } if (weightAccessorIndex != -1) { attributes.WEIGHTS_0 = weightAccessorIndex; } if (jointsAccessorIndex != -1) { attributes.JOINTS_0 = jointsAccessorIndex; } var gltfMesh = new glTFMesh(mesh.name); for (int j = 0; j < mesh.subMeshCount; ++j) { var indices = TriangleUtil.FlipTriangle(mesh.GetIndices(j)).Select(y => (uint)y).ToArray(); var indicesAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, indices, glBufferTarget.ELEMENT_ARRAY_BUFFER); if (j >= materials.Length) { Debug.LogWarningFormat("{0}.materials is not enough", rendererName); break; } gltfMesh.primitives.Add(new glTFPrimitives { attributes = attributes, indices = indicesAccessorIndex, mode = 4, // triangles ? material = unityMaterials.IndexOf(materials[j]) }); } return(gltfMesh); }
public static IEnumerable <(Mesh, glTFMesh, Dictionary <int, int>)> ExportMeshes(glTF gltf, int bufferIndex, List <MeshWithRenderer> unityMeshes, List <Material> unityMaterials, MeshExportSettings settings) { for (int i = 0; i < unityMeshes.Count; ++i) { var x = unityMeshes[i]; var mesh = x.Mesh; var materials = x.Renderer.sharedMaterials; var gltfMesh = ExportPrimitives(gltf, bufferIndex, x.Renderer.name, mesh, materials, unityMaterials); var blendShapeIndexMap = new Dictionary <int, int>(); int exportBlendShapes = 0; for (int j = 0; j < mesh.blendShapeCount; ++j) { var morphTarget = ExportMorphTarget(gltf, bufferIndex, mesh, j, settings.UseSparseAccessorForMorphTarget, settings.ExportOnlyBlendShapePosition); if (morphTarget.POSITION < 0 && morphTarget.NORMAL < 0 && morphTarget.TANGENT < 0) { continue; } // maybe skip blendShapeIndexMap.Add(j, exportBlendShapes++); // // all primitive has same blendShape // for (int k = 0; k < gltfMesh.primitives.Count; ++k) { gltfMesh.primitives[k].targets.Add(morphTarget); gltfMesh.primitives[k].extras.targetNames.Add(mesh.GetBlendShapeName(j)); } } yield return(mesh, gltfMesh, blendShapeIndexMap); } }
public static glTFMesh Export(glTF gltf, int bufferIndex, MeshWithRenderer unityMesh, List<Material> unityMaterials, IAxisInverter axisInverter, MeshExportSettings settings) { var mesh = unityMesh.Mesh; var gltfMesh = new glTFMesh(mesh.name); if (settings.ExportTangents) { // support しない throw new NotImplementedException(); } var positions = mesh.vertices; var normals = mesh.normals; var uv = mesh.uv; var boneWeights = mesh.boneWeights; Func<int, int> getJointIndex = null; if (boneWeights != null && boneWeights.Length == positions.Length) { getJointIndex = unityMesh.GetJointIndex; } Vector3[] blendShapePositions = new Vector3[mesh.vertexCount]; Vector3[] blendShapeNormals = new Vector3[mesh.vertexCount]; var usedIndices = new List<int>(); for (int i = 0; i < mesh.subMeshCount; ++i) { var indices = mesh.GetIndices(i); // mesh // index の順に attributes を蓄える var buffer = new MeshExportUtil.VertexBuffer(indices.Length, getJointIndex); usedIndices.Clear(); for (int k = 0; k < positions.Length; ++k) { if (indices.Contains(k)) { // indices から参照される頂点だけを蓄える usedIndices.Add(k); buffer.Push(k, axisInverter.InvertVector3(positions[k]), axisInverter.InvertVector3(normals[k]), uv[k].ReverseUV()); if (getJointIndex != null) { buffer.Push(boneWeights[k]); } } } var material = unityMesh.Renderer.sharedMaterials[i]; var materialIndex = -1; if (material != null) { materialIndex = unityMaterials.IndexOf(material); } var flipped = new List<int>(); for (int j = 0; j < indices.Length; j += 3) { var t0 = indices[j]; var t1 = indices[j + 1]; var t2 = indices[j + 2]; flipped.Add(t2); flipped.Add(t1); flipped.Add(t0); } var gltfPrimitive = buffer.ToGltfPrimitive(gltf, bufferIndex, materialIndex, flipped); // blendShape for (int j = 0; j < mesh.blendShapeCount; ++j) { var blendShape = new MeshExportUtil.BlendShapeBuffer(indices.Length); // index の順に attributes を蓄える mesh.GetBlendShapeFrameVertices(j, 0, blendShapePositions, blendShapeNormals, null); foreach (var k in usedIndices) { blendShape.Push( axisInverter.InvertVector3(blendShapePositions[k]), axisInverter.InvertVector3(blendShapeNormals[k])); } gltfPrimitive.targets.Add(blendShape.ToGltf(gltf, bufferIndex, !settings.ExportOnlyBlendShapePosition)); } gltfMesh.primitives.Add(gltfPrimitive); } var targetNames = Enumerable.Range(0, mesh.blendShapeCount).Select(x => mesh.GetBlendShapeName(x)).ToArray(); gltf_mesh_extras_targetNames.Serialize(gltfMesh, targetNames); return gltfMesh; }
public static (glTFMesh gltfMesh, Dictionary <int, int> blendShapeIndexMap) ExportMesh(glTF gltf, int bufferIndex, Mesh mesh, Renderer renderer, List <Material> exportedMaterials, MeshExportSettings meshExportSettings, IAxisInverter axisInverter) { var meshMaterials = default(Material[]); if (renderer != null) { meshMaterials = renderer.sharedMaterials; } var boneWeights = default(BoneWeight[]); var jointIndexMap = default(int[]); if (renderer is SkinnedMeshRenderer skin) { var bones = skin.bones; var uniqueBones = bones.Distinct().ToArray(); jointIndexMap = new int[bones.Length]; for (var i = 0; i < bones.Length; i++) { jointIndexMap[i] = Array.IndexOf(uniqueBones, bones[i]); } boneWeights = mesh.boneWeights; } var gltfMesh = ExportPrimitives(gltf, bufferIndex, mesh, meshMaterials, boneWeights, jointIndexMap, exportedMaterials); var targetNames = new List <string>(); var blendShapeIndexMap = new Dictionary <int, int>(); int exportBlendShapes = 0; for (int j = 0; j < mesh.blendShapeCount; ++j) { var morphTarget = ExportMorphTarget(gltf, bufferIndex, mesh, j, meshExportSettings.UseSparseAccessorForMorphTarget, meshExportSettings.ExportOnlyBlendShapePosition, axisInverter); if (morphTarget.POSITION < 0 && morphTarget.NORMAL < 0 && morphTarget.TANGENT < 0) { continue; } // maybe skip var blendShapeName = mesh.GetBlendShapeName(j); blendShapeIndexMap.Add(j, exportBlendShapes++); targetNames.Add(blendShapeName); // // all primitive has same blendShape // for (int k = 0; k < gltfMesh.primitives.Count; ++k) { gltfMesh.primitives[k].targets.Add(morphTarget); } } gltf_mesh_extras_targetNames.Serialize(gltfMesh, targetNames); return(gltfMesh, blendShapeIndexMap); }
public static AnimationClip ConvertAnimationClip(glTF gltf, glTFAnimation animation, AxisInverter inverter, glTFNode root = null) { var clip = new AnimationClip(); clip.ClearCurves(); clip.legacy = true; clip.name = animation.name; clip.wrapMode = WrapMode.Loop; foreach (var channel in animation.channels) { var relativePath = RelativePathFrom(gltf.nodes, root, gltf.nodes[channel.target.node]); switch (channel.target.path) { case glTFAnimationTarget.PATH_TRANSLATION: { var sampler = animation.samplers[channel.sampler]; var input = gltf.GetArrayFromAccessor <float>(sampler.input); var output = gltf.FlatternFloatArrayFromAccessor(sampler.output); AnimationImporterUtil.SetAnimationCurve( clip, relativePath, new string[] { "localPosition.x", "localPosition.y", "localPosition.z" }, input, output, sampler.interpolation, typeof(Transform), (values, last) => { Vector3 temp = new Vector3(values[0], values[1], values[2]); return(inverter.InvertVector3(temp).ToArray()); } ); } break; case glTFAnimationTarget.PATH_ROTATION: { var sampler = animation.samplers[channel.sampler]; var input = gltf.GetArrayFromAccessor <float>(sampler.input); var output = gltf.FlatternFloatArrayFromAccessor(sampler.output); AnimationImporterUtil.SetAnimationCurve( clip, relativePath, new string[] { "localRotation.x", "localRotation.y", "localRotation.z", "localRotation.w" }, input, output, sampler.interpolation, typeof(Transform), (values, last) => { Quaternion currentQuaternion = new Quaternion(values[0], values[1], values[2], values[3]); Quaternion lastQuaternion = new Quaternion(last[0], last[1], last[2], last[3]); return(AnimationImporterUtil.GetShortest(lastQuaternion, inverter.InvertQuaternion(currentQuaternion)).ToArray()); } ); clip.EnsureQuaternionContinuity(); } break; case glTFAnimationTarget.PATH_SCALE: { var sampler = animation.samplers[channel.sampler]; var input = gltf.GetArrayFromAccessor <float>(sampler.input); var output = gltf.FlatternFloatArrayFromAccessor(sampler.output); AnimationImporterUtil.SetAnimationCurve( clip, relativePath, new string[] { "localScale.x", "localScale.y", "localScale.z" }, input, output, sampler.interpolation, typeof(Transform), (values, last) => values); } break; case glTFAnimationTarget.PATH_WEIGHT: { var node = gltf.nodes[channel.target.node]; var mesh = gltf.meshes[node.mesh]; var primitive = mesh.primitives.FirstOrDefault(); var targets = primitive.targets; if (!gltf_mesh_extras_targetNames.TryGet(mesh, out List <string> targetNames)) { throw new Exception("glTF BlendShape Animation. targetNames invalid."); } var keyNames = targetNames .Where(x => !string.IsNullOrEmpty(x)) .Select(x => "blendShape." + x) .ToArray(); var sampler = animation.samplers[channel.sampler]; var input = gltf.GetArrayFromAccessor <float>(sampler.input); var output = gltf.GetArrayFromAccessor <float>(sampler.output); AnimationImporterUtil.SetAnimationCurve( clip, relativePath, keyNames, input, output, sampler.interpolation, typeof(SkinnedMeshRenderer), (values, last) => { for (int j = 0; j < values.Length; j++) { values[j] *= 100.0f; } return(values); }); } break; default: Debug.LogWarningFormat("unknown path: {0}", channel.target.path); break; } } return(clip); }
public static int ExtendBufferAndGetViewIndex <T>(this glTF gltf, int bufferIndex, T[] array, glBufferTarget target = glBufferTarget.NONE) where T : struct { return(ExtendBufferAndGetViewIndex(gltf, bufferIndex, new ArraySegment <T>(array), target)); }
public static GetTextureParam NormalTexture(glTF gltf, glTFMaterial src) { return(GetTextureParam.CreateNormal(gltf, src.normalTexture.index)); }
public static void Serialize(JsonFormatter f, glTF value) { f.BeginMap(); if (value.asset != null) { f.Key("asset"); Serialize_gltf_asset(f, value.asset); } if (value.buffers != null && value.buffers.Count >= 1) { f.Key("buffers"); Serialize_gltf_buffers(f, value.buffers); } if (value.bufferViews != null && value.bufferViews.Count >= 1) { f.Key("bufferViews"); Serialize_gltf_bufferViews(f, value.bufferViews); } if (value.accessors != null && value.accessors.Count >= 1) { f.Key("accessors"); Serialize_gltf_accessors(f, value.accessors); } if (value.textures != null && value.textures.Count >= 1) { f.Key("textures"); Serialize_gltf_textures(f, value.textures); } if (value.samplers != null && value.samplers.Count >= 1) { f.Key("samplers"); Serialize_gltf_samplers(f, value.samplers); } if (value.images != null && value.images.Count >= 1) { f.Key("images"); Serialize_gltf_images(f, value.images); } if (value.materials != null && value.materials.Count >= 1) { f.Key("materials"); Serialize_gltf_materials(f, value.materials); } if (value.meshes != null && value.meshes.Count >= 1) { f.Key("meshes"); Serialize_gltf_meshes(f, value.meshes); } if (value.nodes != null && value.nodes.Count >= 1) { f.Key("nodes"); Serialize_gltf_nodes(f, value.nodes); } if (value.skins != null && value.skins.Count >= 1) { f.Key("skins"); Serialize_gltf_skins(f, value.skins); } if (value.scene >= 0) { f.Key("scene"); f.Value(value.scene); } if (value.scenes != null && value.scenes.Count >= 1) { f.Key("scenes"); Serialize_gltf_scenes(f, value.scenes); } if (value.animations != null && value.animations.Count >= 1) { f.Key("animations"); Serialize_gltf_animations(f, value.animations); } if (value.cameras != null && value.cameras.Count >= 1) { f.Key("cameras"); Serialize_gltf_cameras(f, value.cameras); } if (value.extensionsUsed != null && value.extensionsUsed.Count >= 1) { f.Key("extensionsUsed"); Serialize_gltf_extensionsUsed(f, value.extensionsUsed); } if (value.extensionsRequired != null && value.extensionsRequired.Count >= 1) { f.Key("extensionsRequired"); Serialize_gltf_extensionsRequired(f, value.extensionsRequired); } if (value.extensions != null) { f.Key("extensions"); value.extensions.Serialize(f); } if (value.extras != null) { f.Key("extras"); value.extras.Serialize(f); } f.EndMap(); }
public static async Task <Material> CreateAsync(IAwaitCaller awaitCaller, glTF gltf, int i, GetTextureAsyncFunc getTexture) { if (getTexture == null) { getTexture = (IAwaitCaller _awaitCaller, glTF _gltf, GetTextureParam _param) => Task.FromResult <Texture2D>(null); } if (i < 0 || i >= gltf.materials.Count) { return(MaterialFactory.CreateMaterial(i, null, ShaderName)); } var src = gltf.materials[i]; var material = MaterialFactory.CreateMaterial(i, src, ShaderName); var standardParam = default(GetTextureParam); if (src.pbrMetallicRoughness != null || src.occlusionTexture != null) { if (src.pbrMetallicRoughness.metallicRoughnessTexture != null || src.occlusionTexture != null) { standardParam = StandardTexture(gltf, src); } if (src.pbrMetallicRoughness.baseColorFactor != null && src.pbrMetallicRoughness.baseColorFactor.Length == 4) { var color = src.pbrMetallicRoughness.baseColorFactor; material.color = (new Color(color[0], color[1], color[2], color[3])).gamma; } if (src.pbrMetallicRoughness.baseColorTexture != null && src.pbrMetallicRoughness.baseColorTexture.index != -1) { material.mainTexture = await getTexture(awaitCaller, gltf, BaseColorTexture(gltf, src)); // Texture Offset and Scale MaterialFactory.SetTextureOffsetAndScale(material, src.pbrMetallicRoughness.baseColorTexture, "_MainTex"); } if (src.pbrMetallicRoughness.metallicRoughnessTexture != null && src.pbrMetallicRoughness.metallicRoughnessTexture.index != -1) { material.EnableKeyword("_METALLICGLOSSMAP"); var texture = await getTexture(awaitCaller, gltf, standardParam); if (texture != null) { material.SetTexture(GetTextureParam.METALLIC_GLOSS_PROP, texture); } material.SetFloat("_Metallic", 1.0f); // Set 1.0f as hard-coded. See: https://github.com/dwango/UniVRM/issues/212. material.SetFloat("_GlossMapScale", 1.0f); // Texture Offset and Scale MaterialFactory.SetTextureOffsetAndScale(material, src.pbrMetallicRoughness.metallicRoughnessTexture, "_MetallicGlossMap"); } else { material.SetFloat("_Metallic", src.pbrMetallicRoughness.metallicFactor); material.SetFloat("_Glossiness", 1.0f - src.pbrMetallicRoughness.roughnessFactor); } } if (src.normalTexture != null && src.normalTexture.index != -1) { material.EnableKeyword("_NORMALMAP"); var texture = await getTexture(awaitCaller, gltf, NormalTexture(gltf, src)); if (texture != null) { material.SetTexture(GetTextureParam.NORMAL_PROP, texture); material.SetFloat("_BumpScale", src.normalTexture.scale); } // Texture Offset and Scale MaterialFactory.SetTextureOffsetAndScale(material, src.normalTexture, "_BumpMap"); } if (src.occlusionTexture != null && src.occlusionTexture.index != -1) { var texture = await getTexture(awaitCaller, gltf, standardParam); if (texture != null) { material.SetTexture(GetTextureParam.OCCLUSION_PROP, texture); material.SetFloat("_OcclusionStrength", src.occlusionTexture.strength); } // Texture Offset and Scale MaterialFactory.SetTextureOffsetAndScale(material, src.occlusionTexture, "_OcclusionMap"); } if (src.emissiveFactor != null || (src.emissiveTexture != null && src.emissiveTexture.index != -1)) { material.EnableKeyword("_EMISSION"); material.globalIlluminationFlags &= ~MaterialGlobalIlluminationFlags.EmissiveIsBlack; if (src.emissiveFactor != null && src.emissiveFactor.Length == 3) { material.SetColor("_EmissionColor", new Color(src.emissiveFactor[0], src.emissiveFactor[1], src.emissiveFactor[2])); } if (src.emissiveTexture != null && src.emissiveTexture.index != -1) { var texture = await getTexture(awaitCaller, gltf, GetTextureParam.CreateSRGB(gltf, src.emissiveTexture.index)); if (texture != null) { material.SetTexture("_EmissionMap", texture); } // Texture Offset and Scale MaterialFactory.SetTextureOffsetAndScale(material, src.emissiveTexture, "_EmissionMap"); } } BlendMode blendMode = BlendMode.Opaque; // https://forum.unity.com/threads/standard-material-shader-ignoring-setfloat-property-_mode.344557/#post-2229980 switch (src.alphaMode) { case "BLEND": blendMode = BlendMode.Fade; material.SetOverrideTag("RenderType", "Transparent"); material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); material.SetInt("_ZWrite", 0); material.DisableKeyword("_ALPHATEST_ON"); material.EnableKeyword("_ALPHABLEND_ON"); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); material.renderQueue = 3000; break; case "MASK": blendMode = BlendMode.Cutout; material.SetOverrideTag("RenderType", "TransparentCutout"); material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero); material.SetInt("_ZWrite", 1); material.SetFloat("_Cutoff", src.alphaCutoff); material.EnableKeyword("_ALPHATEST_ON"); material.DisableKeyword("_ALPHABLEND_ON"); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); material.renderQueue = 2450; break; default: // OPAQUE blendMode = BlendMode.Opaque; material.SetOverrideTag("RenderType", ""); material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero); material.SetInt("_ZWrite", 1); material.DisableKeyword("_ALPHATEST_ON"); material.DisableKeyword("_ALPHABLEND_ON"); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); material.renderQueue = -1; break; } material.SetFloat("_Mode", (float)blendMode); return(material); }
public void ProcessOnAnyThread(glTF gltf, IStorage storage) { }
void FromGameObject(glTF gltf, GameObject go, bool useSparseAccessorForMorphTarget = false) { var bytesBuffer = new ArrayByteBuffer(new byte[50 * 1024 * 1024]); var bufferIndex = gltf.AddBuffer(bytesBuffer); GameObject tmpParent = null; if (go.transform.childCount == 0) { tmpParent = new GameObject("tmpParent"); go.transform.SetParent(tmpParent.transform, true); go = tmpParent; } try { Nodes = go.transform.Traverse() .Skip(1) // exclude root object for the symmetry with the importer .ToList(); #region Materials and Textures Materials = Nodes.SelectMany(x => x.GetSharedMaterials()).Where(x => x != null).Distinct().ToList(); var unityTextures = Materials.SelectMany(x => TextureIO.GetTextures(x)).Where(x => x.Texture != null).Distinct().ToList(); TextureManager = new TextureExportManager(unityTextures.Select(x => x.Texture)); var materialExporter = CreateMaterialExporter(); gltf.materials = Materials.Select(x => materialExporter.ExportMaterial(x, TextureManager)).ToList(); for (int i = 0; i < unityTextures.Count; ++i) { var unityTexture = unityTextures[i]; TextureIO.ExportTexture(gltf, bufferIndex, TextureManager.GetExportTexture(i), unityTexture.TextureType); } #endregion #region Meshes var unityMeshes = Nodes .Select(x => new MeshWithRenderer { Mesh = x.GetSharedMesh(), Renderer = x.GetComponent <Renderer>(), }) .Where(x => { if (x.Mesh == null) { return(false); } if (x.Renderer.sharedMaterials == null || x.Renderer.sharedMaterials.Length == 0) { return(false); } return(true); }) .ToList(); MeshExporter.ExportMeshes(gltf, bufferIndex, unityMeshes, Materials, useSparseAccessorForMorphTarget); Meshes = unityMeshes.Select(x => x.Mesh).ToList(); #endregion #region Nodes and Skins var unitySkins = Nodes .Select(x => x.GetComponent <SkinnedMeshRenderer>()).Where(x => x != null && x.bones != null && x.bones.Length > 0) .ToList(); gltf.nodes = Nodes.Select(x => ExportNode(x, Nodes, unityMeshes.Select(y => y.Renderer).ToList(), unitySkins)).ToList(); gltf.scenes = new List <gltfScene> { new gltfScene { nodes = go.transform.GetChildren().Select(x => Nodes.IndexOf(x)).ToArray(), } }; foreach (var x in unitySkins) { var matrices = x.sharedMesh.bindposes.Select(y => y.ReverseZ()).ToArray(); var accessor = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, matrices, glBufferTarget.NONE); var skin = new glTFSkin { inverseBindMatrices = accessor, joints = x.bones.Select(y => Nodes.IndexOf(y)).ToArray(), skeleton = Nodes.IndexOf(x.rootBone), }; var skinIndex = gltf.skins.Count; gltf.skins.Add(skin); foreach (var z in Nodes.Where(y => y.Has(x))) { var nodeIndex = Nodes.IndexOf(z); var node = gltf.nodes[nodeIndex]; node.skin = skinIndex; } } #endregion #if UNITY_EDITOR #region Animations var clips = new List <AnimationClip>(); var animator = go.GetComponent <Animator>(); var animation = go.GetComponent <Animation>(); if (animator != null) { clips = AnimationExporter.GetAnimationClips(animator); } else if (animation != null) { clips = AnimationExporter.GetAnimationClips(animation); } if (clips.Any()) { foreach (AnimationClip clip in clips) { var animationWithCurve = AnimationExporter.Export(clip, go.transform, Nodes); foreach (var kv in animationWithCurve.SamplerMap) { var sampler = animationWithCurve.Animation.samplers[kv.Key]; var inputAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, kv.Value.Input); sampler.input = inputAccessorIndex; var outputAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, kv.Value.Output); sampler.output = outputAccessorIndex; // modify accessors var outputAccessor = gltf.accessors[outputAccessorIndex]; var channel = animationWithCurve.Animation.channels.First(x => x.sampler == kv.Key); switch (glTFAnimationTarget.GetElementCount(channel.target.path)) { case 1: outputAccessor.type = "SCALAR"; //outputAccessor.count = ; break; case 3: outputAccessor.type = "VEC3"; outputAccessor.count /= 3; break; case 4: outputAccessor.type = "VEC4"; outputAccessor.count /= 4; break; default: throw new NotImplementedException(); } } animationWithCurve.Animation.name = clip.name; gltf.animations.Add(animationWithCurve.Animation); } } #endregion #endif } finally { if (tmpParent != null) { tmpParent.transform.GetChild(0).SetParent(null); if (Application.isPlaying) { GameObject.Destroy(tmpParent); } else { GameObject.DestroyImmediate(tmpParent); } } } }
public void SameMeshButDifferentMaterialExport() { var go = new GameObject("same_mesh"); try { var shader = Shader.Find("Unlit/Color"); var cubeA = GameObject.CreatePrimitive(PrimitiveType.Cube); { cubeA.transform.SetParent(go.transform); var material = new Material(shader); material.name = "red"; material.color = Color.red; cubeA.GetComponent <Renderer>().sharedMaterial = material; } { var cubeB = GameObject.Instantiate(cubeA); cubeB.transform.SetParent(go.transform); var material = new Material(shader); material.color = Color.blue; material.name = "blue"; cubeB.GetComponent <Renderer>().sharedMaterial = material; Assert.AreEqual(cubeB.GetComponent <MeshFilter>().sharedMesh, cubeA.GetComponent <MeshFilter>().sharedMesh); } // export var gltf = new glTF(); var json = default(string); using (var exporter = new gltfExporter(gltf)) { exporter.Prepare(go); exporter.Export(UniGLTF.MeshExportSettings.Default, AssetTextureUtil.IsTextureEditorAsset, AssetTextureUtil.GetTextureBytesWithMime); json = gltf.ToJson(); } Assert.AreEqual(2, gltf.meshes.Count); var red = gltf.materials[gltf.meshes[0].primitives[0].material]; Assert.AreEqual(new float[] { 1, 0, 0, 1 }, red.pbrMetallicRoughness.baseColorFactor); var blue = gltf.materials[gltf.meshes[1].primitives[0].material]; Assert.AreEqual(new float[] { 0, 0, 1, 1 }, blue.pbrMetallicRoughness.baseColorFactor); Assert.AreEqual(2, gltf.nodes.Count); Assert.AreNotEqual(gltf.nodes[0].mesh, gltf.nodes[1].mesh); // import { var parser = new GltfParser(); parser.ParseJson(json, new SimpleStorage(new ArraySegment <byte>(new byte[1024 * 1024]))); using (var context = new ImporterContext(parser)) { //Debug.LogFormat("{0}", context.Json); context.Load(); var importedRed = context.Root.transform.GetChild(0); var importedRedMaterial = importedRed.GetComponent <Renderer>().sharedMaterial; Assert.AreEqual("red", importedRedMaterial.name); Assert.AreEqual(Color.red, importedRedMaterial.color); var importedBlue = context.Root.transform.GetChild(1); var importedBlueMaterial = importedBlue.GetComponent <Renderer>().sharedMaterial; Assert.AreEqual("blue", importedBlueMaterial.name); Assert.AreEqual(Color.blue, importedBlueMaterial.color); } } // import new version { var parser = new GltfParser(); parser.ParseJson(json, new SimpleStorage(new ArraySegment <byte>(new byte[1024 * 1024]))); //Debug.LogFormat("{0}", context.Json); using (var context = new ImporterContext(parser)) { context.Load(); var importedRed = context.Root.transform.GetChild(0); var importedRedMaterial = importedRed.GetComponent <Renderer>().sharedMaterial; Assert.AreEqual("red", importedRedMaterial.name); Assert.AreEqual(Color.red, importedRedMaterial.color); var importedBlue = context.Root.transform.GetChild(1); var importedBlueMaterial = importedBlue.GetComponent <Renderer>().sharedMaterial; Assert.AreEqual("blue", importedBlueMaterial.name); Assert.AreEqual(Color.blue, importedBlueMaterial.color); } } } finally { GameObject.DestroyImmediate(go); } }
static T[] GetAttrib <T>(this glTF self, glTFAccessor accessor, glTFBufferView view) where T : struct { return(self.GetAttrib <T>(accessor.count, accessor.byteOffset, view)); }
public static async Task <Material> CreateAsync(IAwaitCaller awaitCaller, glTF gltf, int i, GetTextureAsyncFunc getTexture, bool hasVertexColor) { if (getTexture == null) { getTexture = (_x, _y, _z) => Task.FromResult <Texture2D>(default);
public void SetSampler(glTF gltf) { SetSampler(Texture, gltf.GetSamplerFromTextureIndex(m_textureIndex)); }
static glTFMesh ExportPrimitives(glTF gltf, int bufferIndex, MeshWithRenderer unityMesh, List <Material> unityMaterials) { var mesh = unityMesh.Mesh; var materials = unityMesh.Renderer.sharedMaterials; var positions = mesh.vertices.Select(y => y.ReverseZ()).ToArray(); var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, positions, glBufferTarget.ARRAY_BUFFER); gltf.accessors[positionAccessorIndex].min = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray(); gltf.accessors[positionAccessorIndex].max = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray(); var normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.normals.Select(y => y.normalized.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER); #if GLTF_EXPORT_TANGENTS var tangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.tangents.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER); #endif var uvAccessorIndex0 = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.uv.Select(y => y.ReverseUV()).ToArray(), glBufferTarget.ARRAY_BUFFER); var uvAccessorIndex1 = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.uv2.Select(y => y.ReverseUV()).ToArray(), glBufferTarget.ARRAY_BUFFER); var colorAccessorIndex = -1; var vColorState = MeshExportInfo.DetectVertexColor(mesh, materials); if (vColorState == MeshExportInfo.VertexColorState.ExistsAndIsUsed || // VColor使っている vColorState == MeshExportInfo.VertexColorState.ExistsAndMixed // VColorを使っているところと使っていないところが混在(とりあえずExportする) ) { // UniUnlit で Multiply 設定になっている colorAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.colors, glBufferTarget.ARRAY_BUFFER); } var boneweights = mesh.boneWeights; var weightAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y => new Vector4(y.weight0, y.weight1, y.weight2, y.weight3)).ToArray(), glBufferTarget.ARRAY_BUFFER); var jointsAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y => new UShort4( (ushort)unityMesh.GetJointIndex(y.boneIndex0), (ushort)unityMesh.GetJointIndex(y.boneIndex1), (ushort)unityMesh.GetJointIndex(y.boneIndex2), (ushort)unityMesh.GetJointIndex(y.boneIndex3)) ).ToArray(), glBufferTarget.ARRAY_BUFFER); var attributes = new glTFAttributes { POSITION = positionAccessorIndex, }; if (normalAccessorIndex != -1) { attributes.NORMAL = normalAccessorIndex; } #if GLTF_EXPORT_TANGENTS if (tangentAccessorIndex != -1) { attributes.TANGENT = tangentAccessorIndex; } #endif if (uvAccessorIndex0 != -1) { attributes.TEXCOORD_0 = uvAccessorIndex0; } if (uvAccessorIndex1 != -1) { attributes.TEXCOORD_1 = uvAccessorIndex1; } if (colorAccessorIndex != -1) { attributes.COLOR_0 = colorAccessorIndex; } if (weightAccessorIndex != -1) { attributes.WEIGHTS_0 = weightAccessorIndex; } if (jointsAccessorIndex != -1) { attributes.JOINTS_0 = jointsAccessorIndex; } var gltfMesh = new glTFMesh(mesh.name); var indices = new List <uint>(); for (int j = 0; j < mesh.subMeshCount; ++j) { indices.Clear(); var triangles = mesh.GetIndices(j); if (triangles.Length == 0) { // https://github.com/vrm-c/UniVRM/issues/664 continue; } for (int i = 0; i < triangles.Length; i += 3) { var i0 = triangles[i]; var i1 = triangles[i + 1]; var i2 = triangles[i + 2]; // flip triangle indices.Add((uint)i2); indices.Add((uint)i1); indices.Add((uint)i0); } var indicesAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, indices.ToArray(), glBufferTarget.ELEMENT_ARRAY_BUFFER); if (indicesAccessorIndex < 0) { // https://github.com/vrm-c/UniVRM/issues/664 throw new Exception(); } if (j >= materials.Length) { Debug.LogWarningFormat("{0}.materials is not enough", unityMesh.Renderer.name); break; } gltfMesh.primitives.Add(new glTFPrimitives { attributes = attributes, indices = indicesAccessorIndex, mode = 4, // triangles ? material = unityMaterials.IndexOf(materials[j]) }); } return(gltfMesh); }
public void Process(glTF gltf, IStorage storage) { ProcessOnAnyThread(gltf, storage); ProcessOnMainThread(gltf); }
public static int ExportTexture(glTF gltf, int bufferIndex, Texture texture) { var bytesWithPath = new BytesWithPath(texture);; // add view var view = gltf.buffers[bufferIndex].Append(bytesWithPath.Bytes, glBufferTarget.NONE); var viewIndex = gltf.AddBufferView(view); // add image var imageIndex = gltf.images.Count; gltf.images.Add(new glTFImage { name = texture.name, bufferView = viewIndex, mimeType = bytesWithPath.Mime, }); // add sampler var filter = default(glFilter); switch (texture.filterMode) { case FilterMode.Point: filter = glFilter.NEAREST; break; default: filter = glFilter.LINEAR; break; } var wrap = default(glWrap); switch (texture.wrapMode) { case TextureWrapMode.Clamp: wrap = glWrap.CLAMP_TO_EDGE; break; case TextureWrapMode.Repeat: wrap = glWrap.REPEAT; break; #if UNITY_2017_OR_NEWER case TextureWrapMode.Mirror: wrap = glWrap.MIRRORED_REPEAT; break; #endif default: throw new NotImplementedException(); } var samplerIndex = gltf.samplers.Count; gltf.samplers.Add(new glTFTextureSampler { magFilter = filter, minFilter = filter, wrapS = wrap, wrapT = wrap, }); // add texture gltf.textures.Add(new glTFTexture { sampler = samplerIndex, source = imageIndex, }); return(imageIndex); }
public void ProcessOnMainThread(glTF gltf) { GetOrCreateTexture(); SetSampler(gltf); }
void OnExported(UniGLTF.glTF vrm) { Debug.LogFormat("exported"); }
public MaterialFactory(glTF gltf, IStorage storage, IEnumerable <(string, UnityEngine.Object)> externalMap)