//Component_MeshInSpace contains only one Component_Mesh. static void MergeGeometries(Component_Mesh mesh, DocumentInstance document, UndoMultiAction undo) { Component_MeshGeometry[] geometries = mesh.GetComponents <Component_MeshGeometry>(); if (geometries == null || geometries.Length < 2) { return; } Reference <Component_Material> material = geometries[0].Material; //for( int i = 1; i < geometries.Length; i++ ) //{ // if( !( material.Value == null && geometries[ i ].Material.Value == null || material.Equals( geometries[ i ].Material ) ) ) // { // //??? Если разные Material какой вариант лучше: 1) Брать из первого geometry с вопросом в MessageBox; 2) Disable в меню для Action. 3) Соединять те, которые с одинаковым материалом. // if( EditorMessageBox.ShowQuestion( "Mesh geometries have different materials. Merge them using a material from the first geometry?", MessageBoxButtons.OKCancel ) == DialogResult.Cancel ) // { // return; // } // } //} var extracted = mesh.ExtractStructure(); var newIndices = new List <int>(); var newVertices = new List <byte>(); var newVertexStructure = extracted.MeshGeometries[0].VertexStructure; var newVertexFormat = new MeshData.MeshGeometryFormat(newVertexStructure); for (int geomIndex = 0; geomIndex < extracted.MeshGeometries.Length; geomIndex++) { var g = extracted.MeshGeometries[geomIndex]; if (g.Vertices == null || g.Indices == null) { continue; } int indexOffset = newVertices.Count / newVertexFormat.vertexSize; for (int i = 0; i < g.Indices.Length; i++) { newIndices.Add(g.Indices[i] + indexOffset); } if (!CommonFunctions.IsSameVertexStructure(newVertexStructure, g.VertexStructure)) { g.Vertices = MeshData.ConvertToFormat(new MeshData.MeshGeometryFormat(g.VertexStructure), g.Vertices, newVertexFormat); } newVertices.AddRange(g.Vertices); foreach (var face in extracted.Structure.Faces) { for (int i = 0; i < face.Triangles.Length; i++) { if (face.Triangles[i].RawGeometry == geomIndex) { face.Triangles[i].RawGeometry = 0; face.Triangles[i].RawVertex += indexOffset; } } } } // changes in the mesh if (undo != null) { //add structure update to undo var property = (Metadata.Property)mesh.MetadataGetMemberBySignature("property:" + nameof(Component_Mesh.Structure)); undo.AddAction(new UndoActionPropertiesChange(new UndoActionPropertiesChange.Item(mesh, property, mesh.Structure?.Clone()))); } bool meshWasEnabled = mesh.Enabled; mesh.Enabled = false; try { var newGeometry = mesh.CreateComponent <Component_MeshGeometry>(); newGeometry.Material = material; newGeometry.Vertices = newVertices.ToArray(); newGeometry.Indices = newIndices.ToArray(); newGeometry.VertexStructure = newVertexStructure; //add created geometry to undo undo?.AddAction(new UndoActionComponentCreateDelete(document, new Component[] { newGeometry }, create: true)); mesh.Structure = extracted.Structure; //delete old mesh geometry undo?.AddAction(new UndoActionComponentCreateDelete(document, geometries, create: false)); newGeometry.Name = CommonFunctions.GetUniqueFriendlyName(newGeometry); } finally { mesh.Enabled = meshWasEnabled; } }
static void ConvertProceduralMeshGeometries(DocumentInstance document, Component_Mesh mesh, UndoMultiAction undoMultiAction, ref bool needUndoForNextActions) { //needUndoForNextActions = true; var meshGeometries = mesh.GetComponents <Component_MeshGeometry>(); if (meshGeometries.Any(g => g is Component_MeshGeometry_Procedural)) { //!!!!? bool hasOrdinary = meshGeometries.Any(g => !(g is Component_MeshGeometry_Procedural)); if (!hasOrdinary) { needUndoForNextActions = false; //??? Если были и обычные geometry и procedural? Как правильно needUndoForNextActions? Пока так: undo не нужен только если все procedural } //!!!!right? !needUndoForNextActions if (undoMultiAction != null && !needUndoForNextActions) { //add structure update to undo var property = (Metadata.Property)mesh.MetadataGetMemberBySignature("property:" + nameof(Component_Mesh.Structure)); undoMultiAction.AddAction(new UndoActionPropertiesChange(new UndoActionPropertiesChange.Item(mesh, property, mesh.Structure?.Clone()))); } for (int i = 0; i < meshGeometries.Length; i++) { var meshGeometry = meshGeometries[i]; //convert to usual Component_MeshGeometry if (meshGeometry is Component_MeshGeometry_Procedural meshGeometryProcedural) { VertexElement[] vertexStructure = null; byte[] vertices = null; int[] indices = null; Component_Material material = null; Component_Mesh.StructureClass structure = null; meshGeometryProcedural.GetProceduralGeneratedData(ref vertexStructure, ref vertices, ref indices, ref material, ref structure); var insertIndex = meshGeometryProcedural.Parent.Components.IndexOf(meshGeometryProcedural); var meshGeometryNew = mesh.CreateComponent <Component_MeshGeometry>(insertIndex); meshGeometryNew.Name = meshGeometry.Name; meshGeometryNew.VertexStructure = vertexStructure; meshGeometryNew.Vertices = vertices; meshGeometryNew.Indices = indices; meshGeometryNew.Material = meshGeometryProcedural.Material; //concut structures. If the geometry is procedural it is not in a structure yet. mesh.Structure = Component_Mesh.StructureClass.Concat(mesh.Structure, structure, i); //delete old mesh geometry if (undoMultiAction != null) { undoMultiAction.AddAction(new UndoActionComponentCreateDelete(document, new Component[] { meshGeometry }, create: false)); } else { meshGeometry.Dispose(); } //add created geometry to undo if (undoMultiAction != null) { undoMultiAction.AddAction(new UndoActionComponentCreateDelete(document, new Component[] { meshGeometryNew }, create: true)); } } } } }
public static bool ExportToFBX(Component_Mesh sourceMesh, string realFileName, out string error) { //!!!!как для Vegetation. оверрайдить в Component_Mesh? //get mesh data var operations = new List <Component_RenderingPipeline.RenderSceneData.MeshDataRenderOperation>(); foreach (var geometry in sourceMesh.GetComponents <Component_MeshGeometry>()) { if (geometry.Enabled) { geometry.CompileDataOfThisObject(out var operation); if (operation != null) { operations.Add(operation); } } } //foreach( var geometry in mesh.Result.MeshData.RenderOperations ) //{ //} FbxManager manager = null; FbxIOSettings setting = null; FbxExporter exporter = null; FbxScene scene = null; try { //init FBX manager manager = FbxManager.Create(); setting = FbxIOSettings.Create(manager, "IOSRoot"); manager.SetIOSettings(setting); scene = FbxScene.Create(manager, "scene"); scene.GetGlobalSettings().SetAxisSystem(new FbxAxisSystem(FbxAxisSystem.EPreDefinedAxisSystem.eMax)); scene.GetGlobalSettings().SetSystemUnit(new FbxSystemUnit(100)); //init FBX scene for (int nOper = 0; nOper < operations.Count; nOper++) { var oper = operations[nOper]; //get data Vector3F[] positions = null; Vector3F[] normals = null; var texCoords = new List <Vector2F[]>(); ColorValue[] colors = null; Vector3F[] tangents = null; Vector3F[] binormals = null; //Position { if (oper.VertexStructure.GetElementBySemantic(VertexElementSemantic.Position, out VertexElement element) && element.Type == VertexElementType.Float3) { var buffer = oper.VertexBuffers[element.Source]; positions = buffer.ExtractChannel <Vector3F>(element.Offset); } } //Normal { if (oper.VertexStructure.GetElementBySemantic(VertexElementSemantic.Normal, out VertexElement element) && element.Type == VertexElementType.Float3) { var buffer = oper.VertexBuffers[element.Source]; normals = buffer.ExtractChannel <Vector3F>(element.Offset); } } //TexCoord for (var channel = VertexElementSemantic.TextureCoordinate0; channel <= VertexElementSemantic.TextureCoordinate3; channel++) { if (oper.VertexStructure.GetElementBySemantic(channel, out VertexElement element) && element.Type == VertexElementType.Float2) { var buffer = oper.VertexBuffers[element.Source]; texCoords.Add(buffer.ExtractChannel <Vector2F>(element.Offset)); } } //Color { if (oper.VertexStructure.GetElementBySemantic(VertexElementSemantic.Color0, out VertexElement element)) { if (element.Type == VertexElementType.Float4) { var buffer = oper.VertexBuffers[element.Source]; var values = buffer.ExtractChannel <Vector4F>(element.Offset); colors = new ColorValue[positions.Length]; int destIndex = 0; foreach (var p in values) { colors[destIndex++] = p.ToColorValue(); } } else if (element.Type == VertexElementType.ColorABGR) { //!!!!check var buffer = oper.VertexBuffers[element.Source]; var values = buffer.ExtractChannel <uint>(element.Offset); colors = new ColorValue[positions.Length]; int destIndex = 0; foreach (var p in values) { colors[destIndex++] = new ColorValue(ColorByte.FromABGR(p)); } } else if (element.Type == VertexElementType.ColorARGB) { //!!!!check var buffer = oper.VertexBuffers[element.Source]; var values = buffer.ExtractChannel <uint>(element.Offset); colors = new ColorValue[positions.Length]; int destIndex = 0; foreach (var p in values) { colors[destIndex++] = new ColorValue(ColorByte.FromARGB(p)); } } } } //Tangent, Binormal if (normals != null) { if (oper.VertexStructure.GetElementBySemantic(VertexElementSemantic.Tangent, out VertexElement element) && element.Type == VertexElementType.Float4) { var buffer = oper.VertexBuffers[element.Source]; var tangents4 = buffer.ExtractChannel <Vector4F>(element.Offset); tangents = new Vector3F[tangents4.Length]; binormals = new Vector3F[tangents4.Length]; int destIndex = 0; foreach (var p in tangents4) { tangents[destIndex] = p.ToVector3F(); binormals[destIndex] = Vector3F.Cross(p.ToVector3F(), normals[destIndex]) * p.W; destIndex++; } } } //indices int[] indices = null; if (oper.IndexBuffer != null) { indices = oper.IndexBuffer.Indices; } //create geometry var geometryName = "Geometry " + nOper.ToString(); var mesh = FbxMesh.Create(scene, geometryName); mesh.InitControlPoints(positions.Length); FbxLayerElementNormal elementNormals = null; if (normals != null) { elementNormals = mesh.CreateElementNormal(); elementNormals.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); elementNormals.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); } FbxLayerElementVertexColor elementColors = null; if (colors != null) { elementColors = mesh.CreateElementVertexColor(); elementColors.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); elementColors.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); } FbxLayerElementTangent elementTangents = null; if (tangents != null) { elementTangents = mesh.CreateElementTangent(); elementTangents.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); elementTangents.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); } FbxLayerElementBinormal elementBinormals = null; if (binormals != null) { elementBinormals = mesh.CreateElementBinormal(); elementBinormals.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); elementBinormals.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); } var uvElements = new List <FbxLayerElementUV>(); for (int uvIndex = 0; uvIndex < texCoords.Count; uvIndex++) { var pUVElement = mesh.CreateElementUV("texcoord" + uvIndex.ToString()); pUVElement.SetMappingMode(FbxLayerElement.EMappingMode.eByControlPoint); pUVElement.SetReferenceMode(FbxLayerElement.EReferenceMode.eDirect); uvElements.Add(pUVElement); } for (int n = 0; n < positions.Length; n++) { mesh.SetControlPointAt(ToFbxVector4(positions[n]), n); if (normals != null) { elementNormals.GetDirectArray().Add(ToFbxVector4(normals[n])); } for (int uvIndex = 0; uvIndex < texCoords.Count; uvIndex++) { var texCoord = texCoords[uvIndex][n]; texCoord.Y = 1.0f - texCoord.Y; uvElements[uvIndex].GetDirectArray().Add(ToFbxVector2(texCoord)); } if (colors != null) { elementColors.GetDirectArray().Add(ToFbxColor(colors[n])); } if (tangents != null) { elementTangents.GetDirectArray().Add(ToFbxVector4(tangents[n])); } if (binormals != null) { elementBinormals.GetDirectArray().Add(ToFbxVector4(binormals[n])); } } if (normals != null) { mesh.GetLayer(0).SetNormals(elementNormals); } if (colors != null) { mesh.GetLayer(0).SetVertexColors(elementColors); } if (tangents != null) { mesh.GetLayer(0).SetTangents(elementTangents); } if (binormals != null) { mesh.GetLayer(0).SetBinormals(elementBinormals); } int polygonCount = indices.Length / 3; for (int i = 0; i < polygonCount; i++) { mesh.BeginPolygon(-1, -1, -1, false); for (int j = 0; j < 3; j++) { int currentIndex = i * 3 + j; int vertexIndex = indices[currentIndex]; mesh.AddPolygon(vertexIndex); } mesh.EndPolygon(); } var node = FbxNode.Create(scene, geometryName); node.SetNodeAttribute(mesh); scene.GetRootNode().AddChild(mesh.GetNode()); } //save exporter = FbxExporter.Create(manager, ""); if (!exporter.Initialize(realFileName, -1, manager.GetIOSettings())) { error = "Can't initialize FBX exporter."; return(false); } if (!exporter.Export(scene)) { error = "Export to FBX failed."; return(false); } } finally { try { scene?.Destroy(); } catch { } try { exporter?.Destroy(); } catch { } try { setting?.Destroy(); } catch { } try { manager?.Destroy(); } catch { } } foreach (var op in operations) { op.DisposeBuffers(); } error = ""; return(true); }
unsafe static void MeshGetIsBillboard(ImportContext context, Component_Mesh destinationMesh) { bool isBillboard = false; var geometries = destinationMesh.GetComponents <Component_MeshGeometry>(); if (geometries.Length == 1) { var geometry = geometries[0]; try { var vertexStructure = geometry.VertexStructure.Value; var vertices = geometry.Vertices.Value; var indices = geometry.Indices.Value; if (vertexStructure?.Length != 0 && vertices?.Length != 0 && indices?.Length != 0) { vertexStructure.GetInfo(out var vertexSize, out _); int vertexCount = vertices.Length / vertexSize; if (indices.Length >= 3) { if (vertexStructure.GetElementBySemantic(VertexElementSemantic.Position, out var positionElement)) { if (positionElement.Type == VertexElementType.Float3 && positionElement.Source == 0) { int offset = positionElement.Offset; var p = new Vector3[vertexCount]; for (int nVertex = 0; nVertex < vertexCount; nVertex++) { fixed(byte *pVertices = vertices) p[nVertex] = *(Vector3F *)(pVertices + nVertex * vertexSize + offset); } var normal1 = Plane.FromPoints(p[indices[0]], p[indices[1]], p[indices[2]]).Normal; if (Math.Abs(normal1.X) > 0.95f || Math.Abs(normal1.Y) > 0.95f) { bool canBeBillboard = true; for (int nTriangle = 0; nTriangle < indices.Length / 3; nTriangle++) { var index0 = indices[nTriangle * 3 + 0]; var index1 = indices[nTriangle * 3 + 1]; var index2 = indices[nTriangle * 3 + 2]; var normal2 = Plane.FromPoints(p[index0], p[index1], p[index2]).Normal; if (!normal1.Equals(normal2, 0.01)) { canBeBillboard = false; break; } } if (canBeBillboard) { isBillboard = true; } } } } } } } catch (Exception e) { Log.Warning(e.Message); } } if (isBillboard) { destinationMesh.Billboard = true; foreach (var geometry in geometries) { if (context.materialByIndex.TryGetValue(-1, out var material)) { geometry.Material = ReferenceUtility.MakeRootReference(material); } } } }