public static IEnumerator BuildMeshCoroutine(ImporterContext ctx, MeshImporter.MeshContext meshContext) { var(mesh, recalculateTangents) = _BuildMesh(meshContext); if (recalculateTangents) { yield return(null); mesh.RecalculateTangents(); yield return(null); } var result = new MeshWithMaterials { Mesh = mesh, Materials = meshContext.MaterialIndices.Select(x => ctx.GetMaterial(x)).ToArray() }; yield return(null); if (meshContext.BlendShapes.Count > 0) { var emptyVertices = new Vector3[mesh.vertexCount]; foreach (var blendShape in meshContext.BlendShapes) { BuildBlendShape(mesh, meshContext, blendShape, emptyVertices); } } yield return(result); }
public static async Task <MeshWithMaterials> BuildMeshAndUploadAsync( IAwaitCaller awaitCaller, MeshData data, Func <int, Material> materialFromIndex) { Profiler.BeginSample("MeshUploader.BuildMesh"); //Debug.Log(prims.ToJson()); var mesh = new Mesh { name = data.Name }; UploadMeshVertices(data, mesh); await awaitCaller.NextFrame(); UploadMeshIndices(data, mesh); await awaitCaller.NextFrame(); // NOTE: mesh.vertices では自動的に行われていたが、SetVertexBuffer では行われないため、明示的に呼び出す. mesh.RecalculateBounds(); await awaitCaller.NextFrame(); if (!data.HasNormal) { mesh.RecalculateNormals(); await awaitCaller.NextFrame(); } mesh.RecalculateTangents(); await awaitCaller.NextFrame(); var result = new MeshWithMaterials { Mesh = mesh, Materials = data.MaterialIndices.Select(materialFromIndex).ToArray(), ShouldSetRendererNodeAsBone = data.AssignBoneWeight, }; await awaitCaller.NextFrame(); if (data.BlendShapes.Count > 0) { var emptyVertices = new Vector3[mesh.vertexCount]; foreach (var blendShape in data.BlendShapes) { await BuildBlendShapeAsync(awaitCaller, mesh, blendShape, emptyVertices); } } Profiler.EndSample(); Profiler.BeginSample("Mesh.UploadMeshData"); mesh.UploadMeshData(false); Profiler.EndSample(); return(result); }
internal static async Task <MeshWithMaterials> BuildMeshAsync( IAwaitCaller awaitCaller, Func <int, Material> ctx, MeshContext meshContext) { Profiler.BeginSample("MeshImporter.BuildMesh"); var(mesh, recalculateTangents) = BuildMesh(meshContext); Profiler.EndSample(); if (recalculateTangents) { await awaitCaller.NextFrame(); mesh.RecalculateTangents(); await awaitCaller.NextFrame(); } // 先にすべてのマテリアルを作成済みなのでテクスチャーは生成済み。Resultを使ってよい var result = new MeshWithMaterials { Mesh = mesh, Materials = meshContext.MaterialIndices.Select(ctx).ToArray() }; await awaitCaller.NextFrame(); if (meshContext.BlendShapes.Count > 0) { var emptyVertices = new Vector3[mesh.vertexCount]; foreach (var blendShape in meshContext.BlendShapes) { await BuildBlendShapeAsync(awaitCaller, mesh, blendShape, emptyVertices); } } Profiler.BeginSample("Mesh.UploadMeshData"); mesh.UploadMeshData(false); Profiler.EndSample(); return(result); }
public static MeshWithMaterials BuildMesh(ImporterContext ctx, MeshContext meshContext) { if (!meshContext.materialIndices.Any()) { meshContext.materialIndices.Add(0); } //Debug.Log(prims.ToJson()); var mesh = new Mesh(); mesh.name = meshContext.name; if (meshContext.positions.Length > UInt16.MaxValue) { #if UNITY_2017_3_OR_NEWER mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; #else Debug.LogWarningFormat("vertices {0} exceed 65535. not implemented. Unity2017.3 supports large mesh", meshContext.positions.Length); #endif } mesh.vertices = meshContext.positions; if (meshContext.normals != null && meshContext.normals.Length > 0) { mesh.normals = meshContext.normals; } else { mesh.RecalculateNormals(); } if (meshContext.tangents != null && meshContext.tangents.Length > 0) { mesh.tangents = meshContext.tangents; } else { #if UNITY_5_6_OR_NEWER mesh.RecalculateTangents(); #endif } if (meshContext.uv != null && meshContext.uv.Length > 0) { mesh.uv = meshContext.uv; } if (meshContext.colors != null && meshContext.colors.Length > 0) { mesh.colors = meshContext.colors; } if (meshContext.boneWeights != null && meshContext.boneWeights.Count > 0) { mesh.boneWeights = meshContext.boneWeights.ToArray(); } mesh.subMeshCount = meshContext.subMeshes.Count; for (int i = 0; i < meshContext.subMeshes.Count; ++i) { mesh.SetTriangles(meshContext.subMeshes[i], i); } var result = new MeshWithMaterials { Mesh = mesh, Materials = meshContext.materialIndices.Select(x => ctx.Materials[x]).ToArray() }; if (meshContext.blendShapes != null) { foreach (var blendShape in meshContext.blendShapes) { if (blendShape.Positions.Count > 0) { if (blendShape.Positions.Count == mesh.vertexCount) { mesh.AddBlendShapeFrame(blendShape.Name, FRAME_WEIGHT, blendShape.Positions.ToArray(), (meshContext.normals != null && meshContext.normals.Length == mesh.vertexCount) ? blendShape.Normals.ToArray() : null, null ); } else { Debug.LogWarningFormat("May be partial primitive has blendShape. Rquire separete mesh or extend blend shape, but not implemented: {0}", blendShape.Name); } } else { Debug.LogFormat("empty blendshape: {0}.{1}", mesh.name, blendShape.Name); // add empty blend shape for keep blend shape index mesh.AddBlendShapeFrame(blendShape.Name, FRAME_WEIGHT, //Enumerable.Range(0, mesh.vertexCount).Select(x => Vector3.zero).ToArray(), null, null, null ); } } } return(result); }
static MeshWithMaterials ImportMesh(glTF gltf, int meshIndex, glTFMesh gltfMesh, List <Material> materials, GetBlendShapeName getBlendShapeName ) { glTFAttributes lastAttributes = null; var sharedAttributes = true; foreach (var prim in gltfMesh.primitives) { if (lastAttributes != null && !prim.attributes.Equals(lastAttributes)) { sharedAttributes = false; break; } lastAttributes = prim.attributes; } var positions = new List <Vector3>(); var normals = new List <Vector3>(); var tangents = new List <Vector4>(); var colors = new List <Vector4>(); var uv = new List <Vector2>(); var boneWeights = new List <BoneWeight>(); var subMeshes = new List <int[]>(); var materialIndices = new List <int>(); BlendShape[] blendShapes = null; if (sharedAttributes) { // multiple submesh sharing same VertexBuffer { var prim = gltfMesh.primitives.First(); positions.AddRange(gltf.GetArrayFromAccessor <Vector3>(prim.attributes.POSITION).Select(x => x.ReverseZ())); // normal if (prim.attributes.NORMAL != -1) { normals.AddRange(gltf.GetArrayFromAccessor <Vector3>(prim.attributes.NORMAL).Select(x => x.ReverseZ())); } // tangent if (prim.attributes.TANGENT != -1) { tangents.AddRange(gltf.GetArrayFromAccessor <Vector4>(prim.attributes.TANGENT).Select(x => x.ReverseZ())); } // vertex color if (prim.attributes.COLOR_0 != -1) { colors.AddRange(gltf.GetArrayFromAccessor <Vector4>(prim.attributes.COLOR_0)); } // uv if (prim.attributes.TEXCOORD_0 != -1) { uv.AddRange(gltf.GetArrayFromAccessor <Vector2>(prim.attributes.TEXCOORD_0).Select(x => x.ReverseY())); } else { // for inconsistent attributes in primitives uv.AddRange(new Vector2[positions.Count]); } // skin if (prim.attributes.JOINTS_0 != -1 && prim.attributes.WEIGHTS_0 != -1) { var joints0 = gltf.GetArrayFromAccessor <UShort4>(prim.attributes.JOINTS_0); // uint4 var weights0 = gltf.GetArrayFromAccessor <Float4>(prim.attributes.WEIGHTS_0).Select(x => x.One()).ToArray(); for (int j = 0; j < joints0.Length; ++j) { var bw = new BoneWeight(); bw.boneIndex0 = joints0[j].x; bw.weight0 = weights0[j].x; bw.boneIndex1 = joints0[j].y; bw.weight1 = weights0[j].y; bw.boneIndex2 = joints0[j].z; bw.weight2 = weights0[j].z; bw.boneIndex3 = joints0[j].w; bw.weight3 = weights0[j].w; boneWeights.Add(bw); } } // blendshape if (prim.targets != null && prim.targets.Count > 0) { if (blendShapes == null) { blendShapes = prim.targets.Select((x, i) => new BlendShape(getBlendShapeName(meshIndex, i))).ToArray(); } for (int i = 0; i < prim.targets.Count; ++i) { //var name = string.Format("target{0}", i++); var primTarget = prim.targets[i]; var blendShape = blendShapes[i]; if (primTarget.POSITION != -1) { blendShape.Positions.AddRange( gltf.GetArrayFromAccessor <Vector3>(primTarget.POSITION).Select(x => x.ReverseZ()).ToArray()); } if (primTarget.NORMAL != -1) { blendShape.Normals.AddRange( gltf.GetArrayFromAccessor <Vector3>(primTarget.NORMAL).Select(x => x.ReverseZ()).ToArray()); } if (primTarget.TANGENT != -1) { blendShape.Tangents.AddRange( gltf.GetArrayFromAccessor <Vector3>(primTarget.TANGENT).Select(x => x.ReverseZ()).ToArray()); } } } } foreach (var prim in gltfMesh.primitives) { var indices = gltf.GetIndices(prim.indices).Select(x => x).ToArray(); subMeshes.Add(indices); // material materialIndices.Add(prim.material); } } else { // multiple submMesh is not sharing a VertexBuffer. // each subMesh use a independent VertexBuffer. var targets = gltfMesh.primitives[0].targets; for (int i = 1; i < gltfMesh.primitives.Count; ++i) { if (!gltfMesh.primitives[i].targets.SequenceEqual(targets)) { throw new NotImplementedException(string.Format("diffirent targets: {0} with {1}", gltfMesh.primitives[i], targets)); } } foreach (var prim in gltfMesh.primitives) { var indexOffset = positions.Count; var indexBuffer = prim.indices; var positionCount = positions.Count; positions.AddRange(gltf.GetArrayFromAccessor <Vector3>(prim.attributes.POSITION).Select(x => x.ReverseZ())); positionCount = positions.Count - positionCount; // normal if (prim.attributes.NORMAL != -1) { normals.AddRange(gltf.GetArrayFromAccessor <Vector3>(prim.attributes.NORMAL).Select(x => x.ReverseZ())); } if (prim.attributes.TANGENT != -1) { tangents.AddRange(gltf.GetArrayFromAccessor <Vector4>(prim.attributes.TANGENT).Select(x => x.ReverseZ())); } // vertex color if (prim.attributes.COLOR_0 != -1) { colors.AddRange(gltf.GetArrayFromAccessor <Vector4>(prim.attributes.COLOR_0)); } // uv if (prim.attributes.TEXCOORD_0 != -1) { uv.AddRange(gltf.GetArrayFromAccessor <Vector2>(prim.attributes.TEXCOORD_0).Select(x => x.ReverseY())); } else { // for inconsistent attributes in primitives uv.AddRange(new Vector2[positionCount]); } // skin if (prim.attributes.JOINTS_0 != -1 && prim.attributes.WEIGHTS_0 != -1) { var joints0 = gltf.GetArrayFromAccessor <UShort4>(prim.attributes.JOINTS_0); // uint4 var weights0 = gltf.GetArrayFromAccessor <Float4>(prim.attributes.WEIGHTS_0).Select(x => x.One()).ToArray(); for (int j = 0; j < joints0.Length; ++j) { var bw = new BoneWeight(); bw.boneIndex0 = joints0[j].x; bw.weight0 = weights0[j].x; bw.boneIndex1 = joints0[j].y; bw.weight1 = weights0[j].y; bw.boneIndex2 = joints0[j].z; bw.weight2 = weights0[j].z; bw.boneIndex3 = joints0[j].w; bw.weight3 = weights0[j].w; boneWeights.Add(bw); } } // blendshape if (prim.targets != null && prim.targets.Count > 0) { if (blendShapes == null) { blendShapes = prim.targets.Select((x, i) => new BlendShape(i.ToString())).ToArray(); } for (int i = 0; i < prim.targets.Count; ++i) { //var name = string.Format("target{0}", i++); var primTarget = prim.targets[i]; var blendShape = blendShapes[i]; if (primTarget.POSITION != -1) { blendShape.Positions.AddRange( gltf.GetArrayFromAccessor <Vector3>(primTarget.POSITION).Select(x => x.ReverseZ()).ToArray()); } if (primTarget.NORMAL != -1) { blendShape.Normals.AddRange( gltf.GetArrayFromAccessor <Vector3>(primTarget.NORMAL).Select(x => x.ReverseZ()).ToArray()); } if (primTarget.TANGENT != -1) { blendShape.Tangents.AddRange( gltf.GetArrayFromAccessor <Vector3>(primTarget.TANGENT).Select(x => x.ReverseZ()).ToArray()); } } } var indices = (indexBuffer >= 0) ? gltf.GetIndices(indexBuffer).Select(x => x + indexOffset).ToArray() : TriangleUtil.FlipTriangle(Enumerable.Range(0, positions.Count)).ToArray() // without index array ; subMeshes.Add(indices); // material materialIndices.Add(prim.material); } } if (!materialIndices.Any()) { materialIndices.Add(0); } //Debug.Log(prims.ToJson()); var mesh = new Mesh(); mesh.name = gltfMesh.name; if (positions.Count > UInt16.MaxValue) { #if UNITY_2017_3_OR_NEWER mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; #else Debug.LogWarningFormat("vertices {0} exceed 65535. not implemented. Unity2017.3 supports large mesh", positions.Count); #endif } mesh.vertices = positions.ToArray(); if (normals.Any()) { mesh.normals = normals.ToArray(); } else { mesh.RecalculateNormals(); } if (tangents.Any()) { mesh.tangents = tangents.ToArray(); } else { mesh.RecalculateTangents(); } if (colors.Any()) { mesh.colors = colors.ConvertAll(x => new Color(x.x, x.y, x.z, 1f)).ToArray(); } if (uv.Any()) { mesh.uv = uv.ToArray(); } if (boneWeights.Any()) { mesh.boneWeights = boneWeights.ToArray(); } mesh.subMeshCount = subMeshes.Count; for (int i = 0; i < subMeshes.Count; ++i) { mesh.SetTriangles(subMeshes[i], i); } var result = new MeshWithMaterials { Mesh = mesh, Materials = materialIndices.Select(x => materials[x]).ToArray() }; List <Material> matList = result.Materials.ToList(); matList.RemoveAll(x => x == null); result.Materials = matList.ToArray(); if (blendShapes != null) { foreach (var blendShape in blendShapes) { if (blendShape.Positions.Count > 0) { if (blendShape.Positions.Count == mesh.vertexCount) { mesh.AddBlendShapeFrame(blendShape.Name, FRAME_WEIGHT, blendShape.Positions.ToArray(), normals.Count == mesh.vertexCount ? blendShape.Normals.ToArray() : null, null ); } else { Debug.LogWarningFormat("May be partial primitive has blendShape. Rquire separete mesh or extend blend shape, but not implemented: {0}", blendShape.Name); } } } } return(result); }
public static IEnumerator BuildMeshCoroutine(ImporterContext ctx, MeshImporter.MeshContext meshContext) { if (!meshContext.materialIndices.Any()) { meshContext.materialIndices.Add(0); } var mesh = new Mesh(); mesh.name = meshContext.name; if (meshContext.positions.Length > UInt16.MaxValue) { #if UNITY_2017_3_OR_NEWER mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; #else Debug.LogWarningFormat("vertices {0} exceed 65535. not implemented. Unity2017.3 supports large mesh", meshContext.positions.Length); #endif } mesh.vertices = meshContext.positions; bool recalculateNormals = false; if (meshContext.normals != null && meshContext.normals.Length > 0) { mesh.normals = meshContext.normals; } else { recalculateNormals = true; } if (meshContext.uv != null && meshContext.uv.Length > 0) { mesh.uv = meshContext.uv; } bool recalculateTangents = true; #if UNIGLTF_IMPORT_TANGENTS if (meshContext.tangents != null && meshContext.tangents.Length > 0) { mesh.tangents = meshContext.tangents; recalculateTangents = false; } #endif if (meshContext.colors != null && meshContext.colors.Length > 0) { mesh.colors = meshContext.colors; } if (meshContext.boneWeights != null && meshContext.boneWeights.Count > 0) { mesh.boneWeights = meshContext.boneWeights.ToArray(); } mesh.subMeshCount = meshContext.subMeshes.Count; for (int i = 0; i < meshContext.subMeshes.Count; ++i) { mesh.SetTriangles(meshContext.subMeshes[i], i); } if (recalculateNormals) { mesh.RecalculateNormals(); } if (recalculateTangents) { #if UNITY_5_6_OR_NEWER yield return(null); mesh.RecalculateTangents(); yield return(null); #else CalcTangents(mesh); #endif } var result = new MeshWithMaterials { Mesh = mesh, Materials = meshContext.materialIndices.Select(x => ctx.GetMaterial(x)).ToArray() }; yield return(null); if (meshContext.blendShapes != null) { Vector3[] emptyVertices = null; foreach (var blendShape in meshContext.blendShapes) { if (blendShape.Positions.Count > 0) { if (blendShape.Positions.Count == mesh.vertexCount) { mesh.AddBlendShapeFrame(blendShape.Name, FRAME_WEIGHT, blendShape.Positions.ToArray(), (meshContext.normals != null && meshContext.normals.Length == mesh.vertexCount && blendShape.Normals.Count() == blendShape.Positions.Count()) ? blendShape.Normals.ToArray() : null, null ); yield return(null); } else { Debug.LogWarningFormat("May be partial primitive has blendShape. Require separate mesh or extend blend shape, but not implemented: {0}", blendShape.Name); } } else { if (emptyVertices == null) { emptyVertices = new Vector3[mesh.vertexCount]; } // Debug.LogFormat("empty blendshape: {0}.{1}", mesh.name, blendShape.Name); // add empty blend shape for keep blend shape index mesh.AddBlendShapeFrame(blendShape.Name, FRAME_WEIGHT, emptyVertices, null, null ); yield return(null); } } } yield return(result); }