/// <summary> /// Combine coplanar triangles from the faceted body if they share the edge. From this process, polygonal faces (with or without holes) will be created /// </summary> public void SimplifyAndMergeFaces(bool ignoreMerge = false) { int eulerBefore = ignoreMerge ? 0 : CalculateEulerCharacteristic(); int noTriangle = (IsMesh) ? m_MeshGeom.NumTriangles : m_Geom.TriangleCount; IEqualityComparer <XYZ> normalComparer = new VectorCompare(); Dictionary <XYZ, List <int> > faceSortedByNormal = new Dictionary <XYZ, List <int> >(normalComparer); for (int ef = 0; ef < noTriangle; ++ef) { IList <int> vertIndex = new List <int>(); if (IsMesh) { MeshTriangle f = m_MeshGeom.get_Triangle(ef); vertIndex = new List <int>(3) { (int)f.get_Index(0), (int)f.get_Index(1), (int)f.get_Index(2) }; } else { TriangleInShellComponent f = m_Geom.GetTriangle(ef); vertIndex = new List <int>(3) { f.VertexIndex0, f.VertexIndex1, f.VertexIndex2 }; } IndexFace intF = new IndexFace(vertIndex, ref m_MeshVertices); m_FacesCollDict.Add(faceIdxOffset++, intF); // Keep faces in a dictionary and assigns ID List <int> fIDList; if (!faceSortedByNormal.TryGetValue(intF.Normal, out fIDList)) { fIDList = new List <int>(1) { ef }; faceSortedByNormal.Add(intF.Normal, fIDList); } else if (!fIDList.Contains(ef)) { fIDList.Add(ef); } } foreach (KeyValuePair <XYZ, List <int> > fListDict in faceSortedByNormal) { List <int> mergedFaceList = null; if (fListDict.Value.Count > 1) { if (!ignoreMerge) { TryMergeFaces(fListDict.Value, out mergedFaceList); } else { // keep original face list mergedFaceList = fListDict.Value; } if (mergedFaceList != null && mergedFaceList.Count > 0) { // insert only new face indexes as the mergedlist from different vertices can be duplicated foreach (int fIdx in mergedFaceList) { if (!m_MergedFaceSet.Contains(fIdx)) { m_MergedFaceSet.Add(fIdx); } } } } else if (!m_MergedFaceSet.Contains(fListDict.Value[0])) { m_MergedFaceSet.Add(fListDict.Value[0]); // No pair face, add it into the mergedList } } int eulerAfter = ignoreMerge ? 0 : CalculateEulerCharacteristic(); if (eulerBefore != eulerAfter) { throw new InvalidOperationException(); // Coplanar merge broke the mesh in some way, so we need to fall back to exporting a triangular mesh } }
private static void CutTriangle(Plane _plane, MeshTriangle _triangle, bool _triangleALeftSide, bool _triangleBLeftSide, bool _triangleCLeftSide, GeneratedMesh _leftSide, GeneratedMesh _rightSide, List <Vector3> _addedVertices) { List <bool> leftSide = new List <bool>(); leftSide.Add(_triangleALeftSide); leftSide.Add(_triangleBLeftSide); leftSide.Add(_triangleCLeftSide); MeshTriangle leftMeshTriangle = new MeshTriangle(new Vector3[2], new Vector3[2], new Vector2[2], _triangle.SubmeshIndex); MeshTriangle rightMeshTriangle = new MeshTriangle(new Vector3[2], new Vector3[2], new Vector2[2], _triangle.SubmeshIndex); bool left = false; bool right = false; for (int i = 0; i < 3; ++i) { if (leftSide[i]) { if (!left) { left = true; leftMeshTriangle.Vertices[0] = _triangle.Vertices[i]; leftMeshTriangle.Vertices[1] = leftMeshTriangle.Vertices[0]; leftMeshTriangle.UVs[0] = _triangle.UVs[i]; leftMeshTriangle.UVs[1] = leftMeshTriangle.UVs[0]; leftMeshTriangle.Normals[0] = _triangle.Normals[i]; leftMeshTriangle.Normals[1] = leftMeshTriangle.Normals[0]; } else { leftMeshTriangle.Vertices[1] = _triangle.Vertices[i]; leftMeshTriangle.Normals[1] = _triangle.Normals[i]; leftMeshTriangle.UVs[1] = _triangle.UVs[i]; } } else { if (!right) { right = true; rightMeshTriangle.Vertices[0] = _triangle.Vertices[i]; rightMeshTriangle.Vertices[1] = rightMeshTriangle.Vertices[0]; rightMeshTriangle.UVs[0] = _triangle.UVs[i]; rightMeshTriangle.UVs[1] = rightMeshTriangle.UVs[0]; rightMeshTriangle.Normals[0] = _triangle.Normals[i]; rightMeshTriangle.Normals[1] = rightMeshTriangle.Normals[0]; } else { rightMeshTriangle.Vertices[1] = _triangle.Vertices[i]; rightMeshTriangle.Normals[1] = _triangle.Normals[i]; rightMeshTriangle.UVs[1] = _triangle.UVs[i]; } } } float normalizedDistance; float distance; _plane.Raycast(new Ray(leftMeshTriangle.Vertices[0], (rightMeshTriangle.Vertices[0] - leftMeshTriangle.Vertices[0]).normalized), out distance); normalizedDistance = distance / (rightMeshTriangle.Vertices[0] - leftMeshTriangle.Vertices[0]).magnitude; Vector3 vertLeft = Vector3.Lerp(leftMeshTriangle.Vertices[0], rightMeshTriangle.Vertices[0], normalizedDistance); _addedVertices.Add(vertLeft); Vector3 normalLeft = Vector3.Lerp(leftMeshTriangle.Normals[0], rightMeshTriangle.Normals[0], normalizedDistance); Vector2 uvLeft = Vector2.Lerp(leftMeshTriangle.UVs[0], rightMeshTriangle.UVs[0], normalizedDistance); _plane.Raycast(new Ray(leftMeshTriangle.Vertices[1], (rightMeshTriangle.Vertices[1] - leftMeshTriangle.Vertices[1]).normalized), out distance); normalizedDistance = distance / (rightMeshTriangle.Vertices[1] - leftMeshTriangle.Vertices[1]).magnitude; Vector3 vertRight = Vector3.Lerp(leftMeshTriangle.Vertices[1], rightMeshTriangle.Vertices[1], normalizedDistance); _addedVertices.Add(vertRight); Vector3 normalRight = Vector3.Lerp(leftMeshTriangle.Normals[1], rightMeshTriangle.Normals[1], normalizedDistance); Vector2 uvRight = Vector2.Lerp(leftMeshTriangle.UVs[1], rightMeshTriangle.UVs[1], normalizedDistance); MeshTriangle currentTriangle; Vector3[] updatedVertices = new Vector3[] { leftMeshTriangle.Vertices[0], vertLeft, vertRight }; Vector3[] updatedNormals = new Vector3[] { leftMeshTriangle.Normals[0], normalLeft, normalRight }; Vector2[] updatedUVs = new Vector2[] { leftMeshTriangle.UVs[0], uvLeft, uvRight }; currentTriangle = new MeshTriangle(updatedVertices, updatedNormals, updatedUVs, _triangle.SubmeshIndex); if (updatedVertices[0] != updatedVertices[1] && updatedVertices[0] != updatedVertices[2]) { if (Vector3.Dot(Vector3.Cross(updatedVertices[1] - updatedVertices[0], updatedVertices[2] - updatedVertices[0]), updatedNormals[0]) < 0) { FlipTriangle(currentTriangle); } _leftSide.AddTriangle(currentTriangle); } updatedVertices = new Vector3[] { leftMeshTriangle.Vertices[0], leftMeshTriangle.Vertices[1], vertRight }; updatedNormals = new Vector3[] { leftMeshTriangle.Normals[0], leftMeshTriangle.Normals[1], normalRight }; updatedUVs = new Vector2[] { leftMeshTriangle.UVs[0], leftMeshTriangle.UVs[1], uvRight }; currentTriangle = new MeshTriangle(updatedVertices, updatedNormals, updatedUVs, _triangle.SubmeshIndex); if (updatedVertices[0] != updatedVertices[1] && updatedVertices[0] != updatedVertices[2]) { if (Vector3.Dot(Vector3.Cross(updatedVertices[1] - updatedVertices[0], updatedVertices[2] - updatedVertices[0]), updatedNormals[0]) < 0) { FlipTriangle(currentTriangle); } _leftSide.AddTriangle(currentTriangle); } updatedVertices = new Vector3[] { rightMeshTriangle.Vertices[0], vertLeft, vertRight }; updatedNormals = new Vector3[] { rightMeshTriangle.Normals[0], normalLeft, normalRight }; updatedUVs = new Vector2[] { rightMeshTriangle.UVs[0], uvLeft, uvRight }; currentTriangle = new MeshTriangle(updatedVertices, updatedNormals, updatedUVs, _triangle.SubmeshIndex); if (updatedVertices[0] != updatedVertices[1] && updatedVertices[0] != updatedVertices[2]) { if (Vector3.Dot(Vector3.Cross(updatedVertices[1] - updatedVertices[0], updatedVertices[2] - updatedVertices[0]), updatedNormals[0]) < 0) { FlipTriangle(currentTriangle); } _rightSide.AddTriangle(currentTriangle); } updatedVertices = new Vector3[] { rightMeshTriangle.Vertices[0], rightMeshTriangle.Vertices[1], vertRight }; updatedNormals = new Vector3[] { rightMeshTriangle.Normals[0], rightMeshTriangle.Normals[1], normalRight }; updatedUVs = new Vector2[] { rightMeshTriangle.UVs[0], rightMeshTriangle.UVs[1], uvRight }; currentTriangle = new MeshTriangle(updatedVertices, updatedNormals, updatedUVs, _triangle.SubmeshIndex); if (updatedVertices[0] != updatedVertices[1] && updatedVertices[0] != updatedVertices[2]) { if (Vector3.Dot(Vector3.Cross(updatedVertices[1] - updatedVertices[0], updatedVertices[2] - updatedVertices[0]), updatedNormals[0]) < 0) { FlipTriangle(currentTriangle); } _rightSide.AddTriangle(currentTriangle); } }
public static void Execute1( ExternalCommandData commandData) { Transaction trans = null; UIDocument uidoc = commandData.Application .ActiveUIDocument; Document doc = uidoc.Document; try { Selection choices = uidoc.Selection; Reference reference = choices.PickObject( ObjectType.Face); Element el = doc.GetElement( reference.ElementId); trans = new Transaction(doc, "Create elements"); trans.Start(); TessellatedShapeBuilder builder = new TessellatedShapeBuilder(); builder.OpenConnectedFaceSet(false); Face face = el.GetGeometryObjectFromReference( reference) as Face; Mesh mesh = face.Triangulate(); List <XYZ> args = new List <XYZ>(3); XYZ offset = new XYZ(); if (el.Location is LocationPoint) { LocationPoint locationPoint = el.Location as LocationPoint; offset = locationPoint.Point; } for (int i = 0; i < mesh.NumTriangles; i++) { MeshTriangle triangle = mesh.get_Triangle( i); XYZ p1 = triangle.get_Vertex(0); XYZ p2 = triangle.get_Vertex(1); XYZ p3 = triangle.get_Vertex(2); p1 = p1.Add(offset); p2 = p2.Add(offset); p3 = p3.Add(offset); args.Clear(); args.Add(p1); args.Add(p2); args.Add(p3); TessellatedFace tesseFace = new TessellatedFace(args, ElementId.InvalidElementId); if (builder.DoesFaceHaveEnoughLoopsAndVertices( tesseFace)) { builder.AddFace(tesseFace); } } builder.CloseConnectedFaceSet(); //TessellatedShapeBuilderResult result // = builder.Build( // TessellatedShapeBuilderTarget.AnyGeometry, // TessellatedShapeBuilderFallback.Mesh, // ElementId.InvalidElementId ); // 2016 builder.Target = TessellatedShapeBuilderTarget.AnyGeometry; // 2018 builder.Fallback = TessellatedShapeBuilderFallback.Mesh; // 2018 builder.Build(); // 2018 TessellatedShapeBuilderResult result = builder.GetBuildResult(); // 2018 ElementId categoryId = new ElementId( BuiltInCategory.OST_GenericModel); //DirectShape ds = DirectShape.CreateElement( // doc, categoryId, // Assembly.GetExecutingAssembly().GetType() // .GUID.ToString(), Guid.NewGuid().ToString() ); // 2016 DirectShape ds = DirectShape.CreateElement( doc, categoryId); // 2018 ds.ApplicationId = Assembly.GetExecutingAssembly() .GetType().GUID.ToString(); // 2018 ds.ApplicationDataId = Guid.NewGuid().ToString(); // 2018 ds.SetShape(result.GetGeometricalObjects()); ds.Name = "MyShape"; trans.Commit(); } catch (Exception ex) { if (trans != null) { trans.RollBack(); } Debug.Print(ex.Message); } }
CollectEvent(object sender, CollectorEventArgs e) { // cast the sender object to the SnoopCollector we are expecting Collector snoopCollector = sender as Collector; if (snoopCollector == null) { Debug.Assert(false); // why did someone else send us the message? return; } // see if it is a type we are responsible for Location loc = e.ObjToSnoop as Location; if (loc != null) { Stream(snoopCollector.Data(), loc); return; } GeometryObject geomObj = e.ObjToSnoop as GeometryObject; if (geomObj != null) { Stream(snoopCollector.Data(), geomObj); return; } Options opts = e.ObjToSnoop as Options; if (opts != null) { Stream(snoopCollector.Data(), opts); return; } Transform trf = e.ObjToSnoop as Transform; if (trf != null) { Stream(snoopCollector.Data(), trf); return; } BoundingBoxXYZ bndBoxXyz = e.ObjToSnoop as BoundingBoxXYZ; if (bndBoxXyz != null) { Stream(snoopCollector.Data(), bndBoxXyz); return; } MeshTriangle meshTri = e.ObjToSnoop as MeshTriangle; if (meshTri != null) { Stream(snoopCollector.Data(), meshTri); return; } Reference reference = e.ObjToSnoop as Reference; if (reference != null) { Stream(snoopCollector.Data(), reference); return; } EdgeArray edgeArray = e.ObjToSnoop as EdgeArray; // NOTE: this is needed because EdgeArrayArray will display enumerable Snoop items if (edgeArray != null) { Stream(snoopCollector.Data(), edgeArray); return; } CurveArray curveArray = e.ObjToSnoop as CurveArray; // NOTE: this is needed because CurveArrayArray will display enumerable Snoop items if (curveArray != null) { Stream(snoopCollector.Data(), curveArray); return; } Plane plane = e.ObjToSnoop as Plane; if (plane != null) { Stream(snoopCollector.Data(), plane); return; } IntersectionResult intrResult = e.ObjToSnoop as IntersectionResult; if (intrResult != null) { Stream(snoopCollector.Data(), intrResult); return; } BoundingBoxUV bboxUV = e.ObjToSnoop as BoundingBoxUV; if (bboxUV != null) { Stream(snoopCollector.Data(), bboxUV); return; } SweepProfile sweepProf = e.ObjToSnoop as SweepProfile; if (sweepProf != null) { Stream(snoopCollector.Data(), sweepProf); return; } DimensionSegment dimSeg = e.ObjToSnoop as DimensionSegment; if (dimSeg != null) { Stream(snoopCollector.Data(), dimSeg); return; } UV uv = e.ObjToSnoop as UV; if (uv != null) { Stream(snoopCollector.Data(), uv); return; } }
// public Vector3 ClosestPoint (Vector3 point) // { // } public MeshTriangle[] Subdivide() { MeshTriangle[] output = new MeshTriangle[4]; return(output); }
public static Triangle3D ToSAM(this MeshTriangle meshTriangle) { return(new Triangle3D(meshTriangle.get_Vertex(0).ToSAM(), meshTriangle.get_Vertex(1).ToSAM(), meshTriangle.get_Vertex(2).ToSAM())); }
private static void CutTriangle(Plane plane, MeshTriangle triangle, bool [] pointsOnLeftSide, GeneratedMesh leftMesh, GeneratedMesh rightMesh, List <Vector3> addedVertices) { MeshTriangle leftMeshTriangle = new MeshTriangle(new Vector3[2], new Vector3[2], new Vector2[2], triangle.SubmeshIndices); MeshTriangle rightMeshTriangle = new MeshTriangle(new Vector3[2], new Vector3[2], new Vector2[2], triangle.SubmeshIndices); bool left = false; bool right = false; for (int i = 0; i < 3; i++) { if (pointsOnLeftSide[i]) { if (!left) { left = true; leftMeshTriangle.Vertices[0] = leftMeshTriangle.Vertices[1] = triangle.Vertices[i]; leftMeshTriangle.Uvs[0] = leftMeshTriangle.Uvs[1] = triangle.Uvs[i]; leftMeshTriangle.Normals[0] = leftMeshTriangle.Normals[1] = triangle.Normals[i]; } else { leftMeshTriangle.Vertices[1] = triangle.Vertices[i]; leftMeshTriangle.Uvs[1] = triangle.Uvs[i]; leftMeshTriangle.Normals[1] = triangle.Normals[i]; } } else { if (!right) { right = true; rightMeshTriangle.Vertices[0] = rightMeshTriangle.Vertices[1] = triangle.Vertices[i]; rightMeshTriangle.Uvs[0] = rightMeshTriangle.Uvs[1] = triangle.Uvs[i]; rightMeshTriangle.Normals[0] = rightMeshTriangle.Normals[1] = triangle.Normals[i]; } else { rightMeshTriangle.Vertices[1] = triangle.Vertices[i]; rightMeshTriangle.Uvs[1] = triangle.Uvs[i]; rightMeshTriangle.Normals[1] = triangle.Normals[i]; } } } // можно переписать черех цикл и сократить количество кода в 2 раза и вынести в новую функцию добавление новой вершины float normalizedDistance; float distance; plane.Raycast(new Ray(leftMeshTriangle.Vertices[0], (rightMeshTriangle.Vertices[0] - leftMeshTriangle.Vertices[0]).normalized), out distance); normalizedDistance = distance / (rightMeshTriangle.Vertices[0] - leftMeshTriangle.Vertices[0]).magnitude; Vector3 vertLeft = Vector3.Lerp(leftMeshTriangle.Vertices[0], rightMeshTriangle.Vertices[0], normalizedDistance); addedVertices.Add(vertLeft); Vector3 normalLeft = Vector3.Lerp(leftMeshTriangle.Normals[0], rightMeshTriangle.Normals[0], normalizedDistance); Vector3 uvLeft = Vector3.Lerp(leftMeshTriangle.Uvs[0], rightMeshTriangle.Uvs[0], normalizedDistance); plane.Raycast(new Ray(leftMeshTriangle.Vertices[1], (rightMeshTriangle.Vertices[1] - leftMeshTriangle.Vertices[1]).normalized), out distance); normalizedDistance = distance / (rightMeshTriangle.Vertices[1] - leftMeshTriangle.Vertices[1]).magnitude; Vector3 vertRight = Vector3.Lerp(leftMeshTriangle.Vertices[1], rightMeshTriangle.Vertices[1], normalizedDistance); addedVertices.Add(vertRight); Vector3 normalRight = Vector3.Lerp(leftMeshTriangle.Normals[1], rightMeshTriangle.Normals[1], normalizedDistance); Vector3 uvRight = Vector3.Lerp(leftMeshTriangle.Uvs[1], rightMeshTriangle.Uvs[1], normalizedDistance); // до сюда // можно сократить код в 4 раза и вынести в новую функцию Vector3[] updatedVertices = new Vector3[] { leftMeshTriangle.Vertices[0], vertLeft, vertRight }; Vector3[] updatedNormals = new Vector3[] { leftMeshTriangle.Normals[0], normalLeft, normalRight }; Vector2[] updatedUvs = new Vector2[] { leftMeshTriangle.Uvs[0], uvLeft, uvRight }; MeshTriangle currentTriangle = new MeshTriangle(updatedVertices, updatedNormals, updatedUvs, triangle.SubmeshIndices); if (updatedVertices[0] != updatedVertices[1] && updatedVertices[0] != updatedVertices[2]) { if (Vector3.Dot(Vector3.Cross(updatedVertices[1] - updatedVertices[0], updatedVertices[2] - updatedVertices[0]), updatedNormals[0]) < 0) { FlipTriangle(currentTriangle); } leftMesh.AddTriangle(currentTriangle); } updatedVertices = new Vector3[] { leftMeshTriangle.Vertices[0], leftMeshTriangle.Vertices[1], vertRight }; updatedNormals = new Vector3[] { leftMeshTriangle.Normals[0], leftMeshTriangle.Normals[1], normalRight }; updatedUvs = new Vector2[] { leftMeshTriangle.Uvs[0], leftMeshTriangle.Uvs[1], uvRight }; currentTriangle = new MeshTriangle(updatedVertices, updatedNormals, updatedUvs, triangle.SubmeshIndices); if (updatedVertices[0] != updatedVertices[1] && updatedVertices[0] != updatedVertices[2]) { if (Vector3.Dot(Vector3.Cross(updatedVertices[1] - updatedVertices[0], updatedVertices[2] - updatedVertices[0]), updatedNormals[0]) < 0) { FlipTriangle(currentTriangle); } leftMesh.AddTriangle(currentTriangle); } updatedVertices = new Vector3[] { rightMeshTriangle.Vertices[0], vertLeft, vertRight }; updatedNormals = new Vector3[] { rightMeshTriangle.Normals[0], normalLeft, normalRight }; updatedUvs = new Vector2[] { rightMeshTriangle.Uvs[0], uvLeft, uvRight }; currentTriangle = new MeshTriangle(updatedVertices, updatedNormals, updatedUvs, triangle.SubmeshIndices); if (updatedVertices[0] != updatedVertices[1] && updatedVertices[0] != updatedVertices[2]) { if (Vector3.Dot(Vector3.Cross(updatedVertices[1] - updatedVertices[0], updatedVertices[2] - updatedVertices[0]), updatedNormals[0]) < 0) { FlipTriangle(currentTriangle); } rightMesh.AddTriangle(currentTriangle); } updatedVertices = new Vector3[] { rightMeshTriangle.Vertices[0], rightMeshTriangle.Vertices[1], vertRight }; updatedNormals = new Vector3[] { rightMeshTriangle.Normals[0], rightMeshTriangle.Normals[1], normalRight }; updatedUvs = new Vector2[] { rightMeshTriangle.Uvs[0], rightMeshTriangle.Uvs[1], uvRight }; currentTriangle = new MeshTriangle(updatedVertices, updatedNormals, updatedUvs, triangle.SubmeshIndices); if (updatedVertices[0] != updatedVertices[1] && updatedVertices[0] != updatedVertices[2]) { if (Vector3.Dot(Vector3.Cross(updatedVertices[1] - updatedVertices[0], updatedVertices[2] - updatedVertices[0]), updatedNormals[0]) < 0) { FlipTriangle(currentTriangle); } rightMesh.AddTriangle(currentTriangle); } // до сюда }
public bool AllCornersAreSimilar(MeshTriangle meshTriangle, float maxDistanceSqr) { return(point1.GetDistanceSqrToClosestPoint(meshTriangle.point1, meshTriangle.point2, meshTriangle.point3) <= maxDistanceSqr && point2.GetDistanceSqrToClosestPoint(meshTriangle.point1, meshTriangle.point2, meshTriangle.point3) <= maxDistanceSqr && point3.GetDistanceSqrToClosestPoint(meshTriangle.point1, meshTriangle.point2, meshTriangle.point3) <= maxDistanceSqr); }
public static GameObject Cut(GameObject _originalGameObject, Vector3 _contactPoint, Vector3 _direction, Material _cutMaterial = null, bool fill = true, bool _addRigigibody = false) { if (currentlyCutting) { return(null); } currentlyCutting = true; // set the cutter relative to victim Plane plane = new Plane(_originalGameObject.transform.InverseTransformDirection(-_direction), _originalGameObject.transform.InverseTransformPoint(_contactPoint)); //get the victims mesh originalMesh = _originalGameObject.GetComponent <MeshFilter>() ? _originalGameObject.GetComponent <MeshFilter>().mesh : _originalGameObject.GetComponent <SkinnedMeshRenderer>().sharedMesh; //List for added vertices List <Vector3> addedVertices = new List <Vector3>(); //Create two new meshes GeneratedMesh leftMesh = new GeneratedMesh(); GeneratedMesh rightMesh = new GeneratedMesh(); int[] submeshIndices; int triangleIndexA, triangleIndexB, triangleIndexC; for (int i = 0; i < originalMesh.subMeshCount; i++) { //Fetches the triangle list for the specified sub-mesh on the victim submeshIndices = originalMesh.GetTriangles(i); for (int j = 0; j < submeshIndices.Length; j += 3) { triangleIndexA = submeshIndices[j]; triangleIndexB = submeshIndices[j + 1]; triangleIndexC = submeshIndices[j + 2]; MeshTriangle currentTriangle = GetTriangle(triangleIndexA, triangleIndexB, triangleIndexC, i); // Get vertices sides bool triangleALeftSide = plane.GetSide(originalMesh.vertices[triangleIndexA]); bool triangleBLeftSide = plane.GetSide(originalMesh.vertices[triangleIndexB]); bool triangleCLeftSide = plane.GetSide(originalMesh.vertices[triangleIndexC]); if (triangleALeftSide && triangleBLeftSide && triangleCLeftSide)// left side { leftMesh.AddTriangle(currentTriangle); } else if (!triangleALeftSide && !triangleBLeftSide && !triangleCLeftSide)// right side { rightMesh.AddTriangle(currentTriangle); } else // Cut the triangle { CutTriangle(plane, currentTriangle, triangleALeftSide, triangleBLeftSide, triangleCLeftSide, leftMesh, rightMesh, addedVertices); } } } // Get Materials to apply to the new objects Material[] mats; if (_originalGameObject.GetComponent <MeshRenderer>()) { mats = _originalGameObject.GetComponent <MeshRenderer>().sharedMaterials; } else { mats = _originalGameObject.GetComponent <SkinnedMeshRenderer>().sharedMaterials; } // if there is a material to fill the cut add it to materials list if (_cutMaterial) { if (mats[mats.Length - 1].name != _cutMaterial.name) { Material[] newmats = new Material[mats.Length + 1]; mats.CopyTo(newmats, 0); newmats[mats.Length] = _cutMaterial; mats = newmats; } } int submeshCount = mats.Length - 1; if (fill) { // fill the opennings FillCut(addedVertices, plane, leftMesh, rightMesh, submeshCount); } //// Left Mesh Mesh left_HalfMesh = leftMesh.GetMesh(); left_HalfMesh.name = "Split Mesh Left"; //// Right Mesh Mesh right_HalfMesh = rightMesh.GetMesh(); right_HalfMesh.name = "Split Mesh Right"; //// assign the game objects if (_originalGameObject.GetComponent <MeshFilter>()) { _originalGameObject.GetComponent <MeshFilter>().mesh = left_HalfMesh; } else { _originalGameObject.GetComponent <SkinnedMeshRenderer>().sharedMesh = left_HalfMesh; } GameObject leftSideObj = _originalGameObject; GameObject rightSideObj = null; if (_originalGameObject.GetComponent <MeshRenderer>()) { rightSideObj = new GameObject("right side", typeof(MeshFilter), typeof(MeshRenderer)); rightSideObj.transform.position = _originalGameObject.transform.position; rightSideObj.transform.rotation = _originalGameObject.transform.rotation; rightSideObj.GetComponent <MeshFilter>().mesh = right_HalfMesh; } else if (_originalGameObject.GetComponent <SkinnedMeshRenderer>()) { rightSideObj = new GameObject("right side"); SkinnedMeshRenderer skinMesh = rightSideObj.AddComponent <SkinnedMeshRenderer>(); rightSideObj.transform.position = _originalGameObject.transform.position; rightSideObj.transform.rotation = _originalGameObject.transform.rotation; skinMesh.sharedMesh = right_HalfMesh; } if (_originalGameObject.transform.parent != null) { rightSideObj.transform.parent = _originalGameObject.transform.parent; } rightSideObj.transform.localScale = _originalGameObject.transform.localScale; //Add rigibody to the new object if (_addRigigibody) { var rigibody = rightSideObj.AddComponent <Rigidbody>(); rigibody = _originalGameObject.GetComponent <Rigidbody>(); } // assign materials if (_originalGameObject.GetComponent <MeshRenderer>()) { leftSideObj.GetComponent <MeshRenderer>().materials = mats; rightSideObj.GetComponent <MeshRenderer>().materials = mats; } else if (_originalGameObject.GetComponent <SkinnedMeshRenderer>()) { leftSideObj.GetComponent <SkinnedMeshRenderer>().materials = mats; rightSideObj.GetComponent <SkinnedMeshRenderer>().materials = mats; } return(rightSideObj); }
/// <summary> /// Get triangles in a solid with transform. /// </summary> /// <param name="solid">The solid contains triangulars</param> /// <param name="transform">The transformation.</param> private void GetTriangular(Document document, Solid solid, Transform transform) { // a solid has many faces FaceArray faces = solid.Faces; bool hasTransform = (null != transform); if (0 == faces.Size) { return; } foreach (Face face in faces) { if (face.Visibility != Visibility.Visible) { continue; } Mesh mesh = face.Triangulate(); if (null == mesh) { continue; } m_TriangularNumber += mesh.NumTriangles; PlanarFace planarFace = face as PlanarFace; // write face to stl file // a face has a mesh, all meshes are made of triangles for (int ii = 0; ii < mesh.NumTriangles; ii++) { MeshTriangle triangular = mesh.get_Triangle(ii); double[] xyz = new double[9]; Autodesk.Revit.DB.XYZ normal = new Autodesk.Revit.DB.XYZ(); try { Autodesk.Revit.DB.XYZ[] triPnts = new Autodesk.Revit.DB.XYZ[3]; for (int n = 0; n < 3; ++n) { double x, y, z; Autodesk.Revit.DB.XYZ point = triangular.get_Vertex(n); if (hasTransform) { point = transform.OfPoint(point); } if (m_Settings.ExportSharedCoordinates) { ProjectPosition ps = document.ActiveProjectLocation.GetProjectPosition(point); x = ps.EastWest; y = ps.NorthSouth; z = ps.Elevation; } else { x = point.X; y = point.Y; z = point.Z; } if (m_Settings.Units != DisplayUnitType.DUT_UNDEFINED) { xyz[3 * n] = UnitUtils.ConvertFromInternalUnits(x, m_Settings.Units); xyz[3 * n + 1] = UnitUtils.ConvertFromInternalUnits(y, m_Settings.Units); xyz[3 * n + 2] = UnitUtils.ConvertFromInternalUnits(z, m_Settings.Units); } else { xyz[3 * n] = x; xyz[3 * n + 1] = y; xyz[3 * n + 2] = z; } var mypoint = new XYZ(xyz[3 * n], xyz[3 * n + 1], xyz[3 * n + 2]); triPnts[n] = mypoint; } Autodesk.Revit.DB.XYZ pnt1 = triPnts[1] - triPnts[0]; normal = pnt1.CrossProduct(triPnts[2] - triPnts[1]); } catch (Exception ex) { m_TriangularNumber--; STLDialogManager.ShowDebug(ex.Message); continue; } if (m_Writer is SaveDataAsBinary && m_Settings.ExportColor) { Material material = document.GetElement(face.MaterialElementId) as Material; if (material != null) { ((SaveDataAsBinary)m_Writer).Color = material.Color; } } m_Writer.WriteSection(normal, xyz); } } }
// Fill holl when cutting the triangle public static void Fill(List <Vector3> _vertices, Plane _plane, GeneratedMesh _leftMesh, GeneratedMesh _rightMesh, int submeshCount) { // center of the filling Vector3 centerPosition = Vector3.zero; for (int i = 0; i < _vertices.Count; i++) { centerPosition += _vertices[i]; } centerPosition = centerPosition / _vertices.Count; Vector3 up = new Vector3() { x = _plane.normal.x, y = _plane.normal.y, z = _plane.normal.z }; Vector3 left = Vector3.Cross(_plane.normal, _plane.normal); Vector3 displacement = Vector3.zero; Vector2 uv1 = Vector2.zero; Vector2 uv2 = Vector2.zero; // go through edges and eliminate by creating triangles with connected edges // each new triangle removes 2 edges but creates 1 new edge // keep the chain in order for (int i = 0; i < _vertices.Count; i++) { displacement = _vertices[i] - centerPosition; uv1 = new Vector2() { x = .5f + Vector3.Dot(displacement, left), y = .5f + Vector3.Dot(displacement, up) }; displacement = _vertices[(i + 1) % _vertices.Count] - centerPosition; uv2 = new Vector2() { x = .5f + Vector3.Dot(displacement, left), y = .5f + Vector3.Dot(displacement, up) }; Vector3[] vertices = new Vector3[] { _vertices[i], _vertices[(i + 1) % _vertices.Count], centerPosition }; Vector3[] normals = new Vector3[] { -_plane.normal, -_plane.normal, -_plane.normal }; Vector2[] uvs = new Vector2[] { uv1, uv2, new Vector2(0.5f, 0.5f) }; //Update current triangle MeshTriangle currentTriangle = new MeshTriangle(vertices, normals, uvs, submeshCount); // check if it is facing the right way FacingCheck(currentTriangle); // add to left side _leftMesh.AddTriangle(currentTriangle); normals = new Vector3[] { _plane.normal, _plane.normal, _plane.normal }; currentTriangle = new MeshTriangle(vertices, normals, uvs, submeshCount); // check if it is facing the right way FacingCheck(currentTriangle); // add to right side _rightMesh.AddTriangle(currentTriangle); } }
private static void CutTriangle(Plane _plane, MeshTriangle _triangle, bool _triangleALeftSide, bool _triangleBLeftSide, bool _triangleCLeftSide, GeneratedMesh _leftSide, GeneratedMesh _rightSide, List <Vector3> _addedVertices) { List <bool> leftSide = new List <bool>(); leftSide.Add(_triangleALeftSide); leftSide.Add(_triangleBLeftSide); leftSide.Add(_triangleCLeftSide); MeshTriangle leftMeshTriangle = new MeshTriangle(new Vector3[2], new Vector3[2], new Vector2[2], _triangle.SubmeshIndex); MeshTriangle rightMeshTriangle = new MeshTriangle(new Vector3[2], new Vector3[2], new Vector2[2], _triangle.SubmeshIndex); MeshTriangle meshTriangle = new MeshTriangle(new Vector3[2], new Vector3[2], new Vector2[2], _triangle.SubmeshIndex); bool left = false; bool right = false; for (int i = 0; i < 3; i++) { if (leftSide[i])// left { if (!left) { left = true; leftMeshTriangle.Vertices[0] = _triangle.Vertices[i]; leftMeshTriangle.Vertices[1] = leftMeshTriangle.Vertices[0]; leftMeshTriangle.Uvs[0] = _triangle.Uvs[i]; leftMeshTriangle.Uvs[1] = leftMeshTriangle.Uvs[0]; leftMeshTriangle.Normals[0] = _triangle.Normals[i]; leftMeshTriangle.Normals[1] = leftMeshTriangle.Normals[0]; } else { leftMeshTriangle.Vertices[1] = _triangle.Vertices[i]; leftMeshTriangle.Normals[1] = _triangle.Normals[i]; leftMeshTriangle.Uvs[1] = _triangle.Uvs[i]; } } else // right { if (!right) { right = true; rightMeshTriangle.Vertices[0] = _triangle.Vertices[i]; rightMeshTriangle.Vertices[1] = rightMeshTriangle.Vertices[0]; rightMeshTriangle.Uvs[0] = _triangle.Uvs[i]; rightMeshTriangle.Uvs[1] = rightMeshTriangle.Uvs[0]; rightMeshTriangle.Normals[0] = _triangle.Normals[i]; rightMeshTriangle.Normals[1] = rightMeshTriangle.Normals[0]; } else { rightMeshTriangle.Vertices[1] = _triangle.Vertices[i]; rightMeshTriangle.Normals[1] = _triangle.Normals[i]; rightMeshTriangle.Uvs[1] = _triangle.Uvs[i]; } } } // now to find the intersection points between the solo point and the others float normalizeDistance; float distance; Vector3 edgeVector = Vector3.zero; // edge lenght and direction edgeVector = rightMeshTriangle.Vertices[0] - leftMeshTriangle.Vertices[0]; _plane.Raycast(new Ray(leftMeshTriangle.Vertices[0], edgeVector.normalized), out distance); normalizeDistance = distance / edgeVector.magnitude; Vector3 vertLeft = Vector3.Lerp(leftMeshTriangle.Vertices[0], rightMeshTriangle.Vertices[0], normalizeDistance); Vector3 normalLeft = Vector3.Lerp(leftMeshTriangle.Normals[0], rightMeshTriangle.Normals[0], normalizeDistance); Vector2 uvLeft = Vector2.Lerp(leftMeshTriangle.Uvs[0], rightMeshTriangle.Uvs[0], normalizeDistance); edgeVector = rightMeshTriangle.Vertices[1] - leftMeshTriangle.Vertices[1]; _plane.Raycast(new Ray(leftMeshTriangle.Vertices[1], edgeVector.normalized), out distance); normalizeDistance = distance / edgeVector.magnitude; Vector3 vertRight = Vector3.Lerp(leftMeshTriangle.Vertices[1], rightMeshTriangle.Vertices[1], normalizeDistance); Vector3 normalRight = Vector3.Lerp(leftMeshTriangle.Normals[1], rightMeshTriangle.Normals[1], normalizeDistance); Vector2 uvRight = Vector2.Lerp(leftMeshTriangle.Uvs[1], rightMeshTriangle.Uvs[1], normalizeDistance); if (vertLeft != vertRight) { //tracking newly created points _addedVertices.Add(vertLeft); _addedVertices.Add(vertRight); } // make the new triangles MeshTriangle currentTriangle; Vector3[] updatedVertices = new Vector3[] { leftMeshTriangle.Vertices[0], vertLeft, vertRight }; Vector3[] updatedNormals = new Vector3[] { leftMeshTriangle.Normals[0], normalLeft, normalRight }; Vector2[] updatedUvs = new Vector2[] { leftMeshTriangle.Uvs[0], uvLeft, uvRight }; currentTriangle = new MeshTriangle(updatedVertices, updatedNormals, updatedUvs, _triangle.SubmeshIndex); if (updatedVertices[0] != updatedVertices[1] && updatedVertices[0] != updatedVertices[2]) { // check if it is facing the right way FacingCheck(currentTriangle); // add it _leftSide.AddTriangle(currentTriangle); } updatedVertices = new Vector3[] { leftMeshTriangle.Vertices[0], leftMeshTriangle.Vertices[1], vertRight }; updatedNormals = new Vector3[] { leftMeshTriangle.Normals[0], leftMeshTriangle.Normals[1], normalRight }; updatedUvs = new Vector2[] { leftMeshTriangle.Uvs[0], leftMeshTriangle.Uvs[1], uvRight }; currentTriangle = new MeshTriangle(updatedVertices, updatedNormals, updatedUvs, _triangle.SubmeshIndex); if (updatedVertices[0] != updatedVertices[1] && updatedVertices[0] != updatedVertices[2]) { // check if it is facing the right way FacingCheck(currentTriangle); // add it _leftSide.AddTriangle(currentTriangle); } updatedVertices = new Vector3[] { rightMeshTriangle.Vertices[0], vertLeft, vertRight }; updatedNormals = new Vector3[] { rightMeshTriangle.Normals[0], normalLeft, normalRight }; updatedUvs = new Vector2[] { rightMeshTriangle.Uvs[0], uvLeft, uvRight }; currentTriangle = new MeshTriangle(updatedVertices, updatedNormals, updatedUvs, _triangle.SubmeshIndex); if (updatedVertices[0] != updatedVertices[1] && updatedVertices[0] != updatedVertices[2]) { // check if it is facing the right way FacingCheck(currentTriangle); // add it _rightSide.AddTriangle(currentTriangle); } updatedVertices = new Vector3[] { rightMeshTriangle.Vertices[0], rightMeshTriangle.Vertices[1], vertRight }; updatedNormals = new Vector3[] { rightMeshTriangle.Normals[0], rightMeshTriangle.Normals[1], normalRight }; updatedUvs = new Vector2[] { rightMeshTriangle.Uvs[0], rightMeshTriangle.Uvs[1], uvRight }; currentTriangle = new MeshTriangle(updatedVertices, updatedNormals, updatedUvs, _triangle.SubmeshIndex); if (updatedVertices[0] != updatedVertices[1] && updatedVertices[0] != updatedVertices[2]) { // check if it is facing the right way FacingCheck(currentTriangle); // add it _rightSide.AddTriangle(currentTriangle); } }
void Awake() { I_MeshT = GetComponentInChildren <MeshTriangle>(); I_Line = GetComponentInChildren <LineRenderer>(); }
/// <summary> /// Add the vertices of the given triangle to our /// vertex lookup dictionary and emit a triangle. /// </summary> void StoreTriangle(MeshTriangle triangle) { for (int i = 0; i < 3; ++i) { XYZ p = triangle.get_Vertex(i); PointInt q = new PointInt(p); _triangles.Add(_vertices.AddVertex(q)); } }
public static void CutGameobject(GameObject originalGameObject, Vector3 contactPoint, Vector3 direction, bool addRigidbody = false) { if (currentlyCutting) { return; } currentlyCutting = true; originalMesh = originalGameObject.GetComponent <MeshFilter>().mesh; var plane = new Plane(originalGameObject.transform.InverseTransformDirection(direction), originalGameObject.transform.InverseTransformPoint(contactPoint)); var addedVertices = new List <Vector3>(); var leftMesh = new GeneratedMesh(); var rightMesh = new GeneratedMesh(); int[] submeshIndices; int triangleIndexA, triangleIndexB, triangleIndexC; for (int i = 0; i < originalMesh.subMeshCount; i++) { submeshIndices = originalMesh.GetTriangles(i); for (int j = 0; j < submeshIndices.Length; j += 3) { triangleIndexA = submeshIndices[j]; triangleIndexB = submeshIndices[j + 1]; triangleIndexC = submeshIndices[j + 2]; MeshTriangle currentTriangle = GetTriangle(triangleIndexA, triangleIndexB, triangleIndexC, i); bool[] pointsOnLeftSide = new bool [3]; pointsOnLeftSide[0] = plane.GetSide(originalMesh.vertices[triangleIndexA]); pointsOnLeftSide[1] = plane.GetSide(originalMesh.vertices[triangleIndexB]); pointsOnLeftSide[2] = plane.GetSide(originalMesh.vertices[triangleIndexC]); if (pointsOnLeftSide[0] && pointsOnLeftSide[1] && pointsOnLeftSide[2]) { leftMesh.AddTriangle(currentTriangle); } else if (!pointsOnLeftSide[0] && !pointsOnLeftSide[1] && !pointsOnLeftSide[2]) { rightMesh.AddTriangle(currentTriangle); } else { CutTriangle(plane, currentTriangle, pointsOnLeftSide, leftMesh, rightMesh, addedVertices); } } FillCut(addedVertices, plane, leftMesh, rightMesh); GenerateCutterGameobject(originalGameObject, leftMesh, addRigidbody, Vector3.up); GenerateCutterGameobject(originalGameObject, rightMesh, addRigidbody, Vector3.left); currentlyCutting = false; } }
void SubDivideSoffits_CreateFireRatedLayers(Document doc) { try { #region Get Soffits List <Element> Soffits = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Floors).ToElements().Where(m => !(m is ElementType)).ToList(); #endregion //Subdivide foreach (Element Soffit in Soffits.Where(m => m.Name.ToLower().Contains("eave"))) { #region Get Soffit Geometry Options ops = new Options(); ops.DetailLevel = ViewDetailLevel.Fine; ops.IncludeNonVisibleObjects = true; GeometryElement Geo = Soffit.get_Geometry(ops); #endregion foreach (var item in Geo) { if (item is Solid) { #region Get one of the Main Faces, it doesn't really matter if it is top or bottom Solid GSol = item as Solid; List <Face> Fs = new List <Face>(); foreach (Face f in GSol.Faces) { Fs.Add(f); } Face F = Fs.Where(m => m.Area == Fs.Max(a => a.Area)).First(); #endregion #region Triangulate the Face with max detail Mesh M = F.Triangulate(1); #endregion #region Create Variables for: the curves that will define the new Soffits, List of Custom Triangle Class, List of Custom Pair of Triangle Class List <List <Curve> > LLC = new List <List <Curve> >(); List <Triangle> Triangles = new List <Triangle>(); List <TrianglePair> TPairs = new List <TrianglePair>(); #endregion #region Loop Through Triangles & Add Them to the list of My Triangle Class for (int i = 0; i < M.NumTriangles; i++) { List <Curve> LC = new List <Curve>(); #region Make List of Curves From Triangle MeshTriangle MT = M.get_Triangle(i); List <Curve> Curves = new List <Curve>(); Curve C = Line.CreateBound(MT.get_Vertex(0), MT.get_Vertex(1)) as Curve; Curves.Add(C); C = Line.CreateBound(MT.get_Vertex(1), MT.get_Vertex(2)) as Curve; Curves.Add(C); C = Line.CreateBound(MT.get_Vertex(2), MT.get_Vertex(0)) as Curve; Curves.Add(C); #endregion Triangle T = new Triangle(); T.Sides = new List <Curve>(); T.Sides = Curves; T.Vertices = new List <XYZ>(); T.Vertices.Add(MT.get_Vertex(0)); T.Vertices.Add(MT.get_Vertex(1)); T.Vertices.Add(MT.get_Vertex(2)); Triangles.Add(T); } #endregion #region Loop Through Triangles And Create Trapezoid Pairs To Catch The Segments, Getting Rid of The Shared sides bool GO = true; do { Triangle TKeeper1 = new Triangle(); Triangle TKeeper2 = new Triangle(); foreach (Triangle T in Triangles) { TKeeper1 = new Triangle(); foreach (Triangle T2 in Triangles) { TKeeper2 = new Triangle(); if (T != T2) { if (FindCurvesFacing(T, T2) != null) { if (FindCurvesFacing(T, T2)[0].Length == T.Sides.Min(c => c.Length) || FindCurvesFacing(T, T2)[1].Length == T2.Sides.Min(c => c.Length)) { continue; } Curve[] Cs = FindCurvesFacing(T, T2); T.Sides.Remove(Cs[0]); T2.Sides.Remove(Cs[1]); if (T.Sides.Count() == 2 && T2.Sides.Count() == 2) { TKeeper1 = T; TKeeper2 = T2; goto ADDANDGOROUND; } } } } } GO = false; ADDANDGOROUND: if (GO) { Triangles.Remove(TKeeper1); Triangles.Remove(TKeeper2); TrianglePair TP = new TrianglePair(); TP.T1 = TKeeper1; TP.T2 = TKeeper2; TPairs.Add(TP); } } while(GO); #endregion #region Create Curve Loops From Triangle Pairs foreach (TrianglePair TPair in TPairs) { List <Curve> Cs = new List <Curve>(); Cs.AddRange(TPair.T1.Sides); Cs.AddRange(TPair.T2.Sides); LLC.Add(Cs); } #endregion double Offset = Convert.ToDouble(Soffit.LookupParameter("Height Offset From Level").AsValueString()); FloorType FT = (Soffit as Floor).FloorType; Level Lvl = doc.GetElement((Soffit as Floor).LevelId) as Level; #region Delete Old Soffit If All Went Well using (Transaction T = new Transaction(doc, "Delete Soffit")) { T.Start(); doc.Delete(Soffit.Id); T.Commit(); } #endregion #region Sort The Lists of Curves and Create The New Segments foreach (List <Curve> LC in LLC) { List <Curve> LCSorted = new List <Curve>(); try { LCSorted = SortCurvesContiguous(LC, false); } #region Exception Details if Curves Could not be sorted catch (Exception EXC) { string exmsge = EXC.Message; } #endregion CurveArray CA = new CurveArray(); foreach (Curve C in LCSorted) { CA.Append(C); } using (Transaction T = new Transaction(doc, "Make Segment")) { T.Start(); Floor newFloor = doc.Create.NewFloor(CA, FT, Lvl, false); newFloor.LookupParameter("Height Offset From Level").SetValueString(Offset.ToString()); T.Commit(); } } #endregion } } } //refresh collection Soffits = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Floors).ToElements().Where(m => !(m is ElementType)).ToList(); //test soffits for needing fire rating foreach (Element Soffit in Soffits.Where(m => m.Name.ToLower().Contains("eave"))) { #region Get Soffit Geometry Options ops = new Options(); ops.DetailLevel = ViewDetailLevel.Fine; ops.IncludeNonVisibleObjects = true; GeometryElement Geo = Soffit.get_Geometry(ops); #endregion foreach (var item in Geo) { if (item is Solid) { #region Find boundary Void Element List <Element> MaybeBoundary = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Floors).ToElements().Where(m => !(m is ElementType)).ToList(); Element BoundryElement = MaybeBoundary.Where(m => !(m is FloorType) && m.Name == "Boundary").First(); #endregion #region Get Intersection of Boundary and eave PolygonAnalyser com = new PolygonAnalyser(); List <CurveArray> CArray = com.Execute(BoundryElement as Floor, Soffit as Floor); Level L = doc.GetElement(Soffit.LevelId) as Level; #endregion foreach (CurveArray CA in CArray) { #region Sort The Curves IList <Curve> CAL = new List <Curve>(); foreach (Curve C in CA) { CAL.Add(C); } List <Curve> Curves = SortCurvesContiguous(CAL, false); List <XYZ> NewCurveEnds = new List <XYZ>(); #endregion #region Close the loop if nesesary CurveLoop CL = new CurveLoop(); foreach (Curve curv in Curves) { CL.Append(curv); } if (CL.IsOpen()) { Curves.Add(Line.CreateBound(CL.First().GetEndPoint(0), CL.Last().GetEndPoint(1)) as Curve); } #endregion #region Recreate a Curve Array Curves = SortCurvesContiguous(Curves, false); CurveArray CA2 = new CurveArray(); int i = 0; foreach (Curve c in Curves) { CA2.Insert(c, i); i += 1; } #endregion #region Create The New Fire Rated Layer element FloorType ft = new FilteredElementCollector(doc).WhereElementIsElementType().OfCategory(BuiltInCategory.OST_Floors).ToElements().Where(m => m.Name == "Fire Rated Layer").First() as FloorType; Transaction T = new Transaction(doc, "Fire Rated Layer Creation"); try { T.Start(); Floor F = doc.Create.NewFloor(CA2, ft, L, false); string s = Soffit.LookupParameter("Height Offset From Level").AsValueString(); double si = Convert.ToDouble(s); si = si + (Convert.ToDouble(Soffit.LookupParameter("Thickness").AsValueString())); F.LookupParameter("Height Offset From Level").SetValueString(si.ToString()); T.Commit(); } catch (Exception EX) { T.RollBack(); string EXmsg = EX.Message; } #endregion } } } } } catch (Exception ex) { string mesg = ex.Message; } }
public void BuildPlanet() { Vector3 planetPos = transform.position; Quaternion planetRot = transform.rotation; // Reset planet position to origin temporarily transform.position = Vector3.zero; transform.rotation = Quaternion.identity; if (vectors != null) { vectors.Clear(); } else { vectors = new List <Vector3>(); } if (indices != null) { indices.Clear(); } else { indices = new List <int>(); } if (detailLevel < 0) { detailLevel = 0; } //Mesh generation freezes up for detail levels greater than 4 if (detailLevel > 5) { detailLevel = 5; } unitScale = detailLevel; Geometry.Icosahedron(vectors, indices); // Subdivide icosahedron for (int i = 0; i < detailLevel; i++) { Geometry.Subdivide(vectors, indices, true); } // Normalize vectors to "inflate" the icosahedron into a sphere. for (int i = 0; i < vectors.Count; i++) { // You can also multiply this by some amount to change the build size vectors[i] = Vector3.Normalize(vectors[i]); } Dictionary <Vector3, List <MeshTriangle> > trianglesByTileFaceVerts = new Dictionary <Vector3, List <MeshTriangle> >(); // Map each vertex to its surrounding triangles for (int t = 0; t < indices.Count - 2; t += 3) { Vector3 v0 = vectors[indices[t]]; Vector3 v1 = vectors[indices[t + 1]]; Vector3 v2 = vectors[indices[t + 2]]; if (!trianglesByTileFaceVerts.ContainsKey(v0)) { trianglesByTileFaceVerts.Add(v0, new List <MeshTriangle>()); } if (!trianglesByTileFaceVerts.ContainsKey(v1)) { trianglesByTileFaceVerts.Add(v1, new List <MeshTriangle>()); } if (!trianglesByTileFaceVerts.ContainsKey(v2)) { trianglesByTileFaceVerts.Add(v2, new List <MeshTriangle>()); } MeshTriangle mTri = new MeshTriangle(v0, v1, v2, t, t + 1, t + 2); trianglesByTileFaceVerts[v0].Add(mTri); trianglesByTileFaceVerts[v1].Add(mTri); trianglesByTileFaceVerts[v2].Add(mTri); } // If generating whole planet as a single mesh if (GenerateAsSingleMesh) { MeshFilter mf = GetComponent <MeshFilter>(); if (mf == null) { mf = gameObject.AddComponent <MeshFilter>(); } if (GetComponent <MeshRenderer>() == null) { MeshRenderer mRenderer = gameObject.AddComponent <MeshRenderer>(); mRenderer.sharedMaterial = GroupMaterials[0]; } List <Vector3> verts = new List <Vector3>(); List <int> tris = new List <int>(); List <Vector3> norms = new List <Vector3>(); Transform helper = new GameObject("Helper Transform").transform; helper.parent = transform; foreach (var kvp in trianglesByTileFaceVerts) { GenerateTileSubMesh(kvp.Key, kvp.Value, ref verts, ref tris, ref norms, helper); } Mesh mesh = new Mesh(); mesh.vertices = verts.ToArray(); mesh.triangles = tris.ToArray(); mesh.normals = norms.ToArray(); mesh.RecalculateBounds(); mf.sharedMesh = mesh; DestroyImmediate(helper.gameObject); transform.position = planetPos; transform.rotation = planetRot; return; } // Generate tile gameobjects Dictionary <Vector3, Tile> tilesByFaceVerts = new Dictionary <Vector3, Tile>(); tiles = new List <Tile>(); // Create the tile meshes : O(n) foreach (var kvp in trianglesByTileFaceVerts) { Tile t = CreateTile(kvp.Key, kvp.Value); tiles.Add(t); // Map face vertices to the generated tile for neighbor finding tilesByFaceVerts.Add(kvp.Key, t); } // Find neighbors : O(n) foreach (var kvp in tilesByFaceVerts) { List <Tile> neighbors = new List <Tile>(); // Loop over all vertices in each adjacent triangle foreach (MeshTriangle tri in trianglesByTileFaceVerts[kvp.Key]) { for (int i = 0; i < 3; i++) { Vector3 nVert = tri.Vertices[i]; Tile t; // Look up the tile corresponding to the face vertex in the adjacent triangle if (tilesByFaceVerts.TryGetValue(nVert, out t)) { if (!neighbors.Contains(t) && t != kvp.Value) { neighbors.Add(tilesByFaceVerts[nVert]); } } } } kvp.Value.neighborTiles = neighbors; } TileCount = tiles.Count; tilesGenerated = true; //Assign tiles to navManager navManager.setWorldTiles(tiles); // Restore position and rotation transform.position = planetPos; transform.rotation = planetRot; }
public bool HasSimilarCorner(MeshTriangle meshTriangle, float maxDistanceSqr) { return(point1.GetDistanceSqrToClosestPoint(meshTriangle.point1, meshTriangle.point2, meshTriangle.point3) <= maxDistanceSqr || point2.GetDistanceSqrToClosestPoint(meshTriangle.point1, meshTriangle.point2, meshTriangle.point3) <= maxDistanceSqr || point3.GetDistanceSqrToClosestPoint(meshTriangle.point1, meshTriangle.point2, meshTriangle.point3) <= maxDistanceSqr); }
public Result Execute( ExternalCommandData commandData, ref string message, ElementSet elements) { UIApplication uiapp = commandData.Application; UIDocument uidoc = uiapp.ActiveUIDocument; Application app = uiapp.Application; Document doc = uidoc.Document; //WALLS FACES List <PlanarFace> wallFaces = new List <PlanarFace>(); //WALLS Reference wallRef = uidoc.Selection.PickObject(ObjectType.Element, "Select a Wall"); Element wall = doc.GetElement(wallRef); LocationCurve lc = wall.Location as LocationCurve; Line wallLine = lc.Curve as Line; XYZ perpDir = wallLine.Direction.CrossProduct(XYZ.BasisZ); Options opt = new Options(); opt.ComputeReferences = true; opt.IncludeNonVisibleObjects = false; opt.View = doc.ActiveView; GeometryElement geomElem = doc.GetElement(wallRef).get_Geometry(opt); foreach (GeometryObject geomObj in geomElem) { Solid geomSolid = geomObj as Solid; foreach (Face geomFace in geomSolid.Faces) { XYZ faceNormal = geomFace.ComputeNormal(new UV(0.5, 0.5)); //select only the vertical faces if (faceNormal.CrossProduct(perpDir).IsAlmostEqualTo(XYZ.Zero)) { PlanarFace pf = geomFace as PlanarFace; wallFaces.Add(pf); } } } //GET MESH Reference meshRef = uidoc.Selection.PickObject(ObjectType.Element, "Select Mesh"); Element e = doc.GetElement(meshRef); GeometryElement geomElemSurvey = e.get_Geometry(opt); Mesh geomMesh = null; foreach (GeometryObject geomObj in geomElemSurvey) { try { GeometryInstance gi = geomObj as GeometryInstance; foreach (GeometryObject element in gi.GetInstanceGeometry()) { geomMesh = element as Mesh; } } catch { geomMesh = geomObj as Mesh; } } using (Transaction t = new Transaction(doc, "Find intersection")) { t.Start(); List <XYZ> intPts = new List <XYZ>(); for (int i = 0; i < geomMesh.NumTriangles; i++) { MeshTriangle triangle = geomMesh.get_Triangle(i); XYZ vertex1 = triangle.get_Vertex(0); XYZ vertex2 = triangle.get_Vertex(1); XYZ vertex3 = triangle.get_Vertex(2); Line[] edgeList = new Line[3]; try { Line[] edges = new Line[] { Line.CreateBound(vertex1, vertex2), Line.CreateBound(vertex1, vertex3), Line.CreateBound(vertex2, vertex3) }; for (int k = 0; k < edgeList.Length; k++) { edgeList[k] = edges[k]; } } catch { } // Plane facePlane = Plane.CreateByThreePoints(vertex1, vertex2, vertex3); // SketchPlane sp = SketchPlane.Create(doc, facePlane); // doc.Create.NewModelCurve(edge12, sp); // doc.Create.NewModelCurve(edge13, sp); // doc.Create.NewModelCurve(edge23, sp); foreach (PlanarFace pf in wallFaces) { XYZ[] pts = new XYZ[2]; int count = 0; if (edgeList[0] != null) { foreach (Line edge in edgeList) { IntersectionResultArray intersections = null; SetComparisonResult scr = pf.Intersect(edge, out intersections); if (scr == SetComparisonResult.Overlap && intersections.Size == 1) { for (int j = 0; j < intersections.Size; j++) { //TaskDialog.Show("r", intersections.get_Item(i)); } //TaskDialog.Show("r", intersections.Size.ToString()); IntersectionResult iResult = intersections.get_Item(0); intPts.Add(iResult.XYZPoint); pts[count] = iResult.XYZPoint; count = 1; if (pts.Length == 2 && pts[1] != null) { // TaskDialog.Show("r", String.Format("{0}\n{1}",pts[0], pts[1])); try { Plane wallPlane = Plane.CreateByNormalAndOrigin(pf.FaceNormal, pf.Origin); SketchPlane spWall = SketchPlane.Create(doc, wallPlane); doc.Create.NewModelCurve(Line.CreateBound(pts[0], pts[1]), spWall); } catch { } } } } } } } t.Commit(); } return(Result.Succeeded); }
/// <summary> /// Combine coplanar triangles from the faceted body if they share the edge. From this process, polygonal faces (with or without holes) will be created /// </summary> public void SimplifyAndMergeFaces() { int noTriangle = (IsMesh)? _meshGeom.NumTriangles : _geom.TriangleCount; int noVertices = (IsMesh)? _meshGeom.Vertices.Count : _geom.VertexCount; IEqualityComparer <XYZ> normalComparer = new vectorCompare(); Dictionary <XYZ, List <int> > faceSortedByNormal = new Dictionary <XYZ, List <int> >(normalComparer); for (int ef = 0; ef < noTriangle; ++ef) { IList <int> vertIndex = new List <int>(); if (IsMesh) { MeshTriangle f = _meshGeom.get_Triangle(ef); vertIndex.Add((int)f.get_Index(0)); vertIndex.Add((int)f.get_Index(1)); vertIndex.Add((int)f.get_Index(2)); } else { TriangleInShellComponent f = _geom.GetTriangle(ef); vertIndex.Add(f.VertexIndex0); vertIndex.Add(f.VertexIndex1); vertIndex.Add(f.VertexIndex2); } IndexFace intF = new IndexFace(vertIndex); facesColl.Add(ef, intF); // Keep faces in a dictionary and assigns ID List <int> fIDList; if (!faceSortedByNormal.TryGetValue(intF.normal, out fIDList)) { fIDList = new List <int>(); fIDList.Add(ef); faceSortedByNormal.Add(intF.normal, fIDList); } else { if (!fIDList.Contains(ef)) { fIDList.Add(ef); } } } foreach (KeyValuePair <XYZ, List <int> > fListDict in faceSortedByNormal) { List <int> mergedFaceList = null; if (fListDict.Value.Count > 1) { TryMergeFaces(fListDict.Value, out mergedFaceList); if (mergedFaceList != null && mergedFaceList.Count > 0) { // insert only new face indexes as the mergedlist from different vertices can be duplicated foreach (int fIdx in mergedFaceList) { if (!_mergedFaceList.Contains(fIdx)) { _mergedFaceList.Add(fIdx); } } } } else if (!_mergedFaceList.Contains(fListDict.Value[0])) { _mergedFaceList.Add(fListDict.Value[0]); // No pair face, add it into the mergedList } } }
public static string GetFacesAndEdges(Element e, bool startFromZero) { String xx = ""; bool RetainCurvedSurfaceFacets = true; // Get element geometry Options opt = new Options(); GeometryElement geomElem = e.get_Geometry(opt); int[] triangleIndices = new int[3]; XYZ[] triangleCorners = new XYZ[3]; List <string> faceVertices = new List <string>(); List <string> faceNormals = new List <string>(); List <string> faceElements = new List <string>(); //// First we need to get transformation //LocationCurve lc = e.Location as LocationCurve; //// Get curve starting- and endpoint //XYZ startingPoint = lc.Curve.GetEndPoint(0); //XYZ endPoint = lc.Curve.GetEndPoint(1); foreach (GeometryObject geomObj in geomElem) { Solid geomSolid = geomObj as Solid; if (null != geomSolid) { faceVertices.Clear(); faceNormals.Clear(); faceElements.Clear(); foreach (Face face in geomSolid.Faces) { // Triangulate face to get mesh Mesh mesh = face.Triangulate(); int nTriangles = mesh.NumTriangles; IList <XYZ> vertices = mesh.Vertices; int nVertices = vertices.Count; List <int> vertexCoordsMm = new List <int>(3 * nVertices); // A vertex may be reused several times with // different normals for different faces, so // we cannot precalculate normals per vertex. // List<double> normals = new List<double>( 3 * nVertices ); // Extract vertices foreach (XYZ v in vertices) { vertexCoordsMm.Add(ConvertLengthToMM(v.X)); vertexCoordsMm.Add(ConvertLengthToMM(v.Y)); vertexCoordsMm.Add(ConvertLengthToMM(v.Z)); } // Loop over triangles for (int i = 0; i < nTriangles; ++i) { MeshTriangle triangle = mesh.get_Triangle(i); for (int j = 0; j < 3; ++j) { int k = (int)triangle.get_Index(j); triangleIndices[j] = k; triangleCorners[j] = vertices[k]; } // Calculate constant triangle facet normal. XYZ v = triangleCorners[1] - triangleCorners[0]; XYZ w = triangleCorners[2] - triangleCorners[0]; XYZ triangleNormal = v .CrossProduct(w) .Normalize(); // List to store vertice indexes in the form: [v1//vn1 v2//vn2 v3//vn3] List <string> vertIndexes = new List <string>(); for (int j = 0; j < 3; ++j) { int nFaceVertices = faceVertices.Count; //if(nFaceVertices != faceNormals.Count) //{ // xx += "expected equal number of face vertex and normal coordinates\n"; //} int i3 = triangleIndices[j] * 3; // Rotate the X, Y and Z directions, // since the Z direction points upward // in Revit as opposed to sideways or // outwards or forwards in WebGL. string vStr = $"v {vertexCoordsMm[i3]} {vertexCoordsMm[i3 + 1]} {vertexCoordsMm[i3 + 2]}"; // get vertice index int vidx = faceVertices.IndexOf(vStr); // add if not exist if (vidx == -1) { faceVertices.Add(vStr); vidx = faceVertices.Count - 1; } string vnStr = ""; if (RetainCurvedSurfaceFacets) { vnStr = $"vn {Math.Round(triangleNormal.X, 2)} {Math.Round(triangleNormal.Y, 2)} {Math.Round(triangleNormal.Z, 2)}"; } else { UV uv = face.Project( triangleCorners[j]).UVPoint; XYZ normal = face.ComputeNormal(uv); vnStr = $"vn {Math.Round(normal.X, 2)} {Math.Round(normal.Y, 2)} {Math.Round(normal.Z, 2)}"; } // get face normal index int vnidx = faceNormals.IndexOf(vnStr); // add if not in list if (vnidx == -1) { faceNormals.Add(vnStr); vnidx = faceNormals.Count - 1; } // add indexes to list vertIndexes.Add($"{vidx+1+objStartIndex}/{vnidx+1 + objStartNormal}"); } // Store face elements string fStr = $"f {vertIndexes[0]} {vertIndexes[1]} {vertIndexes[2]}"; faceElements.Add(fStr); } } // Write to string xx += String.Join("\n\t", faceVertices) + "\n\t"; xx += String.Join("\n\t", faceNormals) + "\n\t"; xx += String.Join("\n\t", faceElements) + "\n\t"; if (!startFromZero) { objStartIndex += faceVertices.Count; objStartNormal += faceNormals.Count; } } Mesh geomMesh = geomObj as Mesh; Curve geomCurve = geomObj as Curve; Point geomPoint = geomObj as Point; PolyLine geomPoly = geomObj as PolyLine; GeometryInstance geomInst = geomObj as GeometryInstance; if (null != geomInst) { GeometryElement geomElement = geomInst.GetInstanceGeometry(); foreach (GeometryObject geomObj1 in geomElement) { Solid geomSolid1 = geomObj1 as Solid; if (null != geomSolid1) { Console.Out.WriteLine("got element: " + geomSolid1.Faces); } } } } return(xx); }
int getGeometry(Element e) { bool RetainCurvedSurfaceFacets = true; Options opt = new Options(); GeometryElement geo = e.get_Geometry(opt); if (geo == null) { return(0); } List <int> faceIndices = new List <int>(); List <double> faceVertices = new List <double>(); List <double> faceNormals = new List <double>(); int[] triangleIndices = new int[3]; XYZ[] triangleCorners = new XYZ[3]; foreach (GeometryObject obj in geo) { Solid solid = obj as Solid; if (solid != null && 0 < solid.Faces.Size) { faceIndices.Clear(); faceVertices.Clear(); faceNormals.Clear(); foreach (Face face in solid.Faces) { Mesh mesh = face.Triangulate(); int nTriangles = mesh.NumTriangles; IList <XYZ> vertices = mesh.Vertices; int nVertices = vertices.Count; List <double> vertexCoordsMm = new List <double>(3 * nVertices); // A vertex may be reused several times with // different normals for different faces, so // we cannot precalculate normals per vertex. //List<double> normals = new List<double>( 3 * nVertices ); foreach (XYZ v in vertices) { // Translate the entire element geometry // to the bounding box midpoint and scale // to metric millimetres. XYZ p = v; vertexCoordsMm.Add(p.X * _footToMm); vertexCoordsMm.Add(p.Y * _footToMm); vertexCoordsMm.Add(p.Z * _footToMm); } for (int i = 0; i < nTriangles; ++i) { MeshTriangle triangle = mesh.get_Triangle(i); for (int j = 0; j < 3; ++j) { int k = (int)triangle.get_Index(j); triangleIndices[j] = k; triangleCorners[j] = vertices[k]; } // Calculate constant triangle facet normal. XYZ v = triangleCorners[1] - triangleCorners[0]; XYZ w = triangleCorners[2] - triangleCorners[0]; XYZ triangleNormal = v .CrossProduct(w) .Normalize(); for (int j = 0; j < 3; ++j) { int nFaceVertices = faceVertices.Count; //Debug.Assert(nFaceVertices.Equals(faceNormals.Count), // "expected equal number of face vertex and normal coordinates"); faceIndices.Add(nFaceVertices / 3); int i3 = triangleIndices[j] * 3; // Rotate the X, Y and Z directions, // since the Z direction points upward // in Revit as opposed to sideways or // outwards or forwards in WebGL. faceVertices.Add(vertexCoordsMm[i3 + 1]); faceVertices.Add(vertexCoordsMm[i3 + 2]); faceVertices.Add(vertexCoordsMm[i3]); if (RetainCurvedSurfaceFacets) { faceNormals.Add(triangleNormal.Y); faceNormals.Add(triangleNormal.Z); faceNormals.Add(triangleNormal.X); } else { UV uv = face.Project( triangleCorners[j]).UVPoint; XYZ normal = face.ComputeNormal(uv); faceNormals.Add(normal.Y); faceNormals.Add(normal.Z); faceNormals.Add(normal.X); } } } } // Scale the vertices to a [-1,1] cube // centered around the origin. Translation // to the origin was already performed above. //double scale = 2.0 / FootToMm(MaxCoord(vsize)); //Debug.Print("position: [{0}],", // string.Join(", ", // faceVertices.ConvertAll<string>( // i => (i * scale).ToString("0.##")))); //Debug.Print("normal: [{0}],", // string.Join(", ", // faceNormals.ConvertAll<string>( // f => f.ToString("0.##")))); //Debug.Print("indices: [{0}],", // string.Join(", ", // faceIndices.ConvertAll<string>( // i => i.ToString()))); } } return(faceIndices.Count); }
private static void SortVerticesFromIntersectedTriangle(MeshTriangle _triangle, List <bool> leftSide, MeshTriangle leftMeshTriangle, MeshTriangle rightMeshTriangle) { // These boolean values help us determine if either 1 or 2 verices of the intersecting triangle lie on a specific side bool oneVertexLeft = false; bool oneVertexRight = false; // We sort the vertices of the triangle depending on which side of the plane it was on for (int i = 0; i < 3; i++) { if (leftSide[i]) { // First time we have a vertex on the left side, we assume that that's the only vertex on that side if (!oneVertexLeft) { oneVertexLeft = true; leftMeshTriangle.Vertices[0] = _triangle.Vertices[i]; leftMeshTriangle.Vertices[1] = leftMeshTriangle.Vertices[0]; leftMeshTriangle.UVs[0] = _triangle.UVs[i]; leftMeshTriangle.UVs[1] = leftMeshTriangle.UVs[0]; leftMeshTriangle.Normals[0] = _triangle.Normals[i]; leftMeshTriangle.Normals[1] = leftMeshTriangle.Normals[0]; } // If we encounter another vertex on the left side, simply overright what we had before else { leftMeshTriangle.Vertices[1] = _triangle.Vertices[i]; leftMeshTriangle.Normals[1] = _triangle.Normals[i]; leftMeshTriangle.UVs[1] = _triangle.UVs[i]; } } else { if (!oneVertexRight) { oneVertexRight = true; rightMeshTriangle.Vertices[0] = _triangle.Vertices[i]; rightMeshTriangle.Vertices[1] = rightMeshTriangle.Vertices[0]; rightMeshTriangle.UVs[0] = _triangle.UVs[i]; rightMeshTriangle.UVs[1] = rightMeshTriangle.UVs[0]; rightMeshTriangle.Normals[0] = _triangle.Normals[i]; rightMeshTriangle.Normals[1] = rightMeshTriangle.Normals[0]; } else { rightMeshTriangle.Vertices[1] = _triangle.Vertices[i]; rightMeshTriangle.Normals[1] = _triangle.Normals[i]; rightMeshTriangle.UVs[1] = _triangle.UVs[i]; } } } }
private static void CutTriangle(Plane _plane, MeshTriangle meshTri, bool tALS, bool TBLS, bool TCLS, GeneratedMesh lSide, GeneratedMesh rSide, List <Vector3> addedVert) { List <bool> leftSide = new List <bool>(); leftSide.Add(tALS); leftSide.Add(TBLS); leftSide.Add(TCLS); MeshTriangle leftMeshTriangle = new MeshTriangle(new Vector3[2], new Vector3[2], new Vector2[2], meshTri.SMIndex); MeshTriangle rightMeshTriangle = new MeshTriangle(new Vector3[2], new Vector3[2], new Vector2[2], meshTri.SMIndex); bool left = false; bool right = false; for (int i = 0; i < 3; i++) { if (leftSide[i]) { if (!left) { left = true; leftMeshTriangle.Vert[0] = meshTri.Vert[i]; leftMeshTriangle.Vert[1] = leftMeshTriangle.Vert[0]; leftMeshTriangle.UV[0] = meshTri.UV[i]; leftMeshTriangle.UV[1] = leftMeshTriangle.UV[0]; leftMeshTriangle.Norm[0] = meshTri.Norm[i]; leftMeshTriangle.Norm[1] = leftMeshTriangle.Norm[0]; } else { leftMeshTriangle.Vert[1] = meshTri.Vert[i]; leftMeshTriangle.Norm[1] = meshTri.Vert[i]; leftMeshTriangle.UV[1] = meshTri.Vert[i]; } } else { if (!right) { right = true; rightMeshTriangle.Vert[0] = meshTri.Vert[i]; rightMeshTriangle.Vert[1] = rightMeshTriangle.Vert[0]; rightMeshTriangle.UV[0] = meshTri.UV[i]; rightMeshTriangle.UV[1] = rightMeshTriangle.UV[0]; rightMeshTriangle.Norm[0] = meshTri.Norm[i]; rightMeshTriangle.Norm[1] = rightMeshTriangle.Norm[0]; } else { rightMeshTriangle.Vert[1] = meshTri.Vert[i]; rightMeshTriangle.Norm[1] = meshTri.Vert[i]; rightMeshTriangle.UV[1] = meshTri.Vert[i]; } } } float normalizedDistance; float distance; _plane.Raycast(new Ray(leftMeshTriangle.Vert[0], (rightMeshTriangle.Vert[0] - leftMeshTriangle.Vert[0]).normalized), out distance); normalizedDistance = distance / (rightMeshTriangle.Vert[0] - leftMeshTriangle.Vert[0]).magnitude; Vector3 vertLeft = Vector3.Lerp(leftMeshTriangle.Vert[0], rightMeshTriangle.Vert[0], normalizedDistance); addedVert.Add(vertLeft); Vector3 normalLeft = Vector3.Lerp(leftMeshTriangle.Norm[0], rightMeshTriangle.Norm[0], normalizedDistance); Vector2 uvLeft = Vector2.Lerp(leftMeshTriangle.UV[0], rightMeshTriangle.UV[0], normalizedDistance); _plane.Raycast(new Ray(leftMeshTriangle.Vert[1], (rightMeshTriangle.Vert[1] - leftMeshTriangle.Vert[1]).normalized), out distance); normalizedDistance = distance / (rightMeshTriangle.Vert[1] - leftMeshTriangle.Vert[1]).magnitude; Vector3 vertRight = Vector3.Lerp(leftMeshTriangle.Vert[1], rightMeshTriangle.Vert[1], normalizedDistance); addedVert.Add(vertLeft); Vector3 normalRight = Vector3.Lerp(leftMeshTriangle.Norm[1], rightMeshTriangle.Norm[1], normalizedDistance); Vector2 uvRight = Vector2.Lerp(leftMeshTriangle.UV[1], rightMeshTriangle.UV[1], normalizedDistance); MeshTriangle currentTriangle; Vector3[] updatedVert = new Vector3[] { leftMeshTriangle.Vert[0], vertLeft, vertRight }; Vector3[] updatedNorm = new Vector3[] { leftMeshTriangle.Norm[0], normalLeft, normalRight }; Vector2[] updatedUV = new Vector2[] { leftMeshTriangle.UV[0], uvLeft, uvRight }; currentTriangle = new MeshTriangle(updatedVert, updatedNorm, updatedUV, meshTri.SMIndex); if (updatedVert[0] != updatedVert[1] && updatedVert[0] != updatedVert[2]) { if (Vector3.Dot(Vector3.Cross(updatedVert[1] - updatedVert[0], updatedVert[2] - updatedVert[0]), updatedVert[0]) < 0) { FlipTriangle(currentTriangle); } lSide.AddTriangle(currentTriangle); } updatedVert = new Vector3[] { leftMeshTriangle.Vert[0], leftMeshTriangle.Vert[1], vertRight }; updatedNorm = new Vector3[] { leftMeshTriangle.Norm[0], leftMeshTriangle.Norm[1], normalRight }; updatedUV = new Vector2[] { leftMeshTriangle.UV[0], uvLeft, uvRight }; currentTriangle = new MeshTriangle(updatedVert, updatedNorm, updatedUV, meshTri.SMIndex); if (updatedVert[0] != updatedVert[1] && updatedVert[0] != updatedVert[2]) { if (Vector3.Dot(Vector3.Cross(updatedVert[1] - updatedVert[0], updatedVert[2] - updatedVert[0]), updatedVert[0]) < 0) { FlipTriangle(currentTriangle); } lSide.AddTriangle(currentTriangle); } updatedVert = new Vector3[] { rightMeshTriangle.Vert[0], vertLeft, vertRight }; updatedNorm = new Vector3[] { rightMeshTriangle.Norm[0], normalLeft, normalRight }; updatedUV = new Vector2[] { rightMeshTriangle.UV[0], uvLeft, uvRight }; currentTriangle = new MeshTriangle(updatedVert, updatedNorm, updatedUV, meshTri.SMIndex); if (updatedVert[0] != updatedVert[1] && updatedVert[0] != updatedVert[2]) { if (Vector3.Dot(Vector3.Cross(updatedVert[1] - updatedVert[0], updatedVert[2] - updatedVert[0]), updatedVert[0]) < 0) { FlipTriangle(currentTriangle); } rSide.AddTriangle(currentTriangle); } updatedVert = new Vector3[] { rightMeshTriangle.Vert[0], rightMeshTriangle.Vert[1], vertRight }; updatedNorm = new Vector3[] { rightMeshTriangle.Norm[0], rightMeshTriangle.Norm[1], normalRight }; updatedUV = new Vector2[] { rightMeshTriangle.UV[0], uvLeft, uvRight }; currentTriangle = new MeshTriangle(updatedVert, updatedNorm, updatedUV, meshTri.SMIndex); if (updatedVert[0] != updatedVert[1] && updatedVert[0] != updatedVert[2]) { if (Vector3.Dot(Vector3.Cross(updatedVert[1] - updatedVert[0], updatedVert[2] - updatedVert[0]), updatedVert[0]) < 0) { FlipTriangle(currentTriangle); } rSide.AddTriangle(currentTriangle); } }
public static void Cut(GameObject _originalGameObject, Vector3 _contactPoint, Vector3 _direction, Material _cutMaterial = null, bool fill = true, bool _addRigidBody = false) { if (currentlyCutting) { return; } currentlyCutting = true; Plane plane = new Plane(_originalGameObject.transform.InverseTransformDirection(-_direction), _originalGameObject.transform.InverseTransformPoint(_contactPoint)); originalGameObject = _originalGameObject; originalMesh = _originalGameObject.GetComponent <MeshFilter>().mesh; List <Vector3> addedVertices = new List <Vector3>(); GeneratedMesh leftMesh = new GeneratedMesh(); GeneratedMesh rightMesh = new GeneratedMesh(); int[] submeshIndices; int triangleIndexA, triangleIndexB, triangleIndexC; for (int i = 0; i < originalMesh.subMeshCount; i++) { submeshIndices = originalMesh.GetTriangles(i); for (int j = 0; j < submeshIndices.Length; j += 3) { triangleIndexA = submeshIndices[j]; triangleIndexB = submeshIndices[j + 1]; triangleIndexC = submeshIndices[j + 2]; MeshTriangle currentTriangle = GetTriangle(triangleIndexA, triangleIndexB, triangleIndexC, i); bool triangleALeftSide = plane.GetSide(originalMesh.vertices[triangleIndexA]); bool triangleBLeftSide = plane.GetSide(originalMesh.vertices[triangleIndexB]); bool triangleCLeftSide = plane.GetSide(originalMesh.vertices[triangleIndexC]); /* * Three different cases: * - The triangle is either above the plane * - The triangle is below the plane * - The place intersects the triangle */ if (triangleALeftSide && triangleBLeftSide && triangleCLeftSide) { leftMesh.AddTriangle(currentTriangle); } else if (!triangleALeftSide && !triangleBLeftSide && !triangleCLeftSide) { rightMesh.AddTriangle(currentTriangle); } else { CutTriangle(plane, currentTriangle, triangleALeftSide, triangleBLeftSide, triangleCLeftSide, leftMesh, rightMesh, addedVertices); } } } // if either mesh has no vertices, return if (leftMesh.Vertices.Count == 0 || rightMesh.Vertices.Count == 0 || addedVertices.Count == 0) { currentlyCutting = false; return; } FillCut(addedVertices, plane, leftMesh, rightMesh); GenerateGameObject(leftMesh); GenerateGameObject(rightMesh); Object.Destroy(_originalGameObject); currentlyCutting = false; }
/// <summary> /// Function called before and after triangle merging. /// Before merging it calculates the Euler characteristic of the original mesh. /// After merging it calculates the Euler characteristic of the merged mesh. /// </summary> private int CalculateEulerCharacteristic() { int noVertices = 0; int noHoles = 0; // Stays zero if mesh is triangular int noFaces; HashSet <IndexSegment> edges = new HashSet <IndexSegment>(new SegmentComparer(true /*compareBothDirections*/)); HashSet <int> vertices = new HashSet <int>(); if (m_MergedFaceSet.Count != 0) { // Merging already occurred, calculate new Euler characteristic noFaces = m_MergedFaceSet.Count; foreach (int mergedFace in m_MergedFaceSet) { m_FacesCollDict[mergedFace].IndexOuterBoundary.ToList().ForEach(vt => vertices.Add(vt)); if (m_FacesCollDict[mergedFace].IndexedInnerBoundaries != null) { foreach (IList <int> innerB in m_FacesCollDict[mergedFace].IndexedInnerBoundaries) { innerB.ToList().ForEach(vt => vertices.Add(vt)); } } m_FacesCollDict[mergedFace].OuterAndInnerBoundaries.ToList().ForEach(vp => edges.Add(vp.Value)); if (m_FacesCollDict[mergedFace].IndexedInnerBoundaries != null) { noHoles += m_FacesCollDict[mergedFace].IndexedInnerBoundaries.Count; } } noVertices = vertices.Count; // Vertices must be counted from the final merged faces as some of the inner vertices may disappear after stitching } else { if (IsMesh) { noVertices = m_MeshGeom.Vertices.Count; noFaces = m_MeshGeom.NumTriangles; for (int faceIdx = 0; faceIdx < noFaces; faceIdx++) { MeshTriangle tri = m_MeshGeom.get_Triangle(faceIdx); edges.Add(new IndexSegment((int)tri.get_Index(0), (int)tri.get_Index(1))); edges.Add(new IndexSegment((int)tri.get_Index(1), (int)tri.get_Index(2))); edges.Add(new IndexSegment((int)tri.get_Index(2), (int)tri.get_Index(0))); } } else { noVertices = m_Geom.VertexCount; noFaces = m_Geom.TriangleCount; for (int faceIdx = 0; faceIdx < noFaces; faceIdx++) { TriangleInShellComponent tri = m_Geom.GetTriangle(faceIdx); edges.Add(new IndexSegment(tri.VertexIndex0, tri.VertexIndex1)); edges.Add(new IndexSegment(tri.VertexIndex1, tri.VertexIndex2)); edges.Add(new IndexSegment(tri.VertexIndex2, tri.VertexIndex0)); } } } // V - E + F - I return(noVertices - edges.Count + noFaces - noHoles); }
private static void MakeTriangles(Plane _plane, MeshTriangle _triangle, GeneratedMesh _currentSide, List <Vector3> _addedVertices, MeshTriangle currentMeshTriangle, MeshTriangle oppositeMeshTriangle, bool addVertices) { float normalizedDistance; float distance; // Get the distance from the vertex to the intersecting plane, in the direction of a vertex that we know exists on the other side of the intersection // From our original triangle _plane.Raycast(new Ray(currentMeshTriangle.Vertices[0], (oppositeMeshTriangle.Vertices[0] - currentMeshTriangle.Vertices[0]).normalized), out distance); normalizedDistance = distance / (oppositeMeshTriangle.Vertices[0] - currentMeshTriangle.Vertices[0]).magnitude; Vector3 vertLeft = Vector3.Lerp(currentMeshTriangle.Vertices[0], oppositeMeshTriangle.Vertices[0], normalizedDistance); Vector3 normalLeft = Vector3.Lerp(currentMeshTriangle.Normals[0], oppositeMeshTriangle.Normals[0], normalizedDistance); Vector2 uvLeft = Vector2.Lerp(currentMeshTriangle.UVs[0], oppositeMeshTriangle.UVs[0], normalizedDistance); _plane.Raycast(new Ray(currentMeshTriangle.Vertices[1], (oppositeMeshTriangle.Vertices[1] - currentMeshTriangle.Vertices[1]).normalized), out distance); normalizedDistance = distance / (oppositeMeshTriangle.Vertices[1] - currentMeshTriangle.Vertices[1]).magnitude; Vector3 vertRight = Vector3.Lerp(currentMeshTriangle.Vertices[1], oppositeMeshTriangle.Vertices[1], normalizedDistance); // Since we call this method twice, prevent adding new vertices twice if (addVertices) { _addedVertices.Add(vertLeft); _addedVertices.Add(vertRight); } Vector3 normalRight = Vector3.Lerp(currentMeshTriangle.Normals[1], oppositeMeshTriangle.Normals[1], normalizedDistance); Vector3 uvRight = Vector2.Lerp(currentMeshTriangle.UVs[1], oppositeMeshTriangle.UVs[1], normalizedDistance); MeshTriangle currentTriangle; Vector3[] updatedVertices = new Vector3[] { currentMeshTriangle.Vertices[0], vertLeft, vertRight }; Vector3[] updatedNormals = new Vector3[] { currentMeshTriangle.Normals[0], normalLeft, normalRight }; Vector2[] updatedUVs = new Vector2[] { currentMeshTriangle.UVs[0], uvLeft, uvRight }; currentTriangle = new MeshTriangle(updatedVertices, updatedNormals, updatedUVs, _triangle.SubmeshIndex); if (updatedVertices[0] != updatedVertices[1] && updatedVertices[0] != updatedVertices[2]) { if (Vector3.Dot(Vector3.Cross(updatedVertices[1] - updatedVertices[0], updatedVertices[2] - updatedVertices[0]), updatedNormals[0]) < 0) { FlipTriangle(currentTriangle); } _currentSide.AddTriangle(currentTriangle); } updatedVertices = new Vector3[] { currentMeshTriangle.Vertices[0], currentMeshTriangle.Vertices[1], vertRight }; updatedNormals = new Vector3[] { currentMeshTriangle.Normals[0], currentMeshTriangle.Normals[1], normalRight }; updatedUVs = new Vector2[] { currentMeshTriangle.UVs[0], currentMeshTriangle.UVs[1], uvRight }; currentTriangle = new MeshTriangle(updatedVertices, updatedNormals, updatedUVs, _triangle.SubmeshIndex); if (updatedVertices[0] != updatedVertices[1] && updatedVertices[0] != updatedVertices[2]) { if (Vector3.Dot(Vector3.Cross(updatedVertices[1] - updatedVertices[0], updatedVertices[2] - updatedVertices[0]), updatedNormals[0]) < 0) { FlipTriangle(currentTriangle); } _currentSide.AddTriangle(currentTriangle); } }
public static void Cut(GameObject _originalGameObject, Vector3 _contactPoint, Vector3 _direction, Material _cutMaterial = null, bool _fill = true, bool _addRigidbody = false) { if (currentlyCutting) { return; } currentlyCutting = true; Plane plane = new Plane(_originalGameObject.transform.InverseTransformDirection(-_direction), _originalGameObject.transform.InverseTransformDirection(_contactPoint)); originalMesh = _originalGameObject.GetComponent <MeshFilter>().mesh; List <Vector3> addedVertices = new List <Vector3>(); GeneratedMesh leftMesh = new GeneratedMesh(); GeneratedMesh rightMesh = new GeneratedMesh(); int[] submeshIndices; int triangleIndexA, triangleIndexB, triangleIndexC; for (int i = 0; i < originalMesh.subMeshCount; ++i) { submeshIndices = originalMesh.GetTriangles(i); for (int j = 0; j < submeshIndices.Length; j += 3) { triangleIndexA = submeshIndices[j]; triangleIndexB = submeshIndices[j + 1]; triangleIndexC = submeshIndices[j + 2]; MeshTriangle currentTriangle = GetTriangle(triangleIndexA, triangleIndexB, triangleIndexC, i); bool triangleALeftSide = plane.GetSide(originalMesh.vertices[triangleIndexA]); bool triangleBLeftSide = plane.GetSide(originalMesh.vertices[triangleIndexB]); bool triangleCLeftSide = plane.GetSide(originalMesh.vertices[triangleIndexC]); if (triangleALeftSide && triangleBLeftSide && triangleCLeftSide) { leftMesh.AddTriangle(currentTriangle); } else if (!triangleALeftSide && !triangleBLeftSide && !triangleCLeftSide) { rightMesh.AddTriangle(currentTriangle); } else { CutTriangle(plane, currentTriangle, triangleALeftSide, triangleBLeftSide, triangleCLeftSide, leftMesh, rightMesh, addedVertices); } } } if (_fill) { FillCut(addedVertices, plane, leftMesh, rightMesh); } originalMesh.Clear(); originalMesh.vertices = leftMesh.Vertices.ToArray(); originalMesh.normals = leftMesh.Normals.ToArray(); originalMesh.uv = leftMesh.UVs.ToArray(); originalMesh.triangles = leftMesh.Indices(0); GameObject secondGameObject = GameObject.Instantiate(_originalGameObject); Mesh secondMesh = secondGameObject.GetComponent <MeshFilter>().mesh; secondMesh.vertices = rightMesh.Vertices.ToArray(); secondMesh.normals = rightMesh.Normals.ToArray(); secondMesh.uv = rightMesh.UVs.ToArray(); secondMesh.triangles = rightMesh.Indices(0); Component.Destroy(_originalGameObject.GetComponent <SphereCollider>()); Component.Destroy(secondGameObject.GetComponent <SphereCollider>()); _originalGameObject.AddComponent <MeshCollider>(); secondGameObject.AddComponent <MeshCollider>(); _originalGameObject.GetComponent <MeshCollider>().convex = true; secondGameObject.GetComponent <MeshCollider>().convex = true; currentlyCutting = false; }
private static void Fill(List <Vector3> _vertices, Plane _plane, GeneratedMesh _leftMesh, GeneratedMesh _rightMesh) { Vector3 centerPosition = Vector3.zero; for (int i = 0; i < _vertices.Count; i++) { centerPosition += _vertices[i]; } centerPosition = centerPosition / _vertices.Count; Vector3 up = new Vector3() { x = _plane.normal.x, y = _plane.normal.y, z = _plane.normal.z }; Vector3 left = Vector3.zero; Vector3 displacement = Vector3.zero; Vector2 uv1 = Vector2.zero; Vector2 uv2 = Vector2.zero; for (int i = 0; i < _vertices.Count; i++) { displacement = _vertices[i] - centerPosition; uv1 = new Vector2() { x = .5f + Vector3.Dot(displacement, left), y = .5f + Vector3.Dot(displacement, up) }; displacement = _vertices[(i + 1) % _vertices.Count] - centerPosition; uv2 = new Vector2() { x = .5f + Vector3.Dot(displacement, left), y = .5f + Vector3.Dot(displacement, up) }; Vector3[] vertices = new Vector3[] { _vertices[i], _vertices[(i + 1) % _vertices.Count], centerPosition }; Vector3[] normals = new Vector3[] { -_plane.normal, -_plane.normal, -_plane.normal }; Vector2[] uvs = new Vector2[] { uv1, uv2, new Vector2(0.5f, 0.5f) }; MeshTriangle currentTriangle = new MeshTriangle(vertices, normals, uvs, originalMesh.subMeshCount + 1); // Make sure triangle is facing the right way if (Vector3.Dot(Vector3.Cross(vertices[1] - vertices[0], vertices[2] - vertices[0]), normals[0]) < 0) { FlipTriangle(currentTriangle); } _leftMesh.AddTriangle(currentTriangle); normals = new Vector3[] { _plane.normal, _plane.normal, _plane.normal }; currentTriangle = new MeshTriangle(vertices, normals, uvs, originalMesh.subMeshCount + 1); if (Vector3.Dot(Vector3.Cross(vertices[1] - vertices[0], vertices[2] - vertices[0]), normals[0]) < 0) { FlipTriangle(currentTriangle); } _rightMesh.AddTriangle(currentTriangle); } }
public static void Fill(List <Vector3> _vertices, Plane _plane, GeneratedMesh _leftMesh, GeneratedMesh _rightMesh) { // Firstly we need the center we do this by adding up all the vertices and then calculating the average Vector3 centerPosition = Vector3.zero; for (int i = 0; i < _vertices.Count; ++i) { centerPosition += _vertices[i]; } centerPosition = centerPosition / _vertices.Count; // We now need an Upward Axis we use the plane we cut the mesh with for that Vector3 up = new Vector3() { x = _plane.normal.x, y = _plane.normal.y, z = _plane.normal.z }; Vector3 left = Vector3.Cross(_plane.normal, _plane.normal); Vector3 displacement = Vector3.zero; Vector2 uv1 = Vector2.zero; Vector2 uv2 = Vector2.zero; for (int i = 0; i < _vertices.Count; ++i) { displacement = _vertices[i] - centerPosition; uv1 = new Vector2() { x = 0.5f + Vector3.Dot(displacement, left), y = 0.5f + Vector3.Dot(displacement, up) }; displacement = _vertices[(i + 1) % _vertices.Count] - centerPosition; uv2 = new Vector2() { x = 0.5f + Vector3.Dot(displacement, left), y = 0.5f + Vector3.Dot(displacement, up) }; Vector3[] vertices = new Vector3[] { _vertices[i], _vertices[(i + 1) % _vertices.Count], centerPosition }; Vector3[] normals = new Vector3[] { -_plane.normal, -_plane.normal, -_plane.normal }; Vector2[] uvs = new Vector2[] { uv1, uv2, new Vector2(0.5f, 0.5f) }; MeshTriangle currentTriangle = new MeshTriangle(vertices, normals, uvs, originalMesh.subMeshCount + 1); if (Vector3.Dot(Vector3.Cross(vertices[1] - vertices[0], vertices[2] - vertices[0]), normals[0]) < 0) { FlipTriangle(currentTriangle); } _leftMesh.AddTriangle(currentTriangle); normals = new Vector3[] { _plane.normal, _plane.normal, _plane.normal }; currentTriangle = new MeshTriangle(vertices, normals, uvs, originalMesh.subMeshCount + 1); if (Vector3.Dot(Vector3.Cross(vertices[1] - vertices[0], vertices[2] - vertices[0]), normals[0]) < 0) { FlipTriangle(currentTriangle); } _rightMesh.AddTriangle(currentTriangle); } }
private static void FlipTriangle(MeshTriangle triangle) { triangle.Vertices.Reverse(); triangle.Normals.Reverse(); triangle.UVs.Reverse(); }
private void Stream(ArrayList data, MeshTriangle meshTri) { data.Add(new Snoop.Data.ClassSeparator(typeof(MeshTriangle))); // TBD: not sure what get_index() is all about?? data.Add(new Snoop.Data.Xyz("Vertex [0]", meshTri.get_Vertex(0))); data.Add(new Snoop.Data.Xyz("Vertex [1]", meshTri.get_Vertex(1))); data.Add(new Snoop.Data.Xyz("Vertex [2]", meshTri.get_Vertex(2))); }
private static MeshTriangle[] ExtractSubmeshTriangles( SubMesh subMesh ) { int[] vertIdx = new int[ 3 ]; Vector3[] vertPos = new Vector3[ 3 ]; VertexElement posElem = subMesh.vertexData.vertexDeclaration.FindElementBySemantic( VertexElementSemantic.Position ); HardwareVertexBuffer posBuffer = posBuffer = subMesh.vertexData.vertexBufferBinding.GetBuffer( posElem.Source ); IntPtr indexPtr = subMesh.indexData.indexBuffer.Lock( BufferLocking.ReadOnly ); IntPtr posPtr = posBuffer.Lock( BufferLocking.ReadOnly ); int posOffset = posElem.Offset / sizeof( float ); int posStride = posBuffer.VertexSize / sizeof( float ); int numFaces = subMesh.indexData.indexCount / 3; MeshTriangle[] triangles = new MeshTriangle[ numFaces ]; unsafe { int* pIdxInt32 = null; short* pIdxShort = null; float* pVPos = (float*) posPtr.ToPointer(); if( subMesh.indexData.indexBuffer.Type == IndexType.Size32 ) pIdxInt32 = (int*) indexPtr.ToPointer(); else pIdxShort = (short*) indexPtr.ToPointer(); // loop through all faces to calculate the tangents for( int n = 0; n < numFaces; n++ ) { for( int i = 0; i < 3; i++ ) { // get indices of vertices that form a polygon in the position buffer if( subMesh.indexData.indexBuffer.Type == IndexType.Size32 ) vertIdx[ i ] = pIdxInt32[ 3 * n + i ]; else vertIdx[ i ] = pIdxShort[ 3 * n + i ]; vertPos[ i ].x = pVPos[ vertIdx[ i ] * posStride + posOffset ]; vertPos[ i ].y = pVPos[ vertIdx[ i ] * posStride + posOffset + 1 ]; vertPos[ i ].z = pVPos[ vertIdx[ i ] * posStride + posOffset + 2 ]; } triangles[ n ] = new MeshTriangle( vertPos[ 0 ], vertPos[ 1 ], vertPos[ 2 ] ); } } posBuffer.Unlock(); subMesh.indexData.indexBuffer.Unlock(); if( DoLog ) { int count = triangles.Length; Log( string.Format( " extracted {0} triangles", count ) ); for( int i = 0; i < count; i++ ) Log( string.Format( " {0}", triangles[ i ].ToString() ) ); } return triangles; }