void Start() { // Enable fracturable object collider FracturedObject fracturedObject = GetComponent <FracturedObject>(); pv = fracturedObject.GetComponent <PhotonView> (); // Disable chunk colliders k1 = GameObject.Find("k1").GetComponent <Text>(); k2 = GameObject.Find("k2").GetComponent <Text>(); k3 = GameObject.Find("k3").GetComponent <Text>(); k4 = GameObject.Find("k4").GetComponent <Text>(); if (fracturedObject != null) { if (fracturedObject.GetComponent <Collider>() != null) { fracturedObject.GetComponent <Collider>().enabled = true; } else { Debug.LogWarning("Fracturable Object " + gameObject.name + " has a dynamic rigidbody but no collider. Object will not be able to collide."); } for (int i = 0; i < fracturedObject.ListFracturedChunks.Count; i++) { EnableObjectColliders(fracturedObject.ListFracturedChunks[i].gameObject, false); } } }
public static int ComputeHull(GameObject gameObject, FracturedObject fracturedObject) { int nTotalTriangles = 0; if (ComputeHull(gameObject, fracturedObject.ChunkColliderType == FracturedObject.ColliderType.Trigger, fracturedObject.ConcaveColliderAlgorithm, fracturedObject.ConcaveColliderMaxHulls, fracturedObject.ConcaveColliderMaxHullVertices, fracturedObject.ConcaveColliderLegacySteps, fracturedObject.Verbose, out nTotalTriangles) == false) { if (fracturedObject.ConcaveColliderAlgorithm == FracturedObject.ECCAlgorithm.Fast) { // Fast failed. Try with normal. if (fracturedObject.Verbose) { Debug.Log(gameObject.name + ": Falling back to normal convex decomposition algorithm"); } if (ComputeHull(gameObject, fracturedObject.ChunkColliderType == FracturedObject.ColliderType.Trigger, FracturedObject.ECCAlgorithm.Normal, fracturedObject.ConcaveColliderMaxHulls, fracturedObject.ConcaveColliderMaxHullVertices, fracturedObject.ConcaveColliderLegacySteps, fracturedObject.Verbose, out nTotalTriangles) == false) { if (fracturedObject.Verbose) { Debug.Log(gameObject.name + ": Falling back to box collider"); } } } } return(nTotalTriangles); }
public static int ComputeHull(GameObject gameObject, FracturedObject fracturedObject) { int nTotalTriangles = 0; if(ComputeHull(gameObject, fracturedObject.ConcaveColliderAlgorithm, fracturedObject.ConcaveColliderMaxHulls, fracturedObject.ConcaveColliderMaxHullVertices, fracturedObject.ConcaveColliderLegacySteps, fracturedObject.Verbose, out nTotalTriangles) == false) { if(fracturedObject.ConcaveColliderAlgorithm == FracturedObject.ECCAlgorithm.Fast) { // Fast failed. Try with normal. if(fracturedObject.Verbose) { Debug.Log(gameObject.name + ": Falling back to normal convex decomposition algorithm"); } if(ComputeHull(gameObject, FracturedObject.ECCAlgorithm.Normal, fracturedObject.ConcaveColliderMaxHulls, fracturedObject.ConcaveColliderMaxHullVertices, fracturedObject.ConcaveColliderLegacySteps, fracturedObject.Verbose, out nTotalTriangles) == false) { if(fracturedObject.Verbose) { Debug.Log(gameObject.name + ": Falling back to box collider"); } } } } return nTotalTriangles; }
public void OnCreateFromFracturedObject(FracturedObject fracturedComponent, int nSplitSubMeshIndex) { FracturedObjectSource = fracturedComponent; SplitSubMeshIndex = nSplitSubMeshIndex; RandomMaterialColor = new Color(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value, 0.7f); m_v3InitialLocalPosition = transform.localPosition; }
// Use this for initialization void Start() { fractureWall = gameObject.GetComponent <FracturedObject> (); fractureWall.TotalMass = Random.Range(2, 3); fractureWall.ChunkConnectionStrength = Random.Range(0.2f, 0.5f); }
public void ApplyFractures() { MeshFilter[] allChildren = GetComponentsInChildren <MeshFilter> (); List <float> floatlist = new List <float> (); foreach (MeshFilter child in allChildren) { float volume = child.sharedMesh.bounds.size.x * child.sharedMesh.bounds.size.y * child.sharedMesh.bounds.size.z; floatlist.Add(volume); } floatlist.Sort(); float listmin = floatlist [0]; float listmax = floatlist [floatlist.Count - 1]; float liststep = (listmax - listmin) / (MaximumFracks - 2); int liststepint = (int)liststep; foreach (MeshFilter child in allChildren) { fobj = Instantiate(frack, PlaceForFractures); fobj.name = child.name + "_frack"; fobj.SourceObject = child.gameObject; fobj.RandomSeed = Random.Range(0, 65536); //fobj.EventDetachMinMass = DetachValue; //fobj.EventDetachMinVelocity = DetachValue; fobj.SplitMaterial = InteriorMaterial; // Split Dimensions float dimsum = child.sharedMesh.bounds.size.x + child.sharedMesh.bounds.size.y + child.sharedMesh.bounds.size.z; fobj.SplitXProbability = child.sharedMesh.bounds.size.x / dimsum; fobj.SplitYProbability = child.sharedMesh.bounds.size.y / dimsum; fobj.SplitZProbability = child.sharedMesh.bounds.size.z / dimsum; fobj.SplitXVariation = child.sharedMesh.bounds.size.x / dimsum; fobj.SplitYVariation = child.sharedMesh.bounds.size.y / dimsum; fobj.SplitZVariation = child.sharedMesh.bounds.size.z / dimsum; float volume = child.sharedMesh.bounds.size.x * child.sharedMesh.bounds.size.y * child.sharedMesh.bounds.size.z; fobj.TotalMass = volume * WeightMultiplier; //fobj.StartStatic = true; fobj.GenerateNumChunks = (int)(volume / liststepint) + 2; List <GameObject> listGameObjects; try { UltimateFracturing.Fracturer.FractureToChunks(fobj, true, out listGameObjects, Progress); } catch (System.Exception e) { Debug.LogError(string.Format("Exception computing chunks ({0}):\n{1}", e.Message, e.StackTrace)); } EditorUtility.ClearProgressBar(); } }
void OnCollisionEnter(Collision collision) { if (collision.contacts == null) { return; } if (collision.contacts.Length == 0) { return; } // Was it a big enough hit? FracturedObject fracturedObject = gameObject.GetComponent <FracturedObject>(); if (fracturedObject != null) { float fMass = collision.rigidbody != null ? collision.rigidbody.mass : Mathf.Infinity; if (collision.relativeVelocity.magnitude > fracturedObject.EventDetachMinVelocity && fMass > fracturedObject.EventDetachMinVelocity) { // Disable fracturable object collider fracturedObject.GetComponent <Collider>().enabled = false; Rigidbody fracturableRigidbody = fracturedObject.GetComponent <Rigidbody>(); if (fracturableRigidbody != null) { fracturableRigidbody.isKinematic = true; } // Enable chunk colliders for (int i = 0; i < fracturedObject.ListFracturedChunks.Count; i++) { EnableObjectColliders(fracturedObject.ListFracturedChunks[i].gameObject, true); } // Explode fracturedObject.Explode(collision.contacts[0].point, collision.relativeVelocity.magnitude); } } }
public void ResetChunk(FracturedObject fracturedObjectSource) { transform.parent = fracturedObjectSource.transform; rigidbody.isKinematic = true; IsNonSupportedChunk = m_bNonSupportedChunkStored; FracturedObjectSource = fracturedObjectSource; IsDetachedChunk = false; transform.localPosition = m_v3InitialLocalPosition; if (m_bInitialLocalRotScaleInitialized) { transform.localRotation = m_qInitialLocalRotation; transform.localScale = m_v3InitialLocalScale; } ListAdjacentChunks = new List <AdjacencyInfo>(ListAdjacentChunksCopy); m_fInvisibleTimer = 0.0f; }
public void OnSceneGUI() { FracturedChunk fracturedChunk = target as FracturedChunk; if (fracturedChunk == null) { return; } FracturedObject fracturedObject = fracturedChunk.FracturedObjectSource; // Chunk connections bool bDrawLines = true; if (fracturedObject != null) { bDrawLines = fracturedObject.ShowChunkConnectionLines; } if (bDrawLines) { Color handlesColor = Handles.color; Handles.color = new Color32(155, 89, 182, 255); if (fracturedChunk.ListAdjacentChunks.Count > 0) { Handles.DotHandleCap(0, fracturedChunk.transform.position, Quaternion.identity, HandleUtility.GetHandleSize(fracturedChunk.transform.position) * 0.03f, Event.current.type); } foreach (FracturedChunk.AdjacencyInfo chunkAdjacency in fracturedChunk.ListAdjacentChunks) { if (chunkAdjacency.chunk) { Handles.DotHandleCap(0, chunkAdjacency.chunk.transform.position, Quaternion.identity, HandleUtility.GetHandleSize(chunkAdjacency.chunk.transform.position) * 0.03f, Event.current.type); Handles.DrawLine(fracturedChunk.transform.position, chunkAdjacency.chunk.transform.position); } } Handles.color = handlesColor; } }
public override void updateLife(Damage d) { base.updateLife(d); if (lifeSlider != null) { lifeSlider.value = (float)(life) / maxLife; } if (isDead) { GetComponent <Collider>().enabled = false; FracturedObject f = transform.parent.GetComponentInChildren <FracturedObject>(); if (f != null) { //Exploding the fractured object using Ultimate Game Tool fractured object f.SupportChunksAreIndestructible = false; f.Explode(new Vector3(transform.position.x, 0, transform.position.z), 100f, 100f, false, false, false, false); } Destroy(this.transform.parent.gameObject); } }
public void OnCreateFromFracturedObject(FracturedObject fracturedComponent, int nSplitSubMeshIndex) { FracturedObjectSource = fracturedComponent; SplitSubMeshIndex = nSplitSubMeshIndex; RandomMaterialColor = new Color(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value, 0.7f); m_v3InitialLocalPosition = transform.localPosition; m_qInitialLocalRotation = transform.localRotation; m_v3InitialLocalScale = transform.localScale; m_bInitialLocalRotScaleInitialized = true; }
public void ResetChunk(FracturedObject fracturedObjectSource) { transform.parent = fracturedObjectSource.transform; rigidbody.isKinematic = true; IsNonSupportedChunk = m_bNonSupportedChunkStored; FracturedObjectSource = fracturedObjectSource; IsDetachedChunk = false; transform.localPosition = m_v3InitialLocalPosition; if(m_bInitialLocalRotScaleInitialized) { transform.localRotation = m_qInitialLocalRotation; transform.localScale = m_v3InitialLocalScale; } ListAdjacentChunks = new List<AdjacencyInfo>(ListAdjacentChunksCopy); m_fInvisibleTimer = 0.0f; }
void OnCollisionEnter(Collision collision) { if (collision.contacts == null) { return; } if (collision.contacts.Length == 0) { return; } // Was it a big enough hit? FracturedObject fracturedObject = gameObject.GetComponent <FracturedObject>(); if (fracturedObject != null) { float fMass = collision.rigidbody != null ? collision.rigidbody.mass : Mathf.Infinity; //Debug.Log (collision.gameObject.tag.ToString ());충돌체의 tag탐색 //Debug.Log(collision.gameObject.GetComponent<FracturedObject>().EventDetachMinMass.ToString()); if (collision.relativeVelocity.magnitude > fracturedObject.EventDetachMinVelocity && fMass > fracturedObject.EventDetachMinVelocity) { // Disable fracturable object collider if (collision.rigidbody != null) { //SendKill (PhotonNetwork.player.ID); fracturedObject.EventDetachMinMass -= collision.rigidbody.mass; } if (fracturedObject.EventDetachMinMass < 0) { //Debug.Log (collision.gameObject.GetComponent<PhotonView> ().ownerId.ToString ()); //부순사람 카운트 업 SendKill(collision.gameObject.GetComponent <PhotonView> ().ownerId); //부셔진돌 캔버스 제거 //DeleteName1 (fracturedObject,collision); //fracturedObject.transform.Find("Canvas").GetComponent<Canvas>().enabled = false; //Debug.Log (fracturedObject.name); fracturedObject.GetComponent <Collider> ().enabled = false; Rigidbody fracturableRigidbody = fracturedObject.GetComponent <Rigidbody> (); if (fracturableRigidbody != null) { fracturableRigidbody.isKinematic = true; } for (int i = 0; i < fracturedObject.ListFracturedChunks.Count; i++) { EnableObjectColliders(fracturedObject.ListFracturedChunks[i].gameObject, true); } // Explode fracturedObject.Explode(collision.contacts[0].point, collision.relativeVelocity.magnitude); //죽은돌 삭제 GameObject delStone = GameObject.Find(fracturedObject.name); Destroy(delStone); } // Enable chunk colliders } } }
// Use this for initialization void Start() { mObject = GetComponent <FracturedObject>(); GlobalEventManager.RegisterHandler("Bottle.Explode", ExplodeChunks); }
private static bool ComputeHull(GameObject gameObject, FracturedObject.ECCAlgorithm eAlgorithm, int nMaxHulls, int nMaxHullVertices, int nLegacySteps, bool bVerbose, out int nTotalTrianglesOut) { MeshFilter theMesh = (MeshFilter)gameObject.GetComponent<MeshFilter>(); DllInit(true); SetLogFunctionPointer(Marshal.GetFunctionPointerForDelegate(new LogDelegate(Log))); SConvexDecompositionInfoInOut info = new SConvexDecompositionInfoInOut(); nTotalTrianglesOut = 0; if(theMesh) { if(theMesh.sharedMesh) { uint uLegacySteps = (uint)(Mathf.Max(1, nLegacySteps)); info.uMaxHullVertices = (uint)(Mathf.Max(3, nMaxHullVertices)); info.uMaxHulls = (uint)nMaxHulls; info.fPrecision = 0.2f; info.fBackFaceDistanceFactor = 0.2f; info.uLegacyDepth = eAlgorithm == FracturedObject.ECCAlgorithm.Legacy ? uLegacySteps : 0; info.uNormalizeInputMesh = 0; info.uUseFastVersion = eAlgorithm == FracturedObject.ECCAlgorithm.Fast ? (uint)1 : (uint)0; info.uTriangleCount = (uint)theMesh.sharedMesh.triangles.Length / 3; info.uVertexCount = (uint)theMesh.sharedMesh.vertexCount; Vector3[] av3Vertices = theMesh.sharedMesh.vertices; if(DoConvexDecomposition(ref info, av3Vertices, theMesh.sharedMesh.triangles)) { for(int nHull = 0; nHull < info.nHullsOut; nHull++) { SConvexDecompositionHullInfo hullInfo = new SConvexDecompositionHullInfo(); GetHullInfo((uint)nHull, ref hullInfo); if(hullInfo.nTriangleCount > 0) { Vector3[] hullVertices = new Vector3[hullInfo.nVertexCount]; int[] hullIndices = new int[hullInfo.nTriangleCount * 3]; float fHullVolume = -1.0f; FillHullMeshData((uint)nHull, ref fHullVolume, hullIndices, hullVertices); Mesh hullMesh = new Mesh(); hullMesh.vertices = hullVertices; hullMesh.triangles = hullIndices; hullMesh.uv = new Vector2[hullVertices.Length]; hullMesh.RecalculateNormals(); GameObject goNewHull = new GameObject("Hull " + (nHull + 1)); goNewHull.transform.position = gameObject.transform.position; goNewHull.transform.rotation = gameObject.transform.rotation; goNewHull.transform.localScale = gameObject.transform.localScale; goNewHull.transform.parent = gameObject.transform; goNewHull.layer = gameObject.layer; MeshCollider meshCollider = goNewHull.AddComponent<MeshCollider>() as MeshCollider; meshCollider.sharedMesh = null; meshCollider.sharedMesh = hullMesh; meshCollider.convex = true; nTotalTrianglesOut += hullInfo.nTriangleCount; } else { if(bVerbose) { Debug.LogWarning(gameObject.name + ": Error generating collider. ComputeHull() returned 0 triangles."); } } } if(info.nHullsOut < 0 && bVerbose) { Debug.LogWarning(gameObject.name + ": Error generating collider. ComputeHull() returned no hulls."); } } else { if(bVerbose) { Debug.LogWarning(gameObject.name + ": Error generating collider. ComputeHull() returned false."); } } } } DllClose(); return nTotalTrianglesOut > 0; }
public SupportPlane(FracturedObject fracturedObject) { GUIExpanded = true; GUIName = "New Support Plane"; GUIShowInScene = true; this.fracturedObject = fracturedObject; planeMesh = new Mesh(); Vector3[] av3RectVerts = new Vector3[4]; Vector3[] aRectNormals = new Vector3[4]; Vector2[] aRectMapping = new Vector2[4]; int[] aRectIndices = { 0, 1, 2, 0, 2, 3 }; av3RectVerts[0] = new Vector3(-1.0f, 0.0f, -1.0f); av3RectVerts[1] = new Vector3(-1.0f, 0.0f, +1.0f); av3RectVerts[2] = new Vector3(+1.0f, 0.0f, +1.0f); av3RectVerts[3] = new Vector3(+1.0f, 0.0f, -1.0f); aRectNormals[0] = new Vector3(0.0f, 1.0f, 0.0f); aRectNormals[1] = new Vector3(0.0f, 1.0f, 0.0f); aRectNormals[2] = new Vector3(0.0f, 1.0f, 0.0f); aRectNormals[3] = new Vector3(0.0f, 1.0f, 0.0f); bool bHasRenderer = false; float fHeight = 1.0f; if (fracturedObject.SourceObject) { if (fracturedObject.SourceObject.renderer) { bHasRenderer = true; } } if (bHasRenderer) { Bounds bounds = fracturedObject.SourceObject.renderer.bounds; fHeight = bounds.extents.y; for (int i = 0; i < av3RectVerts.Length; i++) { float fPlaneSize = 1.3f; float fMaxExtents = Mathf.Max(bounds.extents.z * fPlaneSize, bounds.extents.x * fPlaneSize); av3RectVerts[i] = Vector3.Scale(av3RectVerts[i], new Vector3(fMaxExtents, fMaxExtents, fMaxExtents)) + fracturedObject.transform.position; av3RectVerts[i] = fracturedObject.transform.InverseTransformPoint(av3RectVerts[i]); } v3PlanePosition = fracturedObject.transform.position - new Vector3(0.0f, fHeight - 0.05f, 0.0f); v3PlanePosition = fracturedObject.transform.InverseTransformPoint(v3PlanePosition); qPlaneRotation = Quaternion.identity; } else { for (int i = 0; i < av3RectVerts.Length; i++) { av3RectVerts[i] += fracturedObject.transform.position; av3RectVerts[i] = fracturedObject.transform.InverseTransformPoint(av3RectVerts[i]); } v3PlanePosition = new Vector3(0.0f, (-fHeight * 0.5f) + 0.05f, 0.0f); qPlaneRotation = Quaternion.identity; } v3PlaneScale = Vector3.one; planeMesh.vertices = av3RectVerts; planeMesh.normals = aRectNormals; planeMesh.uv = aRectMapping; planeMesh.triangles = aRectIndices; }
public static bool SplitMeshUsingPlane(GameObject gameObjectIn, FracturedObject fracturedComponent, SplitOptions splitOptions, Transform transformPlaneSplit, out List<GameObject> listGameObjectsPosOut, out List<GameObject> listGameObjectsNegOut, ProgressDelegate progress = null) { listGameObjectsPosOut = new List<GameObject>(); listGameObjectsNegOut = new List<GameObject>(); MeshFilter meshfIn = gameObjectIn.GetComponent<MeshFilter>(); if(meshfIn == null) { return false; } foreach(FracturedChunk chunk in fracturedComponent.ListFracturedChunks) { if(chunk != null) { UnityEngine.Object.DestroyImmediate(chunk.gameObject); } } fracturedComponent.ListFracturedChunks.Clear(); fracturedComponent.DecomposeRadius = (meshfIn.sharedMesh.bounds.max - meshfIn.sharedMesh.bounds.min).magnitude; Random.seed = fracturedComponent.RandomSeed; // Debug.Log("In: " + gameObjectIn.name + ": " + meshfIn.sharedMesh.subMeshCount + " submeshes, " + ": " + (meshfIn.sharedMesh.triangles.Length / 3) + " triangles, " + meshfIn.sharedMesh.vertexCount + " vertices, " + (meshfIn.sharedMesh.uv != null ? meshfIn.sharedMesh.uv.Length : 0) + " uv1, " + (meshfIn.sharedMesh.uv2 != null ? meshfIn.sharedMesh.uv2.Length : 0) + " uv2"); // Check if the input object already has been split, to get its split closing submesh FracturedChunk fracturedChunk = gameObjectIn.GetComponent<FracturedChunk>(); int nSplitCloseSubMesh = fracturedChunk != null ? fracturedChunk.SplitSubMeshIndex : -1; if(nSplitCloseSubMesh == -1 && gameObjectIn.GetComponent<Renderer>()) { // Check if its material is the same as the split material if(gameObjectIn.GetComponent<Renderer>().sharedMaterial == fracturedComponent.SplitMaterial) { nSplitCloseSubMesh = 0; } } List<MeshData> listMeshDatasPos; List<MeshData> listMeshDatasNeg; Material[] aMaterials = fracturedComponent.gameObject.GetComponent<Renderer>() ? fracturedComponent.gameObject.GetComponent<Renderer>().sharedMaterials : null; MeshData meshDataIn = new MeshData(meshfIn.transform, meshfIn.sharedMesh, aMaterials, meshfIn.transform.localToWorldMatrix, !splitOptions.bVerticesAreLocal, nSplitCloseSubMesh, true); if(SplitMeshUsingPlane(meshDataIn, fracturedComponent, splitOptions, transformPlaneSplit.up, transformPlaneSplit.right, transformPlaneSplit.position, out listMeshDatasPos, out listMeshDatasNeg, progress) == false) { return false; } // Set the mesh properties and add objects to list if(listMeshDatasPos.Count > 0) { for(int nMeshCount = 0; nMeshCount < listMeshDatasPos.Count; nMeshCount++) { GameObject goPos = CreateNewSplitGameObject(gameObjectIn, fracturedComponent, gameObjectIn.name + "0" + (listMeshDatasPos.Count > 1 ? ("(" + nMeshCount + ")") : ""), !splitOptions.bVerticesAreLocal, listMeshDatasPos[nMeshCount]); listGameObjectsPosOut.Add(goPos); } } if(listMeshDatasNeg.Count > 0) { for(int nMeshCount = 0; nMeshCount < listMeshDatasNeg.Count; nMeshCount++) { GameObject goNeg = CreateNewSplitGameObject(gameObjectIn, fracturedComponent, gameObjectIn.name + "1" + (listMeshDatasNeg.Count > 1 ? ("(" + nMeshCount + ")") : ""), !splitOptions.bVerticesAreLocal, listMeshDatasNeg[nMeshCount]); listGameObjectsNegOut.Add(goNeg); } } return true; }
static void TriangulateConstrainedDelaunay(List <List <Vector3> > listlistPointsConstrainedDelaunay, List <List <int> > listlistHashValuesConstrainedDelaunay, bool bForceVertexSoup, FracturedObject fracturedComponent, bool bConnectivityPostprocess, MeshFaceConnectivity faceConnectivityPos, MeshFaceConnectivity faceConnectivityNeg, MeshDataConnectivity meshConnectivityPos, MeshDataConnectivity meshConnectivityNeg, int nForceMeshConnectivityHash, int nSplitCloseSubMesh, Matrix4x4 mtxPlane, Matrix4x4 mtxToLocalPos, Matrix4x4 mtxToLocalNeg, Vector3 v3CenterPos, Vector3 v3CenterNeg, List <int>[] aListIndicesPosInOut, List <VertexData> listVertexDataPosInOut, List <int>[] aListIndicesNegInOut, List <VertexData> listVertexDataNegInOut) { // Pass to two dimensional plane: Matrix4x4 mtxPlaneInverse = mtxPlane.inverse; List <List <Poly2Tri.Point2D> > listlistCapPoints = new List <List <Poly2Tri.Point2D> >(); List <List <Poly2Tri.PolygonPoint> > listlistCapPolygonPoints = new List <List <Poly2Tri.PolygonPoint> >(); List <Poly2Tri.Polygon> listCapPolygons = new List <Poly2Tri.Polygon>(); for (int i = 0; i < listlistPointsConstrainedDelaunay.Count; i++) { List <Poly2Tri.Point2D> listCapPoints = new List <Poly2Tri.Point2D>(); List <Poly2Tri.PolygonPoint> listCapPolygonsPoints = new List <Poly2Tri.PolygonPoint>(); foreach (Vector3 v3Vertex in listlistPointsConstrainedDelaunay[i]) { Vector3 v3VertexInPlane = mtxPlaneInverse.MultiplyPoint3x4(v3Vertex); listCapPoints.Add(new Poly2Tri.Point2D(v3VertexInPlane.x, v3VertexInPlane.z)); listCapPolygonsPoints.Add(new Poly2Tri.PolygonPoint(v3VertexInPlane.x, v3VertexInPlane.z)); } listlistCapPoints.Add(listCapPoints); listlistCapPolygonPoints.Add(listCapPolygonsPoints); listCapPolygons.Add(new Poly2Tri.Polygon(listCapPolygonsPoints)); } // Remove close vertices float fPrecisionFix = Mathf.Max(Parameters.EPSILONCAPPRECISIONMIN, fracturedComponent.CapPrecisionFix); if (fPrecisionFix > 0.0f) { for (int nCap = 0; nCap < listlistCapPolygonPoints.Count; nCap++) { double lastX = listlistCapPolygonPoints[nCap][listlistCapPolygonPoints[nCap].Count - 1].X; double lastY = listlistCapPolygonPoints[nCap][listlistCapPolygonPoints[nCap].Count - 1].Y; bool bDeleteCap = false; for (int nVertex = 0; nVertex < listlistCapPolygonPoints[nCap].Count; nVertex++) { double vecX = listlistCapPolygonPoints[nCap][nVertex].X - lastX; double vecY = listlistCapPolygonPoints[nCap][nVertex].Y - lastY; if (System.Math.Sqrt(vecX * vecX + vecY * vecY) < fPrecisionFix) { listlistCapPolygonPoints[nCap].RemoveAt(nVertex); nVertex--; if (listlistCapPolygonPoints[nCap].Count < 3) { bDeleteCap = true; break; } } else { lastX = listlistCapPolygonPoints[nCap][nVertex].X; lastY = listlistCapPolygonPoints[nCap][nVertex].Y; } } if (bDeleteCap) { listlistCapPolygonPoints.RemoveAt(nCap); nCap--; } } } if (listlistCapPolygonPoints.Count == 0) { return; } // Search if one of the caps is contained in the other. If this happens we will mark the big one as the polygon and the rest as holes int nSuperPolygon = -1; Poly2Tri.Polygon polygonContainer = null; if (bForceVertexSoup == false) { for (int i = 0; i < listlistCapPolygonPoints.Count; i++) { for (int j = 0; j < listlistCapPolygonPoints.Count; j++) { if (i != j && listlistCapPoints[i].Count >= 3 && listlistCapPoints[j].Count >= 3) { if (Poly2Tri.PolygonUtil.PolygonContainsPolygon(listlistCapPoints[i], listCapPolygons[i].Bounds, listlistCapPoints[j], listCapPolygons[j].Bounds, true)) { nSuperPolygon = i; break; } else if (Poly2Tri.PolygonUtil.PolygonContainsPolygon(listlistCapPoints[j], listCapPolygons[j].Bounds, listlistCapPoints[i], listCapPolygons[i].Bounds, true)) { nSuperPolygon = j; break; } } } } // Add holes if this is a cap with holes if (nSuperPolygon != -1) { polygonContainer = listCapPolygons[nSuperPolygon]; for (int i = 0; i < listlistCapPolygonPoints.Count; i++) { if (i != nSuperPolygon && listCapPolygons[i].Count >= 3) { polygonContainer.AddHole(listCapPolygons[i]); } } } } // Triangulate bool bTriangulatedWithHoles = false; if (polygonContainer != null && bForceVertexSoup == false) { // Polygon with holes try { Poly2Tri.P2T.Triangulate(polygonContainer); if (polygonContainer.Triangles != null) { List <Vector3> listMeshVertices = new List <Vector3>(); List <int> listMeshIndices = new List <int>(); CreateIndexedMesh(polygonContainer.Triangles, listMeshVertices, listMeshIndices, mtxPlane, true); Triangulate(listMeshVertices, listMeshIndices, fracturedComponent, listlistPointsConstrainedDelaunay, listlistHashValuesConstrainedDelaunay, bConnectivityPostprocess, faceConnectivityPos, faceConnectivityNeg, meshConnectivityPos, meshConnectivityNeg, nForceMeshConnectivityHash, nSplitCloseSubMesh, mtxPlane, mtxToLocalPos, mtxToLocalNeg, v3CenterPos, v3CenterNeg, aListIndicesPosInOut, listVertexDataPosInOut, aListIndicesNegInOut, listVertexDataNegInOut); } bTriangulatedWithHoles = true; } catch (System.Exception e) { if (fracturedComponent.Verbose) { Debug.LogWarning("Exception (" + e.GetType() + ") using hole triangulation (holes = " + listlistCapPolygonPoints.Count + "). Trying to use constrained delaunay."); } bTriangulatedWithHoles = false; } } if (bTriangulatedWithHoles == false) { if (bForceVertexSoup) { // Vertex soup List <Poly2Tri.TriangulationPoint> listPoints = new List <Poly2Tri.TriangulationPoint>(); if (listlistCapPolygonPoints.Count > 0) { foreach (Poly2Tri.PolygonPoint polyPoint in listlistCapPolygonPoints[0]) { listPoints.Add(polyPoint); } try { if (listPoints.Count >= 3) { Poly2Tri.PointSet ps = new Poly2Tri.PointSet(listPoints); Poly2Tri.P2T.Triangulate(ps); if (ps.Triangles != null) { List <Vector3> listMeshVertices = new List <Vector3>(); List <int> listMeshIndices = new List <int>(); CreateIndexedMesh(ps.Triangles, listMeshVertices, listMeshIndices, mtxPlane, true); Triangulate(listMeshVertices, listMeshIndices, fracturedComponent, listlistPointsConstrainedDelaunay, listlistHashValuesConstrainedDelaunay, bConnectivityPostprocess, faceConnectivityPos, faceConnectivityNeg, meshConnectivityPos, meshConnectivityNeg, nForceMeshConnectivityHash, nSplitCloseSubMesh, mtxPlane, mtxToLocalPos, mtxToLocalNeg, v3CenterPos, v3CenterNeg, aListIndicesPosInOut, listVertexDataPosInOut, aListIndicesNegInOut, listVertexDataNegInOut); } } } catch (System.Exception e) { if (fracturedComponent.Verbose) { Debug.LogWarning("Exception (" + e.GetType() + ") using vertex soup triangulation."); } } } } else { // Use constrained delaunay triangulation int nPoly = 0; foreach (List <Poly2Tri.PolygonPoint> listPolyPoints in listlistCapPolygonPoints) { IList <Poly2Tri.DelaunayTriangle> listTriangles = null; Poly2Tri.Polygon polygon = null; try { if (listPolyPoints.Count >= 3) { polygon = new Poly2Tri.Polygon(listPolyPoints); Poly2Tri.P2T.Triangulate(polygon); listTriangles = polygon.Triangles; } } catch (System.Exception e) { if (fracturedComponent.Verbose) { Debug.LogWarning("Exception (" + e.GetType() + ") using polygon triangulation of cap polygon " + nPoly + ". Trying to use non constrained"); } listTriangles = null; } if (listTriangles == null) { List <Poly2Tri.TriangulationPoint> listPoints = new List <Poly2Tri.TriangulationPoint>(); foreach (Poly2Tri.PolygonPoint polyPoint in listPolyPoints) { listPoints.Add(polyPoint); } try { if (listPoints.Count >= 3) { Poly2Tri.PointSet ps = new Poly2Tri.PointSet(listPoints); Poly2Tri.P2T.Triangulate(ps); listTriangles = ps.Triangles; } } catch (System.Exception e) { if (fracturedComponent.Verbose) { Debug.LogWarning("Exception (" + e.GetType() + ") using non constrained triangulation of cap polygon " + nPoly + ". Skipping"); } } } if (listTriangles != null) { List <Vector3> listMeshVertices = new List <Vector3>(); List <int> listMeshIndices = new List <int>(); CreateIndexedMesh(listTriangles, listMeshVertices, listMeshIndices, mtxPlane, true); Triangulate(listMeshVertices, listMeshIndices, fracturedComponent, listlistPointsConstrainedDelaunay, listlistHashValuesConstrainedDelaunay, bConnectivityPostprocess, faceConnectivityPos, faceConnectivityNeg, meshConnectivityPos, meshConnectivityNeg, nForceMeshConnectivityHash, nSplitCloseSubMesh, mtxPlane, mtxToLocalPos, mtxToLocalNeg, v3CenterPos, v3CenterNeg, aListIndicesPosInOut, listVertexDataPosInOut, aListIndicesNegInOut, listVertexDataNegInOut); } nPoly++; } } } }
public static SpaceTreeNode BuildSpaceTree(MeshData meshDataIn, int nSubdivisionLevels, FracturedObject fracturedComponent, ProgressDelegate progress = null) { if(nSubdivisionLevels < 1) { return null; } SplitOptions splitOptions = new SplitOptions(); splitOptions.bForceNoIslandGeneration = true; splitOptions.bForceNoChunkConnectionInfo = true; splitOptions.bForceNoIslandConnectionInfo = true; splitOptions.bForceNoCap = false; splitOptions.bVerticesAreLocal = true; SpaceTreeNode nodeRoot = new SpaceTreeNode(); nodeRoot.listMeshDatasSpace = new List<MeshData>(); nodeRoot.listMeshDatasSpace.Add(meshDataIn); nodeRoot.nLevel = 0; nodeRoot.nSplitsX = 0; nodeRoot.nSplitsY = 0; nodeRoot.nSplitsZ = 0; nodeRoot.v3Min = meshDataIn.v3Min; nodeRoot.v3Max = meshDataIn.v3Max; Queue<SpaceTreeNode> queueNodes = new Queue<SpaceTreeNode>(); queueNodes.Enqueue(nodeRoot); int nTotalSubdivisions = 0; int nCurrentSubdivisions = 0; int nSplitsX = 0; int nSplitsY = 0; int nSplitsZ = 0; for(int i = 0; i < nSubdivisionLevels; i++) { nTotalSubdivisions += Mathf.RoundToInt(Mathf.Pow(2, i)); } while(queueNodes.Count > 0) { SpaceTreeNode nodeCurrent = queueNodes.Dequeue(); List<MeshData> listMeshDataPos; List<MeshData> listMeshDataNeg; if(nodeCurrent.nLevel < nSubdivisionLevels) { if(progress != null) { progress("Fracturing", string.Format("Pre computing space volume (split {0}/{1}, Depth {2})", nCurrentSubdivisions + 1, nTotalSubdivisions, nodeCurrent.nLevel + 1), Mathf.Clamp01((float)nCurrentSubdivisions / (float)nTotalSubdivisions)); } if(Fracturer.IsFracturingCancelled()) { return null; } Vector3 v3Normal = Vector3.up; Vector3 v3Right = Vector3.right; Vector3 v3Pos = (nodeCurrent.v3Min + nodeCurrent.v3Max) * 0.5f; float fSizeX = nodeCurrent.v3Max.x - nodeCurrent.v3Min.x; float fSizeY = nodeCurrent.v3Max.y - nodeCurrent.v3Min.y; float fSizeZ = nodeCurrent.v3Max.z - nodeCurrent.v3Min.z; Vector3 v3MinNeg = nodeCurrent.v3Min; Vector3 v3MaxNeg = nodeCurrent.v3Max; Vector3 v3MinPos = nodeCurrent.v3Min; Vector3 v3MaxPos = nodeCurrent.v3Max; if(fSizeX >= fSizeY && fSizeX >= fSizeZ) { v3Normal = Vector3.right; v3Right = Vector3.forward; v3MaxNeg.x = v3Pos.x; v3MinPos.x = v3Pos.x; nSplitsX++; } else if(fSizeY >= fSizeX && fSizeY >= fSizeZ) { v3Normal = Vector3.up; v3Right = Vector3.right; v3MaxNeg.y = v3Pos.y; v3MinPos.y = v3Pos.y; nSplitsY++; } else { v3Normal = Vector3.forward; v3Right = Vector3.right; v3MaxNeg.z = v3Pos.z; v3MinPos.z = v3Pos.z; nSplitsZ++; } foreach(MeshData meshData in nodeCurrent.listMeshDatasSpace) { if(SplitMeshUsingPlane(meshData, fracturedComponent, splitOptions, v3Normal, v3Right, v3Pos, out listMeshDataPos, out listMeshDataNeg, progress) == true) { nodeCurrent.nodeOneSide = new SpaceTreeNode(); nodeCurrent.nodeOneSide.listMeshDatasSpace = listMeshDataNeg; nodeCurrent.nodeOneSide.v3Min = v3MinNeg; nodeCurrent.nodeOneSide.v3Max = v3MaxNeg; nodeCurrent.nodeOneSide.nLevel = nodeCurrent.nLevel + 1; nodeCurrent.nodeOneSide.nSplitsX = nSplitsX; nodeCurrent.nodeOneSide.nSplitsY = nSplitsY; nodeCurrent.nodeOneSide.nSplitsZ = nSplitsZ; queueNodes.Enqueue(nodeCurrent.nodeOneSide); nodeCurrent.nodeOtherSide = new SpaceTreeNode(); nodeCurrent.nodeOtherSide.listMeshDatasSpace = listMeshDataPos; nodeCurrent.nodeOtherSide.v3Min = v3MinPos; nodeCurrent.nodeOtherSide.v3Max = v3MaxPos; nodeCurrent.nodeOtherSide.nLevel = nodeCurrent.nLevel + 1; nodeCurrent.nodeOtherSide.nSplitsX = nSplitsX; nodeCurrent.nodeOtherSide.nSplitsY = nSplitsY; nodeCurrent.nodeOtherSide.nSplitsZ = nSplitsZ; queueNodes.Enqueue(nodeCurrent.nodeOtherSide); } } nCurrentSubdivisions++; } } return nodeRoot; }
static void TriangulateConstrainedDelaunay( List<List<Vector3>> listlistPointsConstrainedDelaunay, List<List<int>> listlistHashValuesConstrainedDelaunay, bool bForceVertexSoup, FracturedObject fracturedComponent, bool bConnectivityPostprocess, MeshFaceConnectivity faceConnectivityPos, MeshFaceConnectivity faceConnectivityNeg, MeshDataConnectivity meshConnectivityPos, MeshDataConnectivity meshConnectivityNeg, int nForceMeshConnectivityHash, int nSplitCloseSubMesh, Matrix4x4 mtxPlane, Matrix4x4 mtxToLocalPos, Matrix4x4 mtxToLocalNeg, Vector3 v3CenterPos, Vector3 v3CenterNeg, List<int>[] aListIndicesPosInOut, List<VertexData> listVertexDataPosInOut, List<int>[] aListIndicesNegInOut, List<VertexData> listVertexDataNegInOut) { // Pass to two dimensional plane: Matrix4x4 mtxPlaneInverse = mtxPlane.inverse; List<List<Poly2Tri.Point2D>> listlistCapPoints = new List<List<Poly2Tri.Point2D>>(); List<List<Poly2Tri.PolygonPoint>> listlistCapPolygonPoints = new List<List<Poly2Tri.PolygonPoint>>(); List<Poly2Tri.Polygon> listCapPolygons = new List<Poly2Tri.Polygon>(); for(int i = 0; i < listlistPointsConstrainedDelaunay.Count; i++) { List<Poly2Tri.Point2D> listCapPoints = new List<Poly2Tri.Point2D>(); List<Poly2Tri.PolygonPoint> listCapPolygonsPoints = new List<Poly2Tri.PolygonPoint>(); foreach(Vector3 v3Vertex in listlistPointsConstrainedDelaunay[i]) { Vector3 v3VertexInPlane = mtxPlaneInverse.MultiplyPoint3x4(v3Vertex); listCapPoints.Add (new Poly2Tri.Point2D (v3VertexInPlane.x, v3VertexInPlane.z)); listCapPolygonsPoints.Add(new Poly2Tri.PolygonPoint(v3VertexInPlane.x, v3VertexInPlane.z)); } listlistCapPoints.Add(listCapPoints); listlistCapPolygonPoints.Add(listCapPolygonsPoints); listCapPolygons.Add(new Poly2Tri.Polygon(listCapPolygonsPoints)); } // Remove close vertices float fPrecisionFix = Mathf.Max(Parameters.EPSILONCAPPRECISIONMIN, fracturedComponent.CapPrecisionFix); if(fPrecisionFix > 0.0f) { for(int nCap = 0; nCap < listlistCapPolygonPoints.Count; nCap++) { double lastX = listlistCapPolygonPoints[nCap][listlistCapPolygonPoints[nCap].Count - 1].X; double lastY = listlistCapPolygonPoints[nCap][listlistCapPolygonPoints[nCap].Count - 1].Y; bool bDeleteCap = false; for(int nVertex = 0; nVertex < listlistCapPolygonPoints[nCap].Count; nVertex++) { double vecX = listlistCapPolygonPoints[nCap][nVertex].X - lastX; double vecY = listlistCapPolygonPoints[nCap][nVertex].Y - lastY; if(System.Math.Sqrt(vecX * vecX + vecY * vecY) < fPrecisionFix) { listlistCapPolygonPoints[nCap].RemoveAt(nVertex); nVertex--; if(listlistCapPolygonPoints[nCap].Count < 3) { bDeleteCap = true; break; } } else { lastX = listlistCapPolygonPoints[nCap][nVertex].X; lastY = listlistCapPolygonPoints[nCap][nVertex].Y; } } if(bDeleteCap) { listlistCapPolygonPoints.RemoveAt(nCap); nCap--; } } } if(listlistCapPolygonPoints.Count == 0) { return; } // Search if one of the caps is contained in the other. If this happens we will mark the big one as the polygon and the rest as holes int nSuperPolygon = -1; Poly2Tri.Polygon polygonContainer = null; if(bForceVertexSoup == false) { for(int i = 0; i < listlistCapPolygonPoints.Count; i++) { for(int j = 0; j < listlistCapPolygonPoints.Count; j++) { if(i != j && listlistCapPoints[i].Count >= 3 && listlistCapPoints[j].Count >= 3) { if(Poly2Tri.PolygonUtil.PolygonContainsPolygon(listlistCapPoints[i], listCapPolygons[i].Bounds, listlistCapPoints[j], listCapPolygons[j].Bounds, true)) { nSuperPolygon = i; break; } else if(Poly2Tri.PolygonUtil.PolygonContainsPolygon(listlistCapPoints[j], listCapPolygons[j].Bounds, listlistCapPoints[i], listCapPolygons[i].Bounds, true)) { nSuperPolygon = j; break; } } } } // Add holes if this is a cap with holes if(nSuperPolygon != -1) { polygonContainer = listCapPolygons[nSuperPolygon]; for(int i = 0; i < listlistCapPolygonPoints.Count; i++) { if(i != nSuperPolygon && listCapPolygons[i].Count >= 3) { polygonContainer.AddHole(listCapPolygons[i]); } } } } // Triangulate bool bTriangulatedWithHoles = false; if(polygonContainer != null && bForceVertexSoup == false) { // Polygon with holes try { Poly2Tri.P2T.Triangulate(polygonContainer); if(polygonContainer.Triangles != null) { List<Vector3> listMeshVertices = new List<Vector3>(); List<int> listMeshIndices = new List<int>(); CreateIndexedMesh(polygonContainer.Triangles, listMeshVertices, listMeshIndices, mtxPlane, true); Triangulate( listMeshVertices, listMeshIndices, fracturedComponent, listlistPointsConstrainedDelaunay, listlistHashValuesConstrainedDelaunay, bConnectivityPostprocess, faceConnectivityPos, faceConnectivityNeg, meshConnectivityPos, meshConnectivityNeg, nForceMeshConnectivityHash, nSplitCloseSubMesh, mtxPlane, mtxToLocalPos, mtxToLocalNeg, v3CenterPos, v3CenterNeg, aListIndicesPosInOut, listVertexDataPosInOut, aListIndicesNegInOut, listVertexDataNegInOut); } bTriangulatedWithHoles = true; } catch(System.Exception e) { if(fracturedComponent.Verbose) Debug.LogWarning("Exception (" + e.GetType() + ") using hole triangulation (holes = " + listlistCapPolygonPoints.Count + "). Trying to use constrained delaunay."); bTriangulatedWithHoles = false; } } if(bTriangulatedWithHoles == false) { if(bForceVertexSoup) { // Vertex soup List<Poly2Tri.TriangulationPoint> listPoints = new List<Poly2Tri.TriangulationPoint>(); if(listlistCapPolygonPoints.Count > 0) { foreach(Poly2Tri.PolygonPoint polyPoint in listlistCapPolygonPoints[0]) { listPoints.Add(polyPoint); } try { if(listPoints.Count >= 3) { Poly2Tri.PointSet ps = new Poly2Tri.PointSet(listPoints); Poly2Tri.P2T.Triangulate(ps); if(ps.Triangles != null) { List<Vector3> listMeshVertices = new List<Vector3>(); List<int> listMeshIndices = new List<int>(); CreateIndexedMesh(ps.Triangles, listMeshVertices, listMeshIndices, mtxPlane, true); Triangulate( listMeshVertices, listMeshIndices, fracturedComponent, listlistPointsConstrainedDelaunay, listlistHashValuesConstrainedDelaunay, bConnectivityPostprocess, faceConnectivityPos, faceConnectivityNeg, meshConnectivityPos, meshConnectivityNeg, nForceMeshConnectivityHash, nSplitCloseSubMesh, mtxPlane, mtxToLocalPos, mtxToLocalNeg, v3CenterPos, v3CenterNeg, aListIndicesPosInOut, listVertexDataPosInOut, aListIndicesNegInOut, listVertexDataNegInOut); } } } catch(System.Exception e) { if(fracturedComponent.Verbose) Debug.LogWarning("Exception (" + e.GetType() + ") using vertex soup triangulation."); } } } else { // Use constrained delaunay triangulation int nPoly = 0; foreach(List<Poly2Tri.PolygonPoint> listPolyPoints in listlistCapPolygonPoints) { IList<Poly2Tri.DelaunayTriangle> listTriangles = null; Poly2Tri.Polygon polygon = null; try { if(listPolyPoints.Count >= 3) { polygon = new Poly2Tri.Polygon(listPolyPoints); Poly2Tri.P2T.Triangulate(polygon); listTriangles = polygon.Triangles; } } catch(System.Exception e) { if(fracturedComponent.Verbose) Debug.LogWarning("Exception (" + e.GetType() + ") using polygon triangulation of cap polygon " + nPoly + ". Trying to use non constrained"); listTriangles = null; } if(listTriangles == null) { List<Poly2Tri.TriangulationPoint> listPoints = new List<Poly2Tri.TriangulationPoint>(); foreach(Poly2Tri.PolygonPoint polyPoint in listPolyPoints) { listPoints.Add(polyPoint); } try { if(listPoints.Count >= 3) { Poly2Tri.PointSet ps = new Poly2Tri.PointSet(listPoints); Poly2Tri.P2T.Triangulate(ps); listTriangles = ps.Triangles; } } catch(System.Exception e) { if(fracturedComponent.Verbose) Debug.LogWarning("Exception (" + e.GetType() + ") using non constrained triangulation of cap polygon " + nPoly + ". Skipping"); } } if(listTriangles != null) { List<Vector3> listMeshVertices = new List<Vector3>(); List<int> listMeshIndices = new List<int>(); CreateIndexedMesh(listTriangles, listMeshVertices, listMeshIndices, mtxPlane, true); Triangulate( listMeshVertices, listMeshIndices, fracturedComponent, listlistPointsConstrainedDelaunay, listlistHashValuesConstrainedDelaunay, bConnectivityPostprocess, faceConnectivityPos, faceConnectivityNeg, meshConnectivityPos, meshConnectivityNeg, nForceMeshConnectivityHash, nSplitCloseSubMesh, mtxPlane, mtxToLocalPos, mtxToLocalNeg, v3CenterPos, v3CenterNeg, aListIndicesPosInOut, listVertexDataPosInOut, aListIndicesNegInOut, listVertexDataNegInOut); } nPoly++; } } } }
static bool ResolveCap(Dictionary<EdgeKeyByHash, CapEdge> dicCapEdges, List<List<Vector3>> listlistResolvedCapVertices, List<List<int>> listlistResolvedCapHashValues, FracturedObject fracturedComponent) { if(dicCapEdges.Count < 3) { if(fracturedComponent.Verbose) Debug.LogWarning("Cap has < 3 segments"); return false; } listlistResolvedCapVertices.Clear(); listlistResolvedCapHashValues.Clear(); List<CapEdge> listResolvedCap = new List<CapEdge>(); List<CapEdge> listUnresolvedCap = new List<CapEdge>(dicCapEdges.Values); List<Vector3> newListVertices = new List<Vector3>(); List<int> newListHashValues = new List<int>(); int nTotalSegments = listUnresolvedCap.Count; listResolvedCap.Add(listUnresolvedCap[0]); newListVertices.Add(listUnresolvedCap[0].v1); newListVertices.Add(listUnresolvedCap[0].v2); newListHashValues.Add(listUnresolvedCap[0].nHash1); newListHashValues.Add(listUnresolvedCap[0].nHash2); listUnresolvedCap.RemoveAt(0); // Try to match all segments while(listUnresolvedCap.Count > 0) { // Search for a connected segment in the unresolved segment pool CapEdge CapEdgeLast = listResolvedCap[listResolvedCap.Count - 1]; CapEdge CapEdgeFirst = listResolvedCap[0]; bool bFound = false; for(int nSegmentUnresolved = 0; nSegmentUnresolved < listUnresolvedCap.Count; nSegmentUnresolved++) { CapEdge CapEdgeUnresolved = listUnresolvedCap[nSegmentUnresolved]; int nSharesVertexEnd = CapEdgeLast.SharesVertex1Of (CapEdgeUnresolved); int nSharesVertexStart = CapEdgeFirst.SharesVertex2Of(CapEdgeUnresolved); if(nSharesVertexEnd == 2) { newListVertices.Add(CapEdgeUnresolved.v2); newListHashValues.Add(CapEdgeUnresolved.nHash2); listResolvedCap.Add(CapEdgeUnresolved); listUnresolvedCap.RemoveAt(nSegmentUnresolved); bFound = true; break; } else if(nSharesVertexStart == 1) { newListVertices.Insert(0, CapEdgeUnresolved.v1); newListHashValues.Insert(0, CapEdgeUnresolved.nHash1); listResolvedCap.Insert(0, CapEdgeUnresolved); listUnresolvedCap.RemoveAt(nSegmentUnresolved); bFound = true; break; } } bool bFinish = bFound == false; if(listResolvedCap.Count >= 3) { if(listResolvedCap[listResolvedCap.Count - 1].SharesVertex1Of(listResolvedCap[0]) == 2) { bFinish = true; } } if(listUnresolvedCap.Count == 0) { bFinish = true; } if(bFinish) { // Finished, new cap vertex group int nTotalAdd = newListVertices.Count; if(Vector3.Distance(newListVertices[0], newListVertices[newListVertices.Count - 1]) < Parameters.EPSILONDISTANCEVERTEX) { nTotalAdd = newListVertices.Count - 1; } if(nTotalAdd > 2) { List<Vector3> listAddVertices = new List<Vector3>(); List<int> listAddHash = new List<int>(); for(int i = 0; i < nTotalAdd; i++) { listAddVertices.Add(newListVertices[i]); listAddHash.Add(newListHashValues[i]); } listlistResolvedCapVertices.Add(listAddVertices); listlistResolvedCapHashValues.Add(listAddHash); } else { if(fracturedComponent.Verbose) Debug.LogWarning("Cap group has less than 3 vertices (" + newListVertices.Count + ")"); } if(listUnresolvedCap.Count > 0) { listResolvedCap.Clear(); listResolvedCap.Add(listUnresolvedCap[0]); newListVertices.Clear(); newListHashValues.Clear(); newListVertices.Add(listUnresolvedCap[0].v1); newListVertices.Add(listUnresolvedCap[0].v2); newListHashValues.Add(listUnresolvedCap[0].nHash1); newListHashValues.Add(listUnresolvedCap[0].nHash2); listUnresolvedCap.RemoveAt(0); } } } if(listUnresolvedCap.Count > 0) { if(fracturedComponent.Verbose) Debug.LogWarning(string.Format("Cap has {0}/{1} unresolved segments left", listUnresolvedCap.Count, nTotalSegments)); } return true; }
static void Triangulate( List<Vector3> listVertices, List<int> listIndices, FracturedObject fracturedComponent, List<List<Vector3>> listlistPointsConstrainedDelaunay, List<List<int>> listlistHashValuesConstrainedDelaunay, bool bConnectivityPostprocess, MeshFaceConnectivity faceConnectivityPos, MeshFaceConnectivity faceConnectivityNeg, MeshDataConnectivity meshConnectivityPos, MeshDataConnectivity meshConnectivityNeg, int nForceMeshConnectivityHash, int nSplitCloseSubMesh, Matrix4x4 mtxPlane, Matrix4x4 mtxToLocalPos, Matrix4x4 mtxToLocalNeg, Vector3 v3CenterPos, Vector3 v3CenterNeg, List<int>[] aListIndicesPosInOut, List<VertexData> listVertexDataPosInOut, List<int>[] aListIndicesNegInOut, List<VertexData> listVertexDataNegInOut) { int nPositiveSideIndexStart = listVertexDataPosInOut.Count; int nNegativeSideIndexStart = listVertexDataNegInOut.Count; if(listVertexDataPosInOut.Count < 1 || listVertexDataNegInOut.Count < 1) { return; } // Add vertex data VertexData[] aVtxDataCapPos = new VertexData[listVertices.Count]; VertexData[] aVtxDataCapNeg = new VertexData[listVertices.Count]; Vector3 v3PlaneNormal = mtxPlane.MultiplyVector(Vector3.up); float fReversedCapNormals = fracturedComponent.InvertCapNormals ? -1.0f : 1.0f; Vector3 v3CapNormalLocalPos = mtxToLocalPos.MultiplyVector(-v3PlaneNormal * fReversedCapNormals); Vector3 v3CapNormalLocalNeg = mtxToLocalNeg.MultiplyVector( v3PlaneNormal * fReversedCapNormals); Vector3 v3TangentPos = Vector3.right; v3TangentPos = mtxPlane.MultiplyVector(v3TangentPos); v3TangentPos = mtxToLocalPos.MultiplyVector(v3TangentPos); Vector3 v3TangentNeg = Vector3.right; v3TangentNeg = mtxPlane.MultiplyVector(v3TangentNeg); v3TangentNeg = mtxToLocalNeg.MultiplyVector(v3TangentNeg); Matrix4x4 mtxPlaneInverse = mtxPlane.inverse; Color32 colWhite = new Color32(255, 255, 255, 255); Vector3 v2Mapping = Vector2.zero; for(int i = 0; i < listVertices.Count; i++) { Vector3 v3Local = mtxPlaneInverse.MultiplyPoint3x4(listVertices[i]); v2Mapping.x = v3Local.x * fracturedComponent.SplitMappingTileU; v2Mapping.y = v3Local.z * fracturedComponent.SplitMappingTileV; int nVertexHash = ComputeVertexHash(listVertices[i], listlistPointsConstrainedDelaunay, listlistHashValuesConstrainedDelaunay); aVtxDataCapPos[i] = new VertexData(nVertexHash, listVertices[i], v3CapNormalLocalPos, v3TangentPos, colWhite, v2Mapping, v2Mapping, true, true, listVertexDataPosInOut[0].bHasColor32, listVertexDataPosInOut[0].bHasMapping1, listVertexDataPosInOut[0].bHasMapping2); aVtxDataCapNeg[i] = new VertexData(nVertexHash, listVertices[i], v3CapNormalLocalNeg, v3TangentNeg, colWhite, v2Mapping, v2Mapping, true, true, listVertexDataNegInOut[0].bHasColor32, listVertexDataNegInOut[0].bHasMapping1, listVertexDataNegInOut[0].bHasMapping2); } listVertexDataPosInOut.AddRange(aVtxDataCapPos); listVertexDataNegInOut.AddRange(aVtxDataCapNeg); // Add indices for(int i = 0; i < listIndices.Count / 3; i++) { int nTriangleA = listIndices[i * 3 + 0]; int nTriangleB = listIndices[i * 3 + 1]; int nTriangleC = listIndices[i * 3 + 2]; int nHashPosA = listVertexDataPosInOut[nPositiveSideIndexStart + nTriangleA].nVertexHash; int nHashPosB = listVertexDataPosInOut[nPositiveSideIndexStart + nTriangleB].nVertexHash; int nHashPosC = listVertexDataPosInOut[nPositiveSideIndexStart + nTriangleC].nVertexHash; int nHashNegA = listVertexDataNegInOut[nNegativeSideIndexStart + nTriangleA].nVertexHash; int nHashNegB = listVertexDataNegInOut[nNegativeSideIndexStart + nTriangleB].nVertexHash; int nHashNegC = listVertexDataNegInOut[nNegativeSideIndexStart + nTriangleC].nVertexHash; if(nHashPosA != -1 && nHashPosB != -1 && nHashPosC != -1 && nHashNegA != -1 && nHashNegB != -1 && nHashNegC != -1) { int nMeshConnectivityHash = nForceMeshConnectivityHash == -1 ? MeshDataConnectivity.GetNewHash() : nForceMeshConnectivityHash; // New hash value to identify the 2 shared faces if(fracturedComponent.GenerateChunkConnectionInfo) { meshConnectivityPos.NotifyNewCapFace(nMeshConnectivityHash, nSplitCloseSubMesh, aListIndicesPosInOut[nSplitCloseSubMesh].Count / 3); } aListIndicesPosInOut[nSplitCloseSubMesh].Add(nPositiveSideIndexStart + nTriangleA); aListIndicesPosInOut[nSplitCloseSubMesh].Add(nPositiveSideIndexStart + nTriangleB); aListIndicesPosInOut[nSplitCloseSubMesh].Add(nPositiveSideIndexStart + nTriangleC); if(bConnectivityPostprocess) { faceConnectivityPos.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleA], listVertices[nTriangleB], nHashPosA, nHashPosB, nPositiveSideIndexStart + nTriangleA, nPositiveSideIndexStart + nTriangleB); faceConnectivityPos.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleB], listVertices[nTriangleC], nHashPosB, nHashPosC, nPositiveSideIndexStart + nTriangleB, nPositiveSideIndexStart + nTriangleC); faceConnectivityPos.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleC], listVertices[nTriangleA], nHashPosC, nHashPosA, nPositiveSideIndexStart + nTriangleC, nPositiveSideIndexStart + nTriangleA); } if(fracturedComponent.GenerateChunkConnectionInfo) { meshConnectivityNeg.NotifyNewCapFace(nMeshConnectivityHash, nSplitCloseSubMesh, aListIndicesNegInOut[nSplitCloseSubMesh].Count / 3); } aListIndicesNegInOut[nSplitCloseSubMesh].Add(nNegativeSideIndexStart + nTriangleA); aListIndicesNegInOut[nSplitCloseSubMesh].Add(nNegativeSideIndexStart + nTriangleC); aListIndicesNegInOut[nSplitCloseSubMesh].Add(nNegativeSideIndexStart + nTriangleB); if(bConnectivityPostprocess) { faceConnectivityNeg.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleA], listVertices[nTriangleC], nHashNegA, nHashNegC, nNegativeSideIndexStart + nTriangleA, nNegativeSideIndexStart + nTriangleC); faceConnectivityNeg.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleC], listVertices[nTriangleB], nHashNegC, nHashNegB, nNegativeSideIndexStart + nTriangleC, nNegativeSideIndexStart + nTriangleB); faceConnectivityNeg.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleB], listVertices[nTriangleA], nHashNegB, nHashNegA, nNegativeSideIndexStart + nTriangleB, nNegativeSideIndexStart + nTriangleA); } } } }
public SupportPlane(FracturedObject fracturedObject) { GUIExpanded = true; GUIName = "New Support Plane"; GUIShowInScene = true; this.fracturedObject = fracturedObject; planeMesh = new Mesh(); Vector3[] av3RectVerts = new Vector3[4]; Vector3[] aRectNormals = new Vector3[4]; Vector2[] aRectMapping = new Vector2[4]; int[] aRectIndices = { 0, 1, 2, 0, 2, 3 }; av3RectVerts[0] = new Vector3(-1.0f, 0.0f, -1.0f); av3RectVerts[1] = new Vector3(-1.0f, 0.0f, +1.0f); av3RectVerts[2] = new Vector3(+1.0f, 0.0f, +1.0f); av3RectVerts[3] = new Vector3(+1.0f, 0.0f, -1.0f); aRectNormals[0] = new Vector3(0.0f, 1.0f, 0.0f); aRectNormals[1] = new Vector3(0.0f, 1.0f, 0.0f); aRectNormals[2] = new Vector3(0.0f, 1.0f, 0.0f); aRectNormals[3] = new Vector3(0.0f, 1.0f, 0.0f); bool bHasRenderer = false; float fHeight = 1.0f; if(fracturedObject.SourceObject) { if(fracturedObject.SourceObject.GetComponent<Renderer>()) { bHasRenderer = true; } } if(bHasRenderer) { Bounds bounds = fracturedObject.SourceObject.GetComponent<Renderer>().bounds; fHeight = bounds.extents.y; for(int i = 0; i < av3RectVerts.Length; i++) { float fPlaneSize = 1.3f; float fMaxExtents = Mathf.Max(bounds.extents.z * fPlaneSize, bounds.extents.x * fPlaneSize); av3RectVerts[i] = Vector3.Scale(av3RectVerts[i], new Vector3(fMaxExtents, fMaxExtents, fMaxExtents)) + fracturedObject.transform.position; av3RectVerts[i] = fracturedObject.transform.InverseTransformPoint(av3RectVerts[i]); } v3PlanePosition = fracturedObject.transform.position - new Vector3(0.0f, fHeight - 0.05f, 0.0f); v3PlanePosition = fracturedObject.transform.InverseTransformPoint(v3PlanePosition); qPlaneRotation = Quaternion.identity; } else { for(int i = 0; i < av3RectVerts.Length; i++) { av3RectVerts[i] += fracturedObject.transform.position; av3RectVerts[i] = fracturedObject.transform.InverseTransformPoint(av3RectVerts[i]); } v3PlanePosition = new Vector3(0.0f, (-fHeight * 0.5f) + 0.05f, 0.0f); qPlaneRotation = Quaternion.identity; } v3PlaneScale = Vector3.one; planeMesh.vertices = av3RectVerts; planeMesh.normals = aRectNormals; planeMesh.uv = aRectMapping; planeMesh.triangles = aRectIndices; }
private static bool SplitMeshUsingPlane(MeshData meshDataIn, FracturedObject fracturedComponent, SplitOptions splitOptions, Vector3 v3PlaneNormal, Vector3 v3PlaneRight, Vector3 v3PlanePoint, out List<MeshData> listMeshDatasPosOut, out List<MeshData> listMeshDatasNegOut, ProgressDelegate progress = null) { Plane planeSplit = new Plane(v3PlaneNormal, v3PlanePoint); listMeshDatasPosOut = new List<MeshData>(); listMeshDatasNegOut = new List<MeshData>(); // Check if the input object already has been split, to get its split closing submesh bool bNeedsNewSplitSubMesh = meshDataIn.nSplitCloseSubMesh == -1; int nSplitCloseSubMesh = meshDataIn.nSplitCloseSubMesh; // Here we are going to store our output vertex/index data int nCurrentVertexHash = meshDataIn.nCurrentVertexHash; // We will use this to identify vertices with same coordinates but different vertex data. They will share the same vertex hash List<VertexData> listVertexDataPos = new List<VertexData>(); List<VertexData> listVertexDataNeg = new List<VertexData>(); List<int>[] alistIndicesPos = new List<int>[meshDataIn.nSubMeshCount + (meshDataIn.nSplitCloseSubMesh == -1 ? 1 : 0)]; List<int>[] alistIndicesNeg = new List<int>[meshDataIn.nSubMeshCount + (meshDataIn.nSplitCloseSubMesh == -1 ? 1 : 0)]; MeshFaceConnectivity faceConnectivityPos = new MeshFaceConnectivity(); MeshFaceConnectivity faceConnectivityNeg = new MeshFaceConnectivity(); MeshDataConnectivity meshConnectivityPos = new MeshDataConnectivity(); MeshDataConnectivity meshConnectivityNeg = new MeshDataConnectivity(); listVertexDataPos.Capacity = meshDataIn.aVertexData.Length / 2; listVertexDataNeg.Capacity = meshDataIn.aVertexData.Length / 2; if(bNeedsNewSplitSubMesh) { // Make room for the split closing submesh nSplitCloseSubMesh = meshDataIn.nSubMeshCount; alistIndicesPos[nSplitCloseSubMesh] = new List<int>(); alistIndicesNeg[nSplitCloseSubMesh] = new List<int>(); } // Our vertices that form the clipped cap Dictionary<EdgeKeyByHash, int> dicClipVerticesHash = new Dictionary<EdgeKeyByHash, int> (new EdgeKeyByHash.EqualityComparer()); Dictionary<EdgeKeyByHash, CapEdge> dicCapEdges = new Dictionary<EdgeKeyByHash, CapEdge>(new EdgeKeyByHash.EqualityComparer()); // A hash table with our clipped edges, to reuse clipped vertices Dictionary<EdgeKeyByIndex, ClippedEdge> dicClippedEdgesPos = new Dictionary<EdgeKeyByIndex, ClippedEdge>(new EdgeKeyByIndex.EqualityComparer()); Dictionary<EdgeKeyByIndex, ClippedEdge> dicClippedEdgesNeg = new Dictionary<EdgeKeyByIndex, ClippedEdge>(new EdgeKeyByIndex.EqualityComparer()); int nClippedCacheHits = 0; int nClippedCacheMisses = 0; // A hash table with the remapped indices, to reuse non-clipped vertices Dictionary<int, int> dicRemappedIndicesPos = new Dictionary<int, int>(); Dictionary<int, int> dicRemappedIndicesNeg = new Dictionary<int, int>(); for(int nSubMesh = 0; nSubMesh < meshDataIn.nSubMeshCount; nSubMesh++) { // Index list alistIndicesPos[nSubMesh] = new List<int>(); alistIndicesNeg[nSubMesh] = new List<int>(); List<int> listIndicesPos = alistIndicesPos[nSubMesh]; List<int> listIndicesNeg = alistIndicesNeg[nSubMesh]; alistIndicesPos[nSubMesh].Capacity = meshDataIn.aaIndices[nSubMesh].Length / 2; alistIndicesNeg[nSubMesh].Capacity = meshDataIn.aaIndices[nSubMesh].Length / 2; // A reference to the output arrays/lists (it will be switching between positive/negative side along the algorithm) List<VertexData> plistVertexData = listVertexDataPos; List<int> plistObjectIndices = listIndicesPos; MeshFaceConnectivity pFaceConnectivity = faceConnectivityPos; MeshDataConnectivity pMeshConnectivity = meshConnectivityPos; Dictionary<EdgeKeyByIndex, ClippedEdge> pdicClippedEdges = dicClippedEdgesPos; Dictionary<int, int> pdicRemappedIndices = dicRemappedIndicesPos; // Iterate through all submesh faces: for(int i = 0; i < meshDataIn.aaIndices[nSubMesh].Length / 3; i++) { plistVertexData = listVertexDataPos; plistObjectIndices = listIndicesPos; pFaceConnectivity = faceConnectivityPos; pMeshConnectivity = meshConnectivityPos; pdicClippedEdges = dicClippedEdgesPos; pdicRemappedIndices = dicRemappedIndicesPos; int nIndex1 = meshDataIn.aaIndices[nSubMesh][i * 3 + 0]; int nIndex2 = meshDataIn.aaIndices[nSubMesh][i * 3 + 1]; int nIndex3 = meshDataIn.aaIndices[nSubMesh][i * 3 + 2]; int nHashV1 = meshDataIn.aVertexData[nIndex1].nVertexHash; int nHashV2 = meshDataIn.aVertexData[nIndex2].nVertexHash; int nHashV3 = meshDataIn.aVertexData[nIndex3].nVertexHash; Vector3 v1 = meshDataIn.aVertexData[nIndex1].v3Vertex; Vector3 v2 = meshDataIn.aVertexData[nIndex2].v3Vertex; Vector3 v3 = meshDataIn.aVertexData[nIndex3].v3Vertex; // Classify vertices depending on the side of the plane they lay on, then clip if necessary. float fSide1 = v1.x * planeSplit.normal.x + v1.y * planeSplit.normal.y + v1.z * planeSplit.normal.z + planeSplit.distance; float fSide2 = v2.x * planeSplit.normal.x + v2.y * planeSplit.normal.y + v2.z * planeSplit.normal.z + planeSplit.distance; float fSide3 = v3.x * planeSplit.normal.x + v3.y * planeSplit.normal.y + v3.z * planeSplit.normal.z + planeSplit.distance; bool bForceSameSide = false; int nAlmostInPlane = 0; bool bAlmostInPlane1 = false; bool bAlmostInPlane2 = false; bool bAlmostInPlane3 = false; float fFurthest = 0.0f; if(Mathf.Abs(fSide1) < UltimateFracturing.Parameters.EPSILONDISTANCEPLANE) { bAlmostInPlane1 = true; nAlmostInPlane++; } if(Mathf.Abs(fSide2) < UltimateFracturing.Parameters.EPSILONDISTANCEPLANE) { bAlmostInPlane2 = true; nAlmostInPlane++; } if(Mathf.Abs(fSide3) < UltimateFracturing.Parameters.EPSILONDISTANCEPLANE) { bAlmostInPlane3 = true; nAlmostInPlane++; } if(Mathf.Abs(fSide1) > Mathf.Abs(fFurthest)) fFurthest = fSide1; if(Mathf.Abs(fSide2) > Mathf.Abs(fFurthest)) fFurthest = fSide2; if(Mathf.Abs(fSide3) > Mathf.Abs(fFurthest)) fFurthest = fSide3; if(nAlmostInPlane == 1) { // Look if the other two vertices are on the same side. If so, we'll skip the clipping too. if(bAlmostInPlane1 && (fSide2 * fSide3 > 0.0f)) bForceSameSide = true; if(bAlmostInPlane2 && (fSide1 * fSide3 > 0.0f)) bForceSameSide = true; if(bAlmostInPlane3 && (fSide1 * fSide2 > 0.0f)) bForceSameSide = true; } else if(nAlmostInPlane > 1) { bForceSameSide = true; if(nAlmostInPlane == 3) { // Coplanar continue; } } if((fSide1 * fSide2 > 0.0f && fSide2 * fSide3 > 0.0f) || bForceSameSide) { // All on the same side, no clipping needed if(fFurthest < 0.0f) { plistVertexData = listVertexDataNeg; plistObjectIndices = listIndicesNeg; pFaceConnectivity = faceConnectivityNeg; pMeshConnectivity = meshConnectivityNeg; pdicClippedEdges = dicClippedEdgesNeg; pdicRemappedIndices = dicRemappedIndicesNeg; } int nNewIndex1 = -1; int nNewIndex2 = -1; int nNewIndex3 = -1; // Find vertices in remapped indices list and add vertex data if not present if(pdicRemappedIndices.ContainsKey(nIndex1)) { nNewIndex1 = pdicRemappedIndices[nIndex1]; } if(nNewIndex1 == -1) { nNewIndex1 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex1].Copy()); pdicRemappedIndices[nIndex1] = nNewIndex1; } if(pdicRemappedIndices.ContainsKey(nIndex2)) { nNewIndex2 = pdicRemappedIndices[nIndex2]; } if(nNewIndex2 == -1) { nNewIndex2 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex2].Copy()); pdicRemappedIndices[nIndex2] = nNewIndex2; } if(pdicRemappedIndices.ContainsKey(nIndex3)) { nNewIndex3 = pdicRemappedIndices[nIndex3]; } if(nNewIndex3 == -1) { nNewIndex3 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex3].Copy()); pdicRemappedIndices[nIndex3] = nNewIndex3; } // Add triangle indices if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false) { pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3); } plistObjectIndices.Add(nNewIndex1); plistObjectIndices.Add(nNewIndex2); plistObjectIndices.Add(nNewIndex3); if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false) { pFaceConnectivity.AddEdge(nSubMesh, v1, v2, nHashV1, nHashV2, nNewIndex1, nNewIndex2); pFaceConnectivity.AddEdge(nSubMesh, v2, v3, nHashV2, nHashV3, nNewIndex2, nNewIndex3); pFaceConnectivity.AddEdge(nSubMesh, v3, v1, nHashV3, nHashV1, nNewIndex3, nNewIndex1); } // Add cap edges only if an edge is lying on the plane if(nAlmostInPlane == 2) { if(fFurthest > 0.0f) { if(bAlmostInPlane1 && bAlmostInPlane2 && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV1, nHashV2, v1, v2); if(bAlmostInPlane2 && bAlmostInPlane3 && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV2, nHashV3, v2, v3); if(bAlmostInPlane3 && bAlmostInPlane1 && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV3, nHashV1, v3, v1); } else { if(bAlmostInPlane1 && bAlmostInPlane2 && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV2, nHashV1, v2, v1); if(bAlmostInPlane2 && bAlmostInPlane3 && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV3, nHashV2, v3, v2); if(bAlmostInPlane3 && bAlmostInPlane1 && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV1, nHashV3, v1, v3); } } } else if(nAlmostInPlane == 1) { // Special treatment clipping for one vertex laying on the clipping plane and the other 2 on different sides int nNewIndex1 = -1; int nNewIndex2 = -1; int nNewIndex3 = -1; int nNewIndex4 = -1; int nHashV4 = -1; bool bEdge = false; EdgeKeyByIndex clippedEdgeKey; if(bAlmostInPlane1) { // v1 almost on the clipping plane if(fSide2 < 0.0f) { plistVertexData = listVertexDataNeg; plistObjectIndices = listIndicesNeg; pFaceConnectivity = faceConnectivityNeg; pMeshConnectivity = meshConnectivityNeg; pdicClippedEdges = dicClippedEdgesNeg; pdicRemappedIndices = dicRemappedIndicesNeg; } clippedEdgeKey = new EdgeKeyByIndex(nIndex2, nIndex3); if(pdicClippedEdges.ContainsKey(clippedEdgeKey)) { nClippedCacheHits++; bEdge = true; nNewIndex2 = pdicClippedEdges[clippedEdgeKey].GetFirstIndex(nIndex2); nNewIndex4 = pdicClippedEdges[clippedEdgeKey].nClippedIndex; } else { nClippedCacheMisses++; if(pdicRemappedIndices.ContainsKey(nIndex2)) nNewIndex2 = pdicRemappedIndices[nIndex2]; } // Clip if not present in clipped edge list EdgeKeyByHash clippedEdgeKeyHash = new EdgeKeyByHash(nHashV2, nHashV3); if(dicClipVerticesHash.ContainsKey(clippedEdgeKeyHash)) { nHashV4 = dicClipVerticesHash[clippedEdgeKeyHash]; } else { nHashV4 = nCurrentVertexHash++; dicClipVerticesHash.Add(clippedEdgeKeyHash, nHashV4); } VertexData vd4 = new VertexData(nHashV4); if(bEdge == false) { if(VertexData.ClipAgainstPlane(meshDataIn.aVertexData, nIndex2, nIndex3, v2, v3, planeSplit, ref vd4) == false) { return false; } } // Add geometry of one side // Add vertex data for all data not present in remapped list if(nNewIndex1 == -1) { if(pdicRemappedIndices.ContainsKey(nIndex1)) { nNewIndex1 = pdicRemappedIndices[nIndex1]; } } if(nNewIndex1 == -1) { nNewIndex1 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex1].Copy()); pdicRemappedIndices[nIndex1] = nNewIndex1; } if(nNewIndex2 == -1) { nNewIndex2 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex2].Copy()); pdicRemappedIndices[nIndex2] = nNewIndex2; } if(nNewIndex4 == -1) { nNewIndex4 = plistVertexData.Count; plistVertexData.Add(vd4); } if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false) { pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3); } plistObjectIndices.Add(nNewIndex1); plistObjectIndices.Add(nNewIndex2); plistObjectIndices.Add(nNewIndex4); Vector3 v4 = plistVertexData[nNewIndex4].v3Vertex; if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false) { pFaceConnectivity.AddEdge(nSubMesh, v1, v2, nHashV1, nHashV2, nNewIndex1, nNewIndex2); pFaceConnectivity.AddEdge(nSubMesh, v2, v4, nHashV2, nHashV4, nNewIndex2, nNewIndex4); pFaceConnectivity.AddEdge(nSubMesh, v4, v1, nHashV4, nHashV1, nNewIndex4, nNewIndex1); } // Update cap edges and cache if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV4, nHashV1, plistVertexData[nNewIndex4].v3Vertex, plistVertexData[nNewIndex1].v3Vertex); if(bEdge == false) pdicClippedEdges.Add(clippedEdgeKey, new ClippedEdge(nIndex2, nIndex3, nNewIndex2, nNewIndex3, nNewIndex4)); // Add geometry of other side if(fSide3 < 0.0f) { plistVertexData = listVertexDataNeg; plistObjectIndices = listIndicesNeg; pFaceConnectivity = faceConnectivityNeg; pMeshConnectivity = meshConnectivityNeg; pdicClippedEdges = dicClippedEdgesNeg; pdicRemappedIndices = dicRemappedIndicesNeg; } else { plistVertexData = listVertexDataPos; plistObjectIndices = listIndicesPos; pFaceConnectivity = faceConnectivityPos; pMeshConnectivity = meshConnectivityPos; pdicClippedEdges = dicClippedEdgesPos; pdicRemappedIndices = dicRemappedIndicesPos; } nNewIndex1 = -1; nNewIndex2 = -1; nNewIndex3 = -1; nNewIndex4 = -1; bEdge = false; // Find edges in cache if(pdicClippedEdges.ContainsKey(clippedEdgeKey)) { nClippedCacheHits++; bEdge = true; nNewIndex3 = pdicClippedEdges[clippedEdgeKey].GetSecondIndex(nIndex3); nNewIndex4 = pdicClippedEdges[clippedEdgeKey].nClippedIndex; } else { nClippedCacheMisses++; if(pdicRemappedIndices.ContainsKey(nIndex3)) nNewIndex3 = pdicRemappedIndices[nIndex3]; } // Add vertex data for all data not present in remapped list if(nNewIndex1 == -1) { if(pdicRemappedIndices.ContainsKey(nIndex1)) { nNewIndex1 = pdicRemappedIndices[nIndex1]; } } if(nNewIndex1 == -1) { nNewIndex1 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex1].Copy()); pdicRemappedIndices[nIndex1] = nNewIndex1; } if(nNewIndex3 == -1) { nNewIndex3 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex3].Copy()); pdicRemappedIndices[nIndex3] = nNewIndex3; } if(nNewIndex4 == -1) { nNewIndex4 = plistVertexData.Count; plistVertexData.Add(vd4); } if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false) { pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3); } plistObjectIndices.Add(nNewIndex1); plistObjectIndices.Add(nNewIndex4); plistObjectIndices.Add(nNewIndex3); if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false) { pFaceConnectivity.AddEdge(nSubMesh, v1, v4, nHashV1, nHashV4, nNewIndex1, nNewIndex4); pFaceConnectivity.AddEdge(nSubMesh, v4, v3, nHashV4, nHashV3, nNewIndex4, nNewIndex3); pFaceConnectivity.AddEdge(nSubMesh, v3, v1, nHashV3, nHashV1, nNewIndex3, nNewIndex1); } // Update cap edges and cache if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV1, nHashV4, plistVertexData[nNewIndex1].v3Vertex, plistVertexData[nNewIndex4].v3Vertex); if(bEdge == false) pdicClippedEdges.Add(clippedEdgeKey, new ClippedEdge(nIndex2, nIndex3, nNewIndex2, nNewIndex3, nNewIndex4)); } else if(bAlmostInPlane2) { // v2 almost on the clipping plane if(fSide3 < 0.0f) { plistVertexData = listVertexDataNeg; plistObjectIndices = listIndicesNeg; pFaceConnectivity = faceConnectivityNeg; pMeshConnectivity = meshConnectivityNeg; pdicClippedEdges = dicClippedEdgesNeg; pdicRemappedIndices = dicRemappedIndicesNeg; } clippedEdgeKey = new EdgeKeyByIndex(nIndex3, nIndex1); if(pdicClippedEdges.ContainsKey(clippedEdgeKey)) { nClippedCacheHits++; bEdge = true; nNewIndex3 = pdicClippedEdges[clippedEdgeKey].GetFirstIndex(nIndex3); nNewIndex4 = pdicClippedEdges[clippedEdgeKey].nClippedIndex; } else { nClippedCacheMisses++; if(pdicRemappedIndices.ContainsKey(nIndex3)) nNewIndex3 = pdicRemappedIndices[nIndex3]; } // Clip if not present in clipped edge list EdgeKeyByHash clippedEdgeKeyHash = new EdgeKeyByHash(nHashV3, nHashV1); if(dicClipVerticesHash.ContainsKey(clippedEdgeKeyHash)) { nHashV4 = dicClipVerticesHash[clippedEdgeKeyHash]; } else { nHashV4 = nCurrentVertexHash++; dicClipVerticesHash.Add(clippedEdgeKeyHash, nHashV4); } VertexData vd4 = new VertexData(nHashV4); if(bEdge == false) { if(VertexData.ClipAgainstPlane(meshDataIn.aVertexData, nIndex3, nIndex1, v3, v1, planeSplit, ref vd4) == false) { return false; } } // Add geometry of one side // Add vertex data for all data not present in remapped list if(nNewIndex2 == -1) { if(pdicRemappedIndices.ContainsKey(nIndex2)) { nNewIndex2 = pdicRemappedIndices[nIndex2]; } } if(nNewIndex2 == -1) { nNewIndex2 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex2].Copy()); pdicRemappedIndices[nIndex2] = nNewIndex2; } if(nNewIndex3 == -1) { nNewIndex3 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex3].Copy()); pdicRemappedIndices[nIndex3] = nNewIndex3; } if(nNewIndex4 == -1) { nNewIndex4 = plistVertexData.Count; plistVertexData.Add(vd4); } if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false) { pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3); } plistObjectIndices.Add(nNewIndex2); plistObjectIndices.Add(nNewIndex3); plistObjectIndices.Add(nNewIndex4); Vector3 v4 = plistVertexData[nNewIndex4].v3Vertex; if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false) { pFaceConnectivity.AddEdge(nSubMesh, v2, v3, nHashV2, nHashV3, nNewIndex2, nNewIndex3); pFaceConnectivity.AddEdge(nSubMesh, v3, v4, nHashV3, nHashV4, nNewIndex3, nNewIndex4); pFaceConnectivity.AddEdge(nSubMesh, v4, v2, nHashV4, nHashV2, nNewIndex4, nNewIndex2); } // Update cap edges and cache if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV4, nHashV2, plistVertexData[nNewIndex4].v3Vertex, plistVertexData[nNewIndex2].v3Vertex); if(bEdge == false) pdicClippedEdges.Add(clippedEdgeKey, new ClippedEdge(nIndex3, nIndex1, nNewIndex3, nNewIndex1, nNewIndex4)); // Add geometry of other side if(fSide1 < 0.0f) { plistVertexData = listVertexDataNeg; plistObjectIndices = listIndicesNeg; pFaceConnectivity = faceConnectivityNeg; pMeshConnectivity = meshConnectivityNeg; pdicClippedEdges = dicClippedEdgesNeg; pdicRemappedIndices = dicRemappedIndicesNeg; } else { plistVertexData = listVertexDataPos; plistObjectIndices = listIndicesPos; pFaceConnectivity = faceConnectivityPos; pMeshConnectivity = meshConnectivityPos; pdicClippedEdges = dicClippedEdgesPos; pdicRemappedIndices = dicRemappedIndicesPos; } nNewIndex1 = -1; nNewIndex2 = -1; nNewIndex4 = -1; bEdge = false; // Find edges in cache if(pdicClippedEdges.ContainsKey(clippedEdgeKey)) { nClippedCacheHits++; bEdge = true; nNewIndex1 = pdicClippedEdges[clippedEdgeKey].GetSecondIndex(nIndex1); nNewIndex4 = pdicClippedEdges[clippedEdgeKey].nClippedIndex; } else { nClippedCacheMisses++; if(pdicRemappedIndices.ContainsKey(nIndex1)) nNewIndex1 = pdicRemappedIndices[nIndex1]; } // Add vertex data for all data not present in remapped list if(nNewIndex1 == -1) { nNewIndex1 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex1].Copy()); pdicRemappedIndices[nIndex1] = nNewIndex1; } if(nNewIndex2 == -1) { if(pdicRemappedIndices.ContainsKey(nIndex2)) { nNewIndex2 = pdicRemappedIndices[nIndex2]; } } if(nNewIndex2 == -1) { nNewIndex2 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex2].Copy()); pdicRemappedIndices[nIndex2] = nNewIndex2; } if(nNewIndex4 == -1) { nNewIndex4 = plistVertexData.Count; plistVertexData.Add(vd4); } if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false) { pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3); } plistObjectIndices.Add(nNewIndex2); plistObjectIndices.Add(nNewIndex4); plistObjectIndices.Add(nNewIndex1); if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false) { pFaceConnectivity.AddEdge(nSubMesh, v2, v4, nHashV2, nHashV4, nNewIndex2, nNewIndex4); pFaceConnectivity.AddEdge(nSubMesh, v4, v1, nHashV4, nHashV1, nNewIndex4, nNewIndex1); pFaceConnectivity.AddEdge(nSubMesh, v1, v2, nHashV1, nHashV2, nNewIndex1, nNewIndex2); } // Update cap edges and cache if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV2, nHashV4, plistVertexData[nNewIndex2].v3Vertex, plistVertexData[nNewIndex4].v3Vertex); if(bEdge == false) pdicClippedEdges.Add(clippedEdgeKey, new ClippedEdge(nIndex3, nIndex1, nNewIndex3, nNewIndex1, nNewIndex4)); } else if(bAlmostInPlane3) { // v3 almost on the clipping plane if(fSide1 < 0.0f) { plistVertexData = listVertexDataNeg; plistObjectIndices = listIndicesNeg; pFaceConnectivity = faceConnectivityNeg; pMeshConnectivity = meshConnectivityNeg; pdicClippedEdges = dicClippedEdgesNeg; pdicRemappedIndices = dicRemappedIndicesNeg; } clippedEdgeKey = new EdgeKeyByIndex(nIndex1, nIndex2); if(pdicClippedEdges.ContainsKey(clippedEdgeKey)) { nClippedCacheHits++; bEdge = true; nNewIndex1 = pdicClippedEdges[clippedEdgeKey].GetFirstIndex(nIndex1); nNewIndex4 = pdicClippedEdges[clippedEdgeKey].nClippedIndex; } else { nClippedCacheMisses++; if(pdicRemappedIndices.ContainsKey(nIndex1)) nNewIndex1 = pdicRemappedIndices[nIndex1]; } // Clip if not present in clipped edge list EdgeKeyByHash clippedEdgeKeyHash = new EdgeKeyByHash(nHashV1, nHashV2); if(dicClipVerticesHash.ContainsKey(clippedEdgeKeyHash)) { nHashV4 = dicClipVerticesHash[clippedEdgeKeyHash]; } else { nHashV4 = nCurrentVertexHash++; dicClipVerticesHash.Add(clippedEdgeKeyHash, nHashV4); } VertexData vd4 = new VertexData(nHashV4); if(bEdge == false) { if(VertexData.ClipAgainstPlane(meshDataIn.aVertexData, nIndex1, nIndex2, v1, v2, planeSplit, ref vd4) == false) { return false; } } // Add geometry of one side // Add vertex data for all data not present in remapped list if(nNewIndex1 == -1) { nNewIndex1 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex1].Copy()); pdicRemappedIndices[nIndex1] = nNewIndex1; } if(nNewIndex3 == -1) { if(pdicRemappedIndices.ContainsKey(nIndex3)) { nNewIndex3 = pdicRemappedIndices[nIndex3]; } } if(nNewIndex3 == -1) { nNewIndex3 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex3].Copy()); pdicRemappedIndices[nIndex3] = nNewIndex3; } if(nNewIndex4 == -1) { nNewIndex4 = plistVertexData.Count; plistVertexData.Add(vd4); } if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false) { pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3); } plistObjectIndices.Add(nNewIndex1); plistObjectIndices.Add(nNewIndex4); plistObjectIndices.Add(nNewIndex3); Vector3 v4 = plistVertexData[nNewIndex4].v3Vertex; if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false) { pFaceConnectivity.AddEdge(nSubMesh, v1, v4, nHashV1, nHashV4, nNewIndex1, nNewIndex4); pFaceConnectivity.AddEdge(nSubMesh, v4, v3, nHashV4, nHashV3, nNewIndex4, nNewIndex3); pFaceConnectivity.AddEdge(nSubMesh, v3, v1, nHashV3, nHashV1, nNewIndex3, nNewIndex1); } // Update cap edges and cache if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV4, nHashV3, plistVertexData[nNewIndex4].v3Vertex, plistVertexData[nNewIndex3].v3Vertex); if(bEdge == false) pdicClippedEdges.Add(clippedEdgeKey, new ClippedEdge(nIndex1, nIndex2, nNewIndex1, nNewIndex2, nNewIndex4)); // Add geometry of other side if(fSide2 < 0.0f) { plistVertexData = listVertexDataNeg; plistObjectIndices = listIndicesNeg; pFaceConnectivity = faceConnectivityNeg; pMeshConnectivity = meshConnectivityNeg; pdicClippedEdges = dicClippedEdgesNeg; pdicRemappedIndices = dicRemappedIndicesNeg; } else { plistVertexData = listVertexDataPos; plistObjectIndices = listIndicesPos; pFaceConnectivity = faceConnectivityPos; pMeshConnectivity = meshConnectivityPos; pdicClippedEdges = dicClippedEdgesPos; pdicRemappedIndices = dicRemappedIndicesPos; } nNewIndex2 = -1; nNewIndex3 = -1; nNewIndex4 = -1; bEdge = false; // Find edges in cache if(pdicClippedEdges.ContainsKey(clippedEdgeKey)) { nClippedCacheHits++; bEdge = true; nNewIndex2 = pdicClippedEdges[clippedEdgeKey].GetSecondIndex(nIndex2); nNewIndex4 = pdicClippedEdges[clippedEdgeKey].nClippedIndex; } else { nClippedCacheMisses++; if(pdicRemappedIndices.ContainsKey(nIndex2)) nNewIndex2 = pdicRemappedIndices[nIndex2]; } // Add vertex data for all data not present in remapped list if(nNewIndex2 == -1) { nNewIndex2 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex2].Copy()); pdicRemappedIndices[nIndex2] = nNewIndex2; } if(nNewIndex3 == -1) { if(pdicRemappedIndices.ContainsKey(nIndex3)) { nNewIndex3 = pdicRemappedIndices[nIndex3]; } } if(nNewIndex3 == -1) { nNewIndex3 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex3].Copy()); pdicRemappedIndices[nIndex3] = nNewIndex3; } if(nNewIndex4 == -1) { nNewIndex4 = plistVertexData.Count; plistVertexData.Add(vd4); } if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false) { pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3); } plistObjectIndices.Add(nNewIndex2); plistObjectIndices.Add(nNewIndex3); plistObjectIndices.Add(nNewIndex4); if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false) { pFaceConnectivity.AddEdge(nSubMesh, v2, v3, nHashV2, nHashV3, nNewIndex2, nNewIndex3); pFaceConnectivity.AddEdge(nSubMesh, v3, v4, nHashV3, nHashV4, nNewIndex3, nNewIndex4); pFaceConnectivity.AddEdge(nSubMesh, v4, v2, nHashV4, nHashV2, nNewIndex4, nNewIndex2); } // Update cap edges and cache if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV3, nHashV4, plistVertexData[nNewIndex3].v3Vertex, plistVertexData[nNewIndex4].v3Vertex); if(bEdge == false) pdicClippedEdges.Add(clippedEdgeKey, new ClippedEdge(nIndex1, nIndex2, nNewIndex1, nNewIndex2, nNewIndex4)); } } else { if(fSide1 * fSide2 < 0.0f) { // v1 and v2 on different sides if(fSide2 * fSide3 < 0.0f) { // ... and v3 on same side as v1 if(fSide1 < 0.0f) { plistVertexData = listVertexDataNeg; plistObjectIndices = listIndicesNeg; pFaceConnectivity = faceConnectivityNeg; pMeshConnectivity = meshConnectivityNeg; pdicClippedEdges = dicClippedEdgesNeg; pdicRemappedIndices = dicRemappedIndicesNeg; } int nNewIndex1 = -1; int nNewIndex2 = -1; int nNewIndex3 = -1; int nNewIndex4 = -1; int nNewIndex5 = -1; int nHashV4 = -1; int nHashV5 = -1; bool bEdgeKey1 = false; bool bEdgeKey2 = false; EdgeKeyByIndex edgeKey1 = new EdgeKeyByIndex(nIndex1, nIndex2); EdgeKeyByIndex edgeKey2 = new EdgeKeyByIndex(nIndex2, nIndex3); // Find edges in cache if(pdicClippedEdges.ContainsKey(edgeKey1)) { nClippedCacheHits++; bEdgeKey1 = true; nNewIndex1 = pdicClippedEdges[edgeKey1].GetFirstIndex(nIndex1); nNewIndex4 = pdicClippedEdges[edgeKey1].nClippedIndex; } else { nClippedCacheMisses++; if(pdicRemappedIndices.ContainsKey(nIndex1)) nNewIndex1 = pdicRemappedIndices[nIndex1]; } if(pdicClippedEdges.ContainsKey(edgeKey2)) { nClippedCacheHits++; bEdgeKey2 = true; nNewIndex3 = pdicClippedEdges[edgeKey2].GetSecondIndex(nIndex3); nNewIndex5 = pdicClippedEdges[edgeKey2].nClippedIndex; } else { nClippedCacheMisses++; if(pdicRemappedIndices.ContainsKey(nIndex3)) nNewIndex3 = pdicRemappedIndices[nIndex3]; } // Clip if not present in clipped edge list EdgeKeyByHash clippedEdgeKeyHash = new EdgeKeyByHash(nHashV1, nHashV2); if(dicClipVerticesHash.ContainsKey(clippedEdgeKeyHash)) { nHashV4 = dicClipVerticesHash[clippedEdgeKeyHash]; } else { nHashV4 = nCurrentVertexHash++; dicClipVerticesHash.Add(clippedEdgeKeyHash, nHashV4); } clippedEdgeKeyHash = new EdgeKeyByHash(nHashV2, nHashV3); if(dicClipVerticesHash.ContainsKey(clippedEdgeKeyHash)) { nHashV5 = dicClipVerticesHash[clippedEdgeKeyHash]; } else { nHashV5 = nCurrentVertexHash++; dicClipVerticesHash.Add(clippedEdgeKeyHash, nHashV5); } VertexData vd4 = new VertexData(nHashV4), vd5 = new VertexData(nHashV5); if(bEdgeKey1 == false) { if(VertexData.ClipAgainstPlane(meshDataIn.aVertexData, nIndex1, nIndex2, v1, v2, planeSplit, ref vd4) == false) { return false; } } if(bEdgeKey2 == false) { if(VertexData.ClipAgainstPlane(meshDataIn.aVertexData, nIndex2, nIndex3, v2, v3, planeSplit, ref vd5) == false) { return false; } } // Add geometry of one side // Add vertex data for all data not present in remapped list if(nNewIndex1 == -1) { nNewIndex1 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex1].Copy()); pdicRemappedIndices[nIndex1] = nNewIndex1; } if(nNewIndex3 == -1) { nNewIndex3 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex3].Copy()); pdicRemappedIndices[nIndex3] = nNewIndex3; } if(nNewIndex4 == -1) { nNewIndex4 = plistVertexData.Count; plistVertexData.Add(vd4); } if(nNewIndex5 == -1) { nNewIndex5 = plistVertexData.Count; plistVertexData.Add(vd5); } if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false) { pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3); } plistObjectIndices.Add(nNewIndex1); plistObjectIndices.Add(nNewIndex4); plistObjectIndices.Add(nNewIndex5); if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false) { pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3); } plistObjectIndices.Add(nNewIndex1); plistObjectIndices.Add(nNewIndex5); plistObjectIndices.Add(nNewIndex3); Vector3 v4 = plistVertexData[nNewIndex4].v3Vertex; Vector3 v5 = plistVertexData[nNewIndex5].v3Vertex; if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false) { pFaceConnectivity.AddEdge(nSubMesh, v1, v4, nHashV1, nHashV4, nNewIndex1, nNewIndex4); pFaceConnectivity.AddEdge(nSubMesh, v4, v5, nHashV4, nHashV5, nNewIndex4, nNewIndex5); pFaceConnectivity.AddEdge(nSubMesh, v5, v1, nHashV5, nHashV1, nNewIndex5, nNewIndex1); pFaceConnectivity.AddEdge(nSubMesh, v1, v5, nHashV1, nHashV5, nNewIndex1, nNewIndex5); pFaceConnectivity.AddEdge(nSubMesh, v5, v3, nHashV5, nHashV3, nNewIndex5, nNewIndex3); pFaceConnectivity.AddEdge(nSubMesh, v3, v1, nHashV3, nHashV1, nNewIndex3, nNewIndex1); } // Update cap edges and cache if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV4, nHashV5, plistVertexData[nNewIndex4].v3Vertex, plistVertexData[nNewIndex5].v3Vertex); if(pdicClippedEdges.ContainsKey(edgeKey1) == false) pdicClippedEdges.Add(edgeKey1, new ClippedEdge(nIndex1, nIndex2, nNewIndex1, nNewIndex2, nNewIndex4)); if(pdicClippedEdges.ContainsKey(edgeKey2) == false) pdicClippedEdges.Add(edgeKey2, new ClippedEdge(nIndex2, nIndex3, nNewIndex2, nNewIndex3, nNewIndex5)); // Add geometry of other side if(fSide2 < 0.0f) { plistVertexData = listVertexDataNeg; plistObjectIndices = listIndicesNeg; pFaceConnectivity = faceConnectivityNeg; pMeshConnectivity = meshConnectivityNeg; pdicClippedEdges = dicClippedEdgesNeg; pdicRemappedIndices = dicRemappedIndicesNeg; } else { plistVertexData = listVertexDataPos; plistObjectIndices = listIndicesPos; pFaceConnectivity = faceConnectivityPos; pMeshConnectivity = meshConnectivityPos; pdicClippedEdges = dicClippedEdgesPos; pdicRemappedIndices = dicRemappedIndicesPos; } nNewIndex1 = -1; nNewIndex2 = -1; nNewIndex3 = -1; nNewIndex4 = -1; nNewIndex5 = -1; bEdgeKey1 = false; bEdgeKey2 = false; // Find edges in cache if(pdicClippedEdges.ContainsKey(edgeKey1)) { nClippedCacheHits++; bEdgeKey1 = true; nNewIndex2 = pdicClippedEdges[edgeKey1].GetSecondIndex(nIndex2); nNewIndex4 = pdicClippedEdges[edgeKey1].nClippedIndex; } else { nClippedCacheMisses++; if(pdicRemappedIndices.ContainsKey(nIndex2)) nNewIndex2 = pdicRemappedIndices[nIndex2]; } if(pdicClippedEdges.ContainsKey(edgeKey2)) { nClippedCacheHits++; bEdgeKey2 = true; nNewIndex2 = pdicClippedEdges[edgeKey2].GetFirstIndex(nIndex2); nNewIndex5 = pdicClippedEdges[edgeKey2].nClippedIndex; } else { nClippedCacheMisses++; if(pdicRemappedIndices.ContainsKey(nIndex2)) nNewIndex2 = pdicRemappedIndices[nIndex2]; } // Add vertex data for all data not present in remapped list if(nNewIndex2 == -1) { nNewIndex2 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex2].Copy()); pdicRemappedIndices[nIndex2] = nNewIndex2; } if(nNewIndex4 == -1) { nNewIndex4 = plistVertexData.Count; plistVertexData.Add(vd4); } if(nNewIndex5 == -1) { nNewIndex5 = plistVertexData.Count; plistVertexData.Add(vd5); } if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false) { pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3); } plistObjectIndices.Add(nNewIndex4); plistObjectIndices.Add(nNewIndex2); plistObjectIndices.Add(nNewIndex5); if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false) { pFaceConnectivity.AddEdge(nSubMesh, v4, v2, nHashV4, nHashV2, nNewIndex4, nNewIndex2); pFaceConnectivity.AddEdge(nSubMesh, v2, v5, nHashV2, nHashV5, nNewIndex2, nNewIndex5); pFaceConnectivity.AddEdge(nSubMesh, v5, v4, nHashV5, nHashV4, nNewIndex5, nNewIndex4); } // Update cap edges and cache if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV5, nHashV4, plistVertexData[nNewIndex5].v3Vertex, plistVertexData[nNewIndex4].v3Vertex); if(pdicClippedEdges.ContainsKey(edgeKey1) == false) pdicClippedEdges.Add(edgeKey1, new ClippedEdge(nIndex1, nIndex2, nNewIndex1, nNewIndex2, nNewIndex4)); if(pdicClippedEdges.ContainsKey(edgeKey2) == false) pdicClippedEdges.Add(edgeKey2, new ClippedEdge(nIndex2, nIndex3, nNewIndex2, nNewIndex3, nNewIndex5)); } else { // ... and v3 on same side as v2 if(fSide1 < 0.0f) { plistVertexData = listVertexDataNeg; plistObjectIndices = listIndicesNeg; pFaceConnectivity = faceConnectivityNeg; pMeshConnectivity = meshConnectivityNeg; pdicClippedEdges = dicClippedEdgesNeg; pdicRemappedIndices = dicRemappedIndicesNeg; } int nNewIndex1 = -1; int nNewIndex2 = -1; int nNewIndex3 = -1; int nNewIndex4 = -1; int nNewIndex5 = -1; int nHashV4 = -1; int nHashV5 = -1; bool bEdgeKey1 = false; bool bEdgeKey3 = false; EdgeKeyByIndex edgeKey1 = new EdgeKeyByIndex(nIndex1, nIndex2); EdgeKeyByIndex edgeKey3 = new EdgeKeyByIndex(nIndex1, nIndex3); // Find edges in cache if(pdicClippedEdges.ContainsKey(edgeKey1)) { nClippedCacheHits++; bEdgeKey1 = true; nNewIndex1 = pdicClippedEdges[edgeKey1].GetFirstIndex(nIndex1); nNewIndex4 = pdicClippedEdges[edgeKey1].nClippedIndex; } else { nClippedCacheMisses++; if(pdicRemappedIndices.ContainsKey(nIndex1)) nNewIndex1 = pdicRemappedIndices[nIndex1]; } if(pdicClippedEdges.ContainsKey(edgeKey3)) { nClippedCacheHits++; bEdgeKey3 = true; nNewIndex1 = pdicClippedEdges[edgeKey3].GetFirstIndex(nIndex1); nNewIndex5 = pdicClippedEdges[edgeKey3].nClippedIndex; } else { nClippedCacheMisses++; if(pdicRemappedIndices.ContainsKey(nIndex1)) nNewIndex1 = pdicRemappedIndices[nIndex1]; } // Clip if not present in clipped edge list EdgeKeyByHash clippedEdgeKeyHash = new EdgeKeyByHash(nHashV1, nHashV2); if(dicClipVerticesHash.ContainsKey(clippedEdgeKeyHash)) { nHashV4 = dicClipVerticesHash[clippedEdgeKeyHash]; } else { nHashV4 = nCurrentVertexHash++; dicClipVerticesHash.Add(clippedEdgeKeyHash, nHashV4); } clippedEdgeKeyHash = new EdgeKeyByHash(nHashV1, nHashV3); if(dicClipVerticesHash.ContainsKey(clippedEdgeKeyHash)) { nHashV5 = dicClipVerticesHash[clippedEdgeKeyHash]; } else { nHashV5 = nCurrentVertexHash++; dicClipVerticesHash.Add(clippedEdgeKeyHash, nHashV5); } VertexData vd4 = new VertexData(nHashV4), vd5 = new VertexData(nHashV5); if(bEdgeKey1 == false) { if(VertexData.ClipAgainstPlane(meshDataIn.aVertexData, nIndex1, nIndex2, v1, v2, planeSplit, ref vd4) == false) { return false; } } if(bEdgeKey3 == false) { if(VertexData.ClipAgainstPlane(meshDataIn.aVertexData, nIndex1, nIndex3, v1, v3, planeSplit, ref vd5) == false) { return false; } } // Add geometry of one side // Add vertex data for all data not present in remapped list if(nNewIndex1 == -1) { nNewIndex1 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex1].Copy()); pdicRemappedIndices[nIndex1] = nNewIndex1; } if(nNewIndex4 == -1) { nNewIndex4 = plistVertexData.Count; plistVertexData.Add(vd4); } if(nNewIndex5 == -1) { nNewIndex5 = plistVertexData.Count; plistVertexData.Add(vd5); } if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false) { pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3); } plistObjectIndices.Add(nNewIndex1); plistObjectIndices.Add(nNewIndex4); plistObjectIndices.Add(nNewIndex5); Vector3 v4 = plistVertexData[nNewIndex4].v3Vertex; Vector3 v5 = plistVertexData[nNewIndex5].v3Vertex; if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false) { pFaceConnectivity.AddEdge(nSubMesh, v1, v4, nHashV1, nHashV4, nNewIndex1, nNewIndex4); pFaceConnectivity.AddEdge(nSubMesh, v4, v5, nHashV4, nHashV5, nNewIndex4, nNewIndex5); pFaceConnectivity.AddEdge(nSubMesh, v5, v1, nHashV5, nHashV1, nNewIndex5, nNewIndex1); } // Update cap edges and cache if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV4, nHashV5, plistVertexData[nNewIndex4].v3Vertex, plistVertexData[nNewIndex5].v3Vertex); if(pdicClippedEdges.ContainsKey(edgeKey1) == false) pdicClippedEdges.Add(edgeKey1, new ClippedEdge(nIndex1, nIndex2, nNewIndex1, nNewIndex2, nNewIndex4)); if(pdicClippedEdges.ContainsKey(edgeKey3) == false) pdicClippedEdges.Add(edgeKey3, new ClippedEdge(nIndex1, nIndex3, nNewIndex1, nNewIndex3, nNewIndex5)); // Add geometry of other side if(fSide2 < 0.0f) { plistVertexData = listVertexDataNeg; plistObjectIndices = listIndicesNeg; pFaceConnectivity = faceConnectivityNeg; pMeshConnectivity = meshConnectivityNeg; pdicClippedEdges = dicClippedEdgesNeg; pdicRemappedIndices = dicRemappedIndicesNeg; } else { plistVertexData = listVertexDataPos; plistObjectIndices = listIndicesPos; pFaceConnectivity = faceConnectivityPos; pMeshConnectivity = meshConnectivityPos; pdicClippedEdges = dicClippedEdgesPos; pdicRemappedIndices = dicRemappedIndicesPos; } nNewIndex1 = -1; nNewIndex2 = -1; nNewIndex3 = -1; nNewIndex4 = -1; nNewIndex5 = -1; bEdgeKey1 = false; bEdgeKey3 = false; // Find edges in cache if(pdicClippedEdges.ContainsKey(edgeKey1)) { nClippedCacheHits++; bEdgeKey1 = true; nNewIndex2 = pdicClippedEdges[edgeKey1].GetSecondIndex(nIndex2); nNewIndex4 = pdicClippedEdges[edgeKey1].nClippedIndex; } else { nClippedCacheMisses++; if(pdicRemappedIndices.ContainsKey(nIndex2)) nNewIndex2 = pdicRemappedIndices[nIndex2]; } if(pdicClippedEdges.ContainsKey(edgeKey3)) { nClippedCacheHits++; bEdgeKey3 = true; nNewIndex3 = pdicClippedEdges[edgeKey3].GetSecondIndex(nIndex3); nNewIndex5 = pdicClippedEdges[edgeKey3].nClippedIndex; } else { nClippedCacheMisses++; if(pdicRemappedIndices.ContainsKey(nIndex3)) nNewIndex3 = pdicRemappedIndices[nIndex3]; } // Add vertex data for all data not present in remapped list if(nNewIndex2 == -1) { nNewIndex2 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex2].Copy()); pdicRemappedIndices[nIndex2] = nNewIndex2; } if(nNewIndex3 == -1) { nNewIndex3 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex3].Copy()); pdicRemappedIndices[nIndex3] = nNewIndex3; } if(nNewIndex4 == -1) { nNewIndex4 = plistVertexData.Count; plistVertexData.Add(vd4); } if(nNewIndex5 == -1) { nNewIndex5 = plistVertexData.Count; plistVertexData.Add(vd5); } if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false) { pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3); } plistObjectIndices.Add(nNewIndex4); plistObjectIndices.Add(nNewIndex2); plistObjectIndices.Add(nNewIndex3); if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false) { pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3); } plistObjectIndices.Add(nNewIndex4); plistObjectIndices.Add(nNewIndex3); plistObjectIndices.Add(nNewIndex5); if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false) { pFaceConnectivity.AddEdge(nSubMesh, v4, v2, nHashV4, nHashV2, nNewIndex4, nNewIndex2); pFaceConnectivity.AddEdge(nSubMesh, v2, v3, nHashV2, nHashV3, nNewIndex2, nNewIndex3); pFaceConnectivity.AddEdge(nSubMesh, v3, v4, nHashV3, nHashV4, nNewIndex3, nNewIndex4); pFaceConnectivity.AddEdge(nSubMesh, v4, v3, nHashV4, nHashV3, nNewIndex4, nNewIndex3); pFaceConnectivity.AddEdge(nSubMesh, v3, v5, nHashV3, nHashV5, nNewIndex3, nNewIndex5); pFaceConnectivity.AddEdge(nSubMesh, v5, v4, nHashV5, nHashV4, nNewIndex5, nNewIndex4); } // Update cap edges and cache if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV5, nHashV4, plistVertexData[nNewIndex5].v3Vertex, plistVertexData[nNewIndex4].v3Vertex); if(pdicClippedEdges.ContainsKey(edgeKey1) == false) pdicClippedEdges.Add(edgeKey1, new ClippedEdge(nIndex1, nIndex2, nNewIndex1, nNewIndex2, nNewIndex4)); if(pdicClippedEdges.ContainsKey(edgeKey3) == false) pdicClippedEdges.Add(edgeKey3, new ClippedEdge(nIndex1, nIndex3, nNewIndex1, nNewIndex3, nNewIndex5)); } } else if(fSide2 * fSide3 < 0.0f) { // v1 and v2 on same side, and v3 on different side if(fSide1 < 0.0f) { plistVertexData = listVertexDataNeg; plistObjectIndices = listIndicesNeg; pFaceConnectivity = faceConnectivityNeg; pMeshConnectivity = meshConnectivityNeg; pdicClippedEdges = dicClippedEdgesNeg; pdicRemappedIndices = dicRemappedIndicesNeg; } int nNewIndex1 = -1; int nNewIndex2 = -1; int nNewIndex3 = -1; int nNewIndex4 = -1; int nNewIndex5 = -1; int nHashV4 = -1; int nHashV5 = -1; bool bEdgeKey2 = false; bool bEdgeKey3 = false; EdgeKeyByIndex edgeKey2 = new EdgeKeyByIndex(nIndex2, nIndex3); EdgeKeyByIndex edgeKey3 = new EdgeKeyByIndex(nIndex1, nIndex3); // Find edges in cache if(pdicClippedEdges.ContainsKey(edgeKey2)) { nClippedCacheHits++; bEdgeKey2 = true; nNewIndex2 = pdicClippedEdges[edgeKey2].GetFirstIndex(nIndex2); nNewIndex5 = pdicClippedEdges[edgeKey2].nClippedIndex; } else { nClippedCacheMisses++; if(pdicRemappedIndices.ContainsKey(nIndex2)) nNewIndex2 = pdicRemappedIndices[nIndex2]; } if(pdicClippedEdges.ContainsKey(edgeKey3)) { nClippedCacheHits++; bEdgeKey3 = true; nNewIndex1 = pdicClippedEdges[edgeKey3].GetFirstIndex(nIndex1); nNewIndex4 = pdicClippedEdges[edgeKey3].nClippedIndex; } else { nClippedCacheMisses++; if(pdicRemappedIndices.ContainsKey(nIndex1)) nNewIndex1 = pdicRemappedIndices[nIndex1]; } // Clip if not present in clipped edge list EdgeKeyByHash clippedEdgeKeyHash = new EdgeKeyByHash(nHashV1, nHashV3); if(dicClipVerticesHash.ContainsKey(clippedEdgeKeyHash)) { nHashV4 = dicClipVerticesHash[clippedEdgeKeyHash]; } else { nHashV4 = nCurrentVertexHash++; dicClipVerticesHash.Add(clippedEdgeKeyHash, nHashV4); } clippedEdgeKeyHash = new EdgeKeyByHash(nHashV2, nHashV3); if(dicClipVerticesHash.ContainsKey(clippedEdgeKeyHash)) { nHashV5 = dicClipVerticesHash[clippedEdgeKeyHash]; } else { nHashV5 = nCurrentVertexHash++; dicClipVerticesHash.Add(clippedEdgeKeyHash, nHashV5); } VertexData vd4 = new VertexData(nHashV4), vd5 = new VertexData(nHashV5); if(bEdgeKey2 == false) { if(VertexData.ClipAgainstPlane(meshDataIn.aVertexData, nIndex2, nIndex3, v2, v3, planeSplit, ref vd5) == false) { return false; } } if(bEdgeKey3 == false) { if(VertexData.ClipAgainstPlane(meshDataIn.aVertexData, nIndex1, nIndex3, v1, v3, planeSplit, ref vd4) == false) { return false; } } // Add geometry of one side // Add vertex data for all data not present in remapped list if(nNewIndex1 == -1) { nNewIndex1 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex1].Copy()); pdicRemappedIndices[nIndex1] = nNewIndex1; } if(nNewIndex2 == -1) { nNewIndex2 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex2].Copy()); pdicRemappedIndices[nIndex2] = nNewIndex2; } if(nNewIndex4 == -1) { nNewIndex4 = plistVertexData.Count; plistVertexData.Add(vd4); } if(nNewIndex5 == -1) { nNewIndex5 = plistVertexData.Count; plistVertexData.Add(vd5); } if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false) { pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3); } plistObjectIndices.Add(nNewIndex2); plistObjectIndices.Add(nNewIndex5); plistObjectIndices.Add(nNewIndex4); if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false) { pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3); } plistObjectIndices.Add(nNewIndex2); plistObjectIndices.Add(nNewIndex4); plistObjectIndices.Add(nNewIndex1); Vector3 v4 = plistVertexData[nNewIndex4].v3Vertex; Vector3 v5 = plistVertexData[nNewIndex5].v3Vertex; if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false) { pFaceConnectivity.AddEdge(nSubMesh, v2, v5, nHashV2, nHashV5, nNewIndex2, nNewIndex5); pFaceConnectivity.AddEdge(nSubMesh, v5, v4, nHashV5, nHashV4, nNewIndex5, nNewIndex4); pFaceConnectivity.AddEdge(nSubMesh, v4, v2, nHashV4, nHashV2, nNewIndex4, nNewIndex2); pFaceConnectivity.AddEdge(nSubMesh, v2, v4, nHashV2, nHashV4, nNewIndex2, nNewIndex4); pFaceConnectivity.AddEdge(nSubMesh, v4, v1, nHashV4, nHashV1, nNewIndex4, nNewIndex1); pFaceConnectivity.AddEdge(nSubMesh, v1, v2, nHashV1, nHashV2, nNewIndex1, nNewIndex2); } // Update cap edges and cache if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV5, nHashV4, plistVertexData[nNewIndex5].v3Vertex, plistVertexData[nNewIndex4].v3Vertex); if(pdicClippedEdges.ContainsKey(edgeKey2) == false) pdicClippedEdges.Add(edgeKey2, new ClippedEdge(nIndex2, nIndex3, nNewIndex2, nNewIndex3, nNewIndex5)); if(pdicClippedEdges.ContainsKey(edgeKey3) == false) pdicClippedEdges.Add(edgeKey3, new ClippedEdge(nIndex1, nIndex3, nNewIndex1, nNewIndex3, nNewIndex4)); // Add geometry of other side if(fSide3 < 0.0f) { plistVertexData = listVertexDataNeg; plistObjectIndices = listIndicesNeg; pFaceConnectivity = faceConnectivityNeg; pMeshConnectivity = meshConnectivityNeg; pdicClippedEdges = dicClippedEdgesNeg; pdicRemappedIndices = dicRemappedIndicesNeg; } else { plistVertexData = listVertexDataPos; plistObjectIndices = listIndicesPos; pFaceConnectivity = faceConnectivityPos; pMeshConnectivity = meshConnectivityPos; pdicClippedEdges = dicClippedEdgesPos; pdicRemappedIndices = dicRemappedIndicesPos; } nNewIndex1 = -1; nNewIndex2 = -1; nNewIndex3 = -1; nNewIndex4 = -1; nNewIndex5 = -1; bEdgeKey2 = false; bEdgeKey3 = false; // Find edges in cache if(pdicClippedEdges.ContainsKey(edgeKey2)) { nClippedCacheHits++; bEdgeKey2 = true; nNewIndex3 = pdicClippedEdges[edgeKey2].GetSecondIndex(nIndex3); nNewIndex5 = pdicClippedEdges[edgeKey2].nClippedIndex; } else { nClippedCacheMisses++; if(pdicRemappedIndices.ContainsKey(nIndex3)) nNewIndex3 = pdicRemappedIndices[nIndex3]; } if(pdicClippedEdges.ContainsKey(edgeKey3)) { nClippedCacheHits++; bEdgeKey3 = true; nNewIndex3 = pdicClippedEdges[edgeKey3].GetSecondIndex(nIndex3); nNewIndex4 = pdicClippedEdges[edgeKey3].nClippedIndex; } else { nClippedCacheMisses++; if(pdicRemappedIndices.ContainsKey(nIndex3)) nNewIndex3 = pdicRemappedIndices[nIndex3]; } // Add vertex data for all data not present in remapped list if(nNewIndex3 == -1) { nNewIndex3 = plistVertexData.Count; plistVertexData.Add(meshDataIn.aVertexData[nIndex3].Copy()); pdicRemappedIndices[nIndex3] = nNewIndex3; } if(nNewIndex4 == -1) { nNewIndex4 = plistVertexData.Count; plistVertexData.Add(vd4); } if(nNewIndex5 == -1) { nNewIndex5 = plistVertexData.Count; plistVertexData.Add(vd5); } if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false) { pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3); } plistObjectIndices.Add(nNewIndex5); plistObjectIndices.Add(nNewIndex3); plistObjectIndices.Add(nNewIndex4); if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false) { pFaceConnectivity.AddEdge(nSubMesh, v5, v3, nHashV5, nHashV3, nNewIndex5, nNewIndex3); pFaceConnectivity.AddEdge(nSubMesh, v3, v4, nHashV3, nHashV4, nNewIndex3, nNewIndex4); pFaceConnectivity.AddEdge(nSubMesh, v4, v5, nHashV4, nHashV5, nNewIndex4, nNewIndex5); } // Update cap edges and cache if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV4, nHashV5, plistVertexData[nNewIndex4].v3Vertex, plistVertexData[nNewIndex5].v3Vertex); if(pdicClippedEdges.ContainsKey(edgeKey2) == false) pdicClippedEdges.Add(edgeKey2, new ClippedEdge(nIndex2, nIndex3, nNewIndex2, nNewIndex3, nNewIndex5)); if(pdicClippedEdges.ContainsKey(edgeKey3) == false) pdicClippedEdges.Add(edgeKey3, new ClippedEdge(nIndex1, nIndex3, nNewIndex1, nNewIndex3, nNewIndex4)); } } } } // Debug.Log("Clipped cache hits " + nClippedCacheHits + " clipped cache misses " + nClippedCacheMisses); // Compute transforms Vector3 v3CenterPos = Vector3.zero; if(listVertexDataPos.Count > 0) { Vector3 v3Min = Vector3.zero, v3Max = Vector3.zero; MeshData.ComputeMinMax(listVertexDataPos, ref v3Min, ref v3Max); v3CenterPos = (v3Min + v3Max) * 0.5f; } Matrix4x4 mtxToLocalPos = Matrix4x4.TRS(v3CenterPos, meshDataIn.qRotation, meshDataIn.v3Scale).inverse; if(splitOptions.bVerticesAreLocal) { mtxToLocalPos = Matrix4x4.TRS(v3CenterPos, Quaternion.identity, Vector3.one).inverse; } Vector3 v3CenterNeg = Vector3.zero; if(listVertexDataNeg.Count > 0) { Vector3 v3Min = Vector3.zero, v3Max = Vector3.zero; MeshData.ComputeMinMax(listVertexDataNeg, ref v3Min, ref v3Max); v3CenterNeg = (v3Min + v3Max) * 0.5f; } Matrix4x4 mtxToLocalNeg = Matrix4x4.TRS(v3CenterNeg, meshDataIn.qRotation, meshDataIn.v3Scale).inverse; if(splitOptions.bVerticesAreLocal) { mtxToLocalNeg = Matrix4x4.TRS(v3CenterNeg, Quaternion.identity, Vector3.one).inverse; } // Resolve cap outline and add its geometry List<List<Vector3>> listlistResolvedCapVertices = new List<List<Vector3>>(); List<List<int>> listlistResolvedCapHashValues = new List<List<int>>(); bool bNeedsConnectivityPostprocess = false; Matrix4x4 mtxPlane = Matrix4x4.TRS(v3PlanePoint, Quaternion.LookRotation(Vector3.Cross(v3PlaneNormal, v3PlaneRight), v3PlaneNormal), Vector3.one); if(dicCapEdges.Count > 0 && splitOptions.bForceNoCap == false) { if(ResolveCap(dicCapEdges, listlistResolvedCapVertices, listlistResolvedCapHashValues, fracturedComponent)) { if(listlistResolvedCapVertices.Count > 1) { // There's more than one closed cap. We need to postprocess the mesh because there may be more than one object on a side of the plane as a result of the clipping. bNeedsConnectivityPostprocess = (fracturedComponent.GenerateIslands && (splitOptions.bForceNoIslandGeneration == false)) ? true : false; } TriangulateConstrainedDelaunay( listlistResolvedCapVertices, listlistResolvedCapHashValues, splitOptions.bForceCapVertexSoup, fracturedComponent, bNeedsConnectivityPostprocess, faceConnectivityPos, faceConnectivityNeg, meshConnectivityPos, meshConnectivityNeg, splitOptions.nForceMeshConnectivityHash, nSplitCloseSubMesh, mtxPlane, mtxToLocalPos, mtxToLocalNeg, v3CenterPos, v3CenterNeg, alistIndicesPos, listVertexDataPos, alistIndicesNeg, listVertexDataNeg); } else { if(fracturedComponent.Verbose) Debug.LogWarning("Error resolving cap"); } } // Postprocess if necessary if(bNeedsConnectivityPostprocess) { // Search for multiple objects inside each meshes List<MeshData> listIslandsPos = MeshData.PostProcessConnectivity(meshDataIn, faceConnectivityPos, meshConnectivityPos, alistIndicesPos, listVertexDataPos, nSplitCloseSubMesh, nCurrentVertexHash, false); List<MeshData> listIslandsNeg = new List<MeshData>(); if(splitOptions.bIgnoreNegativeSide == false) { listIslandsNeg = MeshData.PostProcessConnectivity(meshDataIn, faceConnectivityNeg, meshConnectivityNeg, alistIndicesNeg, listVertexDataNeg, nSplitCloseSubMesh, nCurrentVertexHash, false); } // Sometimes we are feed a mesh with multiple islands as input. If this is the case, compute connectivity between islands at this point. List<MeshData> listTotalIslands = new List<MeshData>(); listTotalIslands.AddRange(listIslandsPos); listTotalIslands.AddRange(listIslandsNeg); if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoIslandConnectionInfo == false) { for(int i = 0; i < listTotalIslands.Count; i++) { if(progress != null && listTotalIslands.Count > 10 && splitOptions.bForceNoProgressInfo == false) { progress("Fracturing", "Processing island connectivity...", i / (float)listTotalIslands.Count); if(Fracturer.IsFracturingCancelled()) return false; } for(int j = 0; j < listTotalIslands.Count; j++) { if(i != j) { ComputeIslandsMeshDataConnectivity(fracturedComponent, splitOptions.bVerticesAreLocal, listTotalIslands[i], listTotalIslands[j]); } } } } listMeshDatasPosOut.AddRange(listIslandsPos); listMeshDatasNegOut.AddRange(listIslandsNeg); } else { // Create new MeshDatas if(listVertexDataPos.Count > 0 && alistIndicesPos.Length > 0) { MeshData newMeshData = new MeshData(meshDataIn.aMaterials, alistIndicesPos, listVertexDataPos, nSplitCloseSubMesh, v3CenterPos, meshDataIn.qRotation, meshDataIn.v3Scale, mtxToLocalPos, false, false); newMeshData.meshDataConnectivity = meshConnectivityPos; newMeshData.nCurrentVertexHash = nCurrentVertexHash; listMeshDatasPosOut.Add(newMeshData); } if(listVertexDataNeg.Count > 0 && alistIndicesNeg.Length > 0 && splitOptions.bIgnoreNegativeSide == false) { MeshData newMeshData = new MeshData(meshDataIn.aMaterials, alistIndicesNeg, listVertexDataNeg, nSplitCloseSubMesh, v3CenterNeg, meshDataIn.qRotation, meshDataIn.v3Scale, mtxToLocalNeg, false, false); newMeshData.meshDataConnectivity = meshConnectivityNeg; newMeshData.nCurrentVertexHash = nCurrentVertexHash; listMeshDatasNegOut.Add(newMeshData); } } return true; }
private static bool ComputeIslandsMeshDataConnectivity(FracturedObject fracturedComponent, bool bVerticesAreLocal, MeshData meshData1, MeshData meshData2) { float fMargin = fracturedComponent.ChunkIslandConnectionMaxDistance; // Vertices and min/max may be in local space. We want distance checks to be in world space Vector3 v3Min1 = meshData1.v3Min; if(bVerticesAreLocal) v3Min1 = Vector3.Scale(v3Min1, meshData1.v3Scale); Vector3 v3Max1 = meshData1.v3Max; if(bVerticesAreLocal) v3Max1 = Vector3.Scale(v3Max1, meshData1.v3Scale); Vector3 v3Min2 = meshData2.v3Min; if(bVerticesAreLocal) v3Min2 = Vector3.Scale(v3Min2, meshData2.v3Scale); Vector3 v3Max2 = meshData2.v3Max; if(bVerticesAreLocal) v3Max2 = Vector3.Scale(v3Max2, meshData2.v3Scale); if((v3Min1.x > (v3Max2.x + fMargin)) || (v3Min1.y > (v3Max2.y + fMargin)) || (v3Min1.z > (v3Max2.z + fMargin))) { return false; } if((v3Min2.x > (v3Max1.x + fMargin)) || (v3Min2.y > (v3Max1.y + fMargin)) || (v3Min2.z > (v3Max1.z + fMargin))) { return false; } bool bConnected = false; float fDistPlaneMax = fracturedComponent.ChunkIslandConnectionMaxDistance; for(int nSubMesh1 = 0; nSubMesh1 < meshData1.aaIndices.Length; nSubMesh1++) { for(int nFace1 = 0; nFace1 < meshData1.aaIndices[nSubMesh1].Length / 3; nFace1++) { Vector3 v1 = meshData1.aVertexData[meshData1.aaIndices[nSubMesh1][nFace1 * 3 + 0]].v3Vertex; Vector3 v2 = meshData1.aVertexData[meshData1.aaIndices[nSubMesh1][nFace1 * 3 + 1]].v3Vertex; Vector3 v3 = meshData1.aVertexData[meshData1.aaIndices[nSubMesh1][nFace1 * 3 + 2]].v3Vertex; if(bVerticesAreLocal) { v1 = Vector3.Scale(v1, meshData1.v3Scale); v2 = Vector3.Scale(v2, meshData1.v3Scale); v3 = Vector3.Scale(v3, meshData1.v3Scale); } Vector3 v3Forward = -Vector3.Cross(v2 - v1, v3 - v1); float fArea1 = v3Forward.magnitude; if(fArea1 < Parameters.EPSILONCROSSPRODUCT) { continue; } Quaternion qFace = Quaternion.LookRotation(v3Forward.normalized, (v2 - v1).normalized); Matrix4x4 mtxToFace = Matrix4x4.TRS(v1, qFace, Vector3.one).inverse; Plane planeFace1 = new Plane(v1, v2, v3); for(int nSubMesh2 = 0; nSubMesh2 < meshData2.aaIndices.Length; nSubMesh2++) { for(int nFace2 = 0; nFace2 < meshData2.aaIndices[nSubMesh2].Length / 3; nFace2++) { Vector3 v3Other1 = meshData2.aVertexData[meshData2.aaIndices[nSubMesh2][nFace2 * 3 + 0]].v3Vertex; Vector3 v3Other2 = meshData2.aVertexData[meshData2.aaIndices[nSubMesh2][nFace2 * 3 + 1]].v3Vertex; Vector3 v3Other3 = meshData2.aVertexData[meshData2.aaIndices[nSubMesh2][nFace2 * 3 + 2]].v3Vertex; if(bVerticesAreLocal) { v3Other1 = Vector3.Scale(v3Other1, meshData2.v3Scale); v3Other2 = Vector3.Scale(v3Other2, meshData2.v3Scale); v3Other3 = Vector3.Scale(v3Other3, meshData2.v3Scale); } // Compute distance from face1 to face2 float fDist1 = Mathf.Abs(planeFace1.GetDistanceToPoint(v3Other1)); if(fDist1 > fDistPlaneMax) continue; float fDist2 = Mathf.Abs(planeFace1.GetDistanceToPoint(v3Other2)); if(fDist2 > fDistPlaneMax) continue; float fDist3 = Mathf.Abs(planeFace1.GetDistanceToPoint(v3Other3)); if(fDist3 > fDistPlaneMax) continue; // See if they intersect in 2D (face 1 local coordinates) Vector3 v3OtherCenterLocal = (v3Other1 + v3Other2 + v3Other3) / 3.0f; v3OtherCenterLocal = mtxToFace.MultiplyPoint3x4(v3OtherCenterLocal); Vector3 v3Local1 = mtxToFace.MultiplyPoint3x4(v1); Vector3 v3Local2 = mtxToFace.MultiplyPoint3x4(v2); Vector3 v3Local3 = mtxToFace.MultiplyPoint3x4(v3); Vector3 v3Edge2 = v3Local3 - v3Local2; Vector3 v3Edge3 = v3Local1 - v3Local3; bool bFaceConnected = false; // Test the center if(v3OtherCenterLocal.x >= 0.0f) { if(Vector3.Cross(v3Edge2, v3OtherCenterLocal - v3Local2).z <= 0.0f) { if(Vector3.Cross(v3Edge3, v3OtherCenterLocal - v3Local3).z <= 0.0f) { bFaceConnected = true; } } } if(bFaceConnected == false) { // Try intersecting lines Vector3 v3OtherLocal1 = mtxToFace.MultiplyPoint3x4(v3Other1); Vector3 v3OtherLocal2 = mtxToFace.MultiplyPoint3x4(v3Other2); Vector3 v3OtherLocal3 = mtxToFace.MultiplyPoint3x4(v3Other3); if(bFaceConnected == false) if(IntersectEdges2D(v3OtherLocal1.x, v3OtherLocal1.y, v3OtherLocal2.x, v3OtherLocal2.y, v3Local1.x, v3Local1.y, v3Local2.x, v3Local2.y)) bFaceConnected = true; if(bFaceConnected == false) if(IntersectEdges2D(v3OtherLocal1.x, v3OtherLocal1.y, v3OtherLocal2.x, v3OtherLocal2.y, v3Local2.x, v3Local2.y, v3Local3.x, v3Local3.y)) bFaceConnected = true; if(bFaceConnected == false) if(IntersectEdges2D(v3OtherLocal1.x, v3OtherLocal1.y, v3OtherLocal2.x, v3OtherLocal2.y, v3Local3.x, v3Local3.y, v3Local1.x, v3Local1.y)) bFaceConnected = true; if(bFaceConnected == false) if(IntersectEdges2D(v3OtherLocal2.x, v3OtherLocal2.y, v3OtherLocal3.x, v3OtherLocal3.y, v3Local1.x, v3Local1.y, v3Local2.x, v3Local2.y)) bFaceConnected = true; if(bFaceConnected == false) if(IntersectEdges2D(v3OtherLocal2.x, v3OtherLocal2.y, v3OtherLocal3.x, v3OtherLocal3.y, v3Local2.x, v3Local2.y, v3Local3.x, v3Local3.y)) bFaceConnected = true; if(bFaceConnected == false) if(IntersectEdges2D(v3OtherLocal2.x, v3OtherLocal2.y, v3OtherLocal3.x, v3OtherLocal3.y, v3Local3.x, v3Local3.y, v3Local1.x, v3Local1.y)) bFaceConnected = true; if(bFaceConnected == false) if(IntersectEdges2D(v3OtherLocal3.x, v3OtherLocal3.y, v3OtherLocal1.x, v3OtherLocal1.y, v3Local1.x, v3Local1.y, v3Local2.x, v3Local2.y)) bFaceConnected = true; if(bFaceConnected == false) if(IntersectEdges2D(v3OtherLocal3.x, v3OtherLocal3.y, v3OtherLocal1.x, v3OtherLocal1.y, v3Local2.x, v3Local2.y, v3Local3.x, v3Local3.y)) bFaceConnected = true; if(bFaceConnected == false) if(IntersectEdges2D(v3OtherLocal3.x, v3OtherLocal3.y, v3OtherLocal1.x, v3OtherLocal1.y, v3Local3.x, v3Local3.y, v3Local1.x, v3Local1.y)) bFaceConnected = true; } if(bFaceConnected) { int nHash = MeshDataConnectivity.GetNewHash(); // New hash value to identify the 2 shared faces meshData1.meshDataConnectivity.NotifyNewCapFace(nHash, nSubMesh1, nFace1); meshData2.meshDataConnectivity.NotifyNewCapFace(nHash, nSubMesh2, nFace2); bConnected = true; } } } } } return bConnected; }
void OnCollisionEnter(Collision collision) { if (collision.gameObject.tag == "Stone") { if (mujuk == false) { mujuk = true; if (collision.contacts == null) { return; } if (collision.contacts.Length == 0) { return; } // Was it a big enough hit? FracturedObject fracturedObject = gameObject.GetComponent <FracturedObject> (); if (fracturedObject != null) { float fMass = collision.rigidbody != null ? collision.rigidbody.mass : Mathf.Infinity; if (collision.relativeVelocity.magnitude > fracturedObject.EventDetachMinVelocity && fMass > fracturedObject.EventDetachMinVelocity) { // Disable fracturable object collider if (collision.rigidbody != null) { fracturedObject.EventDetachMinMass -= collision.rigidbody.mass; } if (fracturedObject.EventDetachMinMass < 0) { //Debug.Log (collision.gameObject.GetComponent<PhotonView> ().ownerId.ToString ()); //부순사람 카운트 업 if (collision.gameObject.GetComponent <PhotonView> ().owner.ID == 1) { SendKill(collision.gameObject.GetComponent <PhotonView> ().owner.ID, k1.text); } if (collision.gameObject.GetComponent <PhotonView> ().owner.ID == 2) { SendKill(collision.gameObject.GetComponent <PhotonView> ().owner.ID, k2.text); } if (collision.gameObject.GetComponent <PhotonView> ().owner.ID == 3) { SendKill(collision.gameObject.GetComponent <PhotonView> ().owner.ID, k3.text); } if (collision.gameObject.GetComponent <PhotonView> ().owner.ID == 4) { SendKill(collision.gameObject.GetComponent <PhotonView> ().owner.ID, k4.text); } //부셔진돌 캔버스 제거 fracturedObject.GetComponent <Collider> ().enabled = false; Rigidbody fracturableRigidbody = fracturedObject.GetComponent <Rigidbody> (); if (fracturableRigidbody != null) { fracturableRigidbody.isKinematic = true; } for (int i = 0; i < fracturedObject.ListFracturedChunks.Count; i++) { EnableObjectColliders(fracturedObject.ListFracturedChunks [i].gameObject, true); } // Explode fracturedObject.Explode(collision.contacts [0].point, collision.relativeVelocity.magnitude); //죽은돌 삭제 GameObject delStone = GameObject.Find(fracturedObject.name); Destroy(delStone); } // Enable chunk colliders } } } StartCoroutine("divine"); } }
public static SpaceTreeNode BuildSpaceTree(MeshData meshDataIn, int nSubdivisionLevels, FracturedObject fracturedComponent, ProgressDelegate progress = null) { if (nSubdivisionLevels < 1) { return(null); } SplitOptions splitOptions = new SplitOptions(); splitOptions.bForceNoIslandGeneration = true; splitOptions.bForceNoChunkConnectionInfo = true; splitOptions.bForceNoIslandConnectionInfo = true; splitOptions.bForceNoCap = false; splitOptions.bVerticesAreLocal = true; SpaceTreeNode nodeRoot = new SpaceTreeNode(); nodeRoot.listMeshDatasSpace = new List <MeshData>(); nodeRoot.listMeshDatasSpace.Add(meshDataIn); nodeRoot.nLevel = 0; nodeRoot.nSplitsX = 0; nodeRoot.nSplitsY = 0; nodeRoot.nSplitsZ = 0; nodeRoot.v3Min = meshDataIn.v3Min; nodeRoot.v3Max = meshDataIn.v3Max; Queue <SpaceTreeNode> queueNodes = new Queue <SpaceTreeNode>(); queueNodes.Enqueue(nodeRoot); int nTotalSubdivisions = 0; int nCurrentSubdivisions = 0; int nSplitsX = 0; int nSplitsY = 0; int nSplitsZ = 0; for (int i = 0; i < nSubdivisionLevels; i++) { nTotalSubdivisions += Mathf.RoundToInt(Mathf.Pow(2, i)); } while (queueNodes.Count > 0) { SpaceTreeNode nodeCurrent = queueNodes.Dequeue(); List <MeshData> listMeshDataPos; List <MeshData> listMeshDataNeg; if (nodeCurrent.nLevel < nSubdivisionLevels) { if (progress != null) { progress("Fracturing", string.Format("Pre computing space volume (split {0}/{1}, Depth {2})", nCurrentSubdivisions + 1, nTotalSubdivisions, nodeCurrent.nLevel + 1), Mathf.Clamp01((float)nCurrentSubdivisions / (float)nTotalSubdivisions)); } if (Fracturer.IsFracturingCancelled()) { return(null); } Vector3 v3Normal = Vector3.up; Vector3 v3Right = Vector3.right; Vector3 v3Pos = (nodeCurrent.v3Min + nodeCurrent.v3Max) * 0.5f; float fSizeX = nodeCurrent.v3Max.x - nodeCurrent.v3Min.x; float fSizeY = nodeCurrent.v3Max.y - nodeCurrent.v3Min.y; float fSizeZ = nodeCurrent.v3Max.z - nodeCurrent.v3Min.z; Vector3 v3MinNeg = nodeCurrent.v3Min; Vector3 v3MaxNeg = nodeCurrent.v3Max; Vector3 v3MinPos = nodeCurrent.v3Min; Vector3 v3MaxPos = nodeCurrent.v3Max; if (fSizeX >= fSizeY && fSizeX >= fSizeZ) { v3Normal = Vector3.right; v3Right = Vector3.forward; v3MaxNeg.x = v3Pos.x; v3MinPos.x = v3Pos.x; nSplitsX++; } else if (fSizeY >= fSizeX && fSizeY >= fSizeZ) { v3Normal = Vector3.up; v3Right = Vector3.right; v3MaxNeg.y = v3Pos.y; v3MinPos.y = v3Pos.y; nSplitsY++; } else { v3Normal = Vector3.forward; v3Right = Vector3.right; v3MaxNeg.z = v3Pos.z; v3MinPos.z = v3Pos.z; nSplitsZ++; } foreach (MeshData meshData in nodeCurrent.listMeshDatasSpace) { if (SplitMeshUsingPlane(meshData, fracturedComponent, splitOptions, v3Normal, v3Right, v3Pos, out listMeshDataPos, out listMeshDataNeg, progress) == true) { nodeCurrent.nodeOneSide = new SpaceTreeNode(); nodeCurrent.nodeOneSide.listMeshDatasSpace = listMeshDataNeg; nodeCurrent.nodeOneSide.v3Min = v3MinNeg; nodeCurrent.nodeOneSide.v3Max = v3MaxNeg; nodeCurrent.nodeOneSide.nLevel = nodeCurrent.nLevel + 1; nodeCurrent.nodeOneSide.nSplitsX = nSplitsX; nodeCurrent.nodeOneSide.nSplitsY = nSplitsY; nodeCurrent.nodeOneSide.nSplitsZ = nSplitsZ; queueNodes.Enqueue(nodeCurrent.nodeOneSide); nodeCurrent.nodeOtherSide = new SpaceTreeNode(); nodeCurrent.nodeOtherSide.listMeshDatasSpace = listMeshDataPos; nodeCurrent.nodeOtherSide.v3Min = v3MinPos; nodeCurrent.nodeOtherSide.v3Max = v3MaxPos; nodeCurrent.nodeOtherSide.nLevel = nodeCurrent.nLevel + 1; nodeCurrent.nodeOtherSide.nSplitsX = nSplitsX; nodeCurrent.nodeOtherSide.nSplitsY = nSplitsY; nodeCurrent.nodeOtherSide.nSplitsZ = nSplitsZ; queueNodes.Enqueue(nodeCurrent.nodeOtherSide); } } nCurrentSubdivisions++; } } return(nodeRoot); }
static bool ResolveCap(Dictionary <EdgeKeyByHash, CapEdge> dicCapEdges, List <List <Vector3> > listlistResolvedCapVertices, List <List <int> > listlistResolvedCapHashValues, FracturedObject fracturedComponent) { if (dicCapEdges.Count < 3) { if (fracturedComponent.Verbose) { Debug.LogWarning("Cap has < 3 segments"); } return(false); } listlistResolvedCapVertices.Clear(); listlistResolvedCapHashValues.Clear(); List <CapEdge> listResolvedCap = new List <CapEdge>(); List <CapEdge> listUnresolvedCap = new List <CapEdge>(dicCapEdges.Values); List <Vector3> newListVertices = new List <Vector3>(); List <int> newListHashValues = new List <int>(); int nTotalSegments = listUnresolvedCap.Count; listResolvedCap.Add(listUnresolvedCap[0]); newListVertices.Add(listUnresolvedCap[0].v1); newListVertices.Add(listUnresolvedCap[0].v2); newListHashValues.Add(listUnresolvedCap[0].nHash1); newListHashValues.Add(listUnresolvedCap[0].nHash2); listUnresolvedCap.RemoveAt(0); // Try to match all segments while (listUnresolvedCap.Count > 0) { // Search for a connected segment in the unresolved segment pool CapEdge CapEdgeLast = listResolvedCap[listResolvedCap.Count - 1]; CapEdge CapEdgeFirst = listResolvedCap[0]; bool bFound = false; for (int nSegmentUnresolved = 0; nSegmentUnresolved < listUnresolvedCap.Count; nSegmentUnresolved++) { CapEdge CapEdgeUnresolved = listUnresolvedCap[nSegmentUnresolved]; int nSharesVertexEnd = CapEdgeLast.SharesVertex1Of(CapEdgeUnresolved); int nSharesVertexStart = CapEdgeFirst.SharesVertex2Of(CapEdgeUnresolved); if (nSharesVertexEnd == 2) { newListVertices.Add(CapEdgeUnresolved.v2); newListHashValues.Add(CapEdgeUnresolved.nHash2); listResolvedCap.Add(CapEdgeUnresolved); listUnresolvedCap.RemoveAt(nSegmentUnresolved); bFound = true; break; } else if (nSharesVertexStart == 1) { newListVertices.Insert(0, CapEdgeUnresolved.v1); newListHashValues.Insert(0, CapEdgeUnresolved.nHash1); listResolvedCap.Insert(0, CapEdgeUnresolved); listUnresolvedCap.RemoveAt(nSegmentUnresolved); bFound = true; break; } } bool bFinish = bFound == false; if (listResolvedCap.Count >= 3) { if (listResolvedCap[listResolvedCap.Count - 1].SharesVertex1Of(listResolvedCap[0]) == 2) { bFinish = true; } } if (listUnresolvedCap.Count == 0) { bFinish = true; } if (bFinish) { // Finished, new cap vertex group int nTotalAdd = newListVertices.Count; if (Vector3.Distance(newListVertices[0], newListVertices[newListVertices.Count - 1]) < Parameters.EPSILONDISTANCEVERTEX) { nTotalAdd = newListVertices.Count - 1; } if (nTotalAdd > 2) { List <Vector3> listAddVertices = new List <Vector3>(); List <int> listAddHash = new List <int>(); for (int i = 0; i < nTotalAdd; i++) { listAddVertices.Add(newListVertices[i]); listAddHash.Add(newListHashValues[i]); } listlistResolvedCapVertices.Add(listAddVertices); listlistResolvedCapHashValues.Add(listAddHash); } else { if (fracturedComponent.Verbose) { Debug.LogWarning("Cap group has less than 3 vertices (" + newListVertices.Count + ")"); } } if (listUnresolvedCap.Count > 0) { listResolvedCap.Clear(); listResolvedCap.Add(listUnresolvedCap[0]); newListVertices.Clear(); newListHashValues.Clear(); newListVertices.Add(listUnresolvedCap[0].v1); newListVertices.Add(listUnresolvedCap[0].v2); newListHashValues.Add(listUnresolvedCap[0].nHash1); newListHashValues.Add(listUnresolvedCap[0].nHash2); listUnresolvedCap.RemoveAt(0); } } } if (listUnresolvedCap.Count > 0) { if (fracturedComponent.Verbose) { Debug.LogWarning(string.Format("Cap has {0}/{1} unresolved segments left", listUnresolvedCap.Count, nTotalSegments)); } } return(true); }
// Use this for initialization void Awake() { fo = GetComponent <FracturedObject> (); }
static void Triangulate(List <Vector3> listVertices, List <int> listIndices, FracturedObject fracturedComponent, List <List <Vector3> > listlistPointsConstrainedDelaunay, List <List <int> > listlistHashValuesConstrainedDelaunay, bool bConnectivityPostprocess, MeshFaceConnectivity faceConnectivityPos, MeshFaceConnectivity faceConnectivityNeg, MeshDataConnectivity meshConnectivityPos, MeshDataConnectivity meshConnectivityNeg, int nForceMeshConnectivityHash, int nSplitCloseSubMesh, Matrix4x4 mtxPlane, Matrix4x4 mtxToLocalPos, Matrix4x4 mtxToLocalNeg, Vector3 v3CenterPos, Vector3 v3CenterNeg, List <int>[] aListIndicesPosInOut, List <VertexData> listVertexDataPosInOut, List <int>[] aListIndicesNegInOut, List <VertexData> listVertexDataNegInOut) { int nPositiveSideIndexStart = listVertexDataPosInOut.Count; int nNegativeSideIndexStart = listVertexDataNegInOut.Count; if (listVertexDataPosInOut.Count < 1 || listVertexDataNegInOut.Count < 1) { return; } // Add vertex data VertexData[] aVtxDataCapPos = new VertexData[listVertices.Count]; VertexData[] aVtxDataCapNeg = new VertexData[listVertices.Count]; Vector3 v3PlaneNormal = mtxPlane.MultiplyVector(Vector3.up); float fReversedCapNormals = fracturedComponent.InvertCapNormals ? -1.0f : 1.0f; Vector3 v3CapNormalLocalPos = mtxToLocalPos.MultiplyVector(-v3PlaneNormal * fReversedCapNormals); Vector3 v3CapNormalLocalNeg = mtxToLocalNeg.MultiplyVector(v3PlaneNormal * fReversedCapNormals); Vector3 v3TangentPos = Vector3.right; v3TangentPos = mtxPlane.MultiplyVector(v3TangentPos); v3TangentPos = mtxToLocalPos.MultiplyVector(v3TangentPos); Vector3 v3TangentNeg = Vector3.right; v3TangentNeg = mtxPlane.MultiplyVector(v3TangentNeg); v3TangentNeg = mtxToLocalNeg.MultiplyVector(v3TangentNeg); Matrix4x4 mtxPlaneInverse = mtxPlane.inverse; Color32 colWhite = new Color32(255, 255, 255, 255); Vector3 v2Mapping = Vector2.zero; for (int i = 0; i < listVertices.Count; i++) { Vector3 v3Local = mtxPlaneInverse.MultiplyPoint3x4(listVertices[i]); v2Mapping.x = v3Local.x * fracturedComponent.SplitMappingTileU; v2Mapping.y = v3Local.z * fracturedComponent.SplitMappingTileV; int nVertexHash = ComputeVertexHash(listVertices[i], listlistPointsConstrainedDelaunay, listlistHashValuesConstrainedDelaunay); aVtxDataCapPos[i] = new VertexData(nVertexHash, listVertices[i], v3CapNormalLocalPos, v3TangentPos, colWhite, v2Mapping, v2Mapping, true, true, listVertexDataPosInOut[0].bHasColor32, listVertexDataPosInOut[0].bHasMapping1, listVertexDataPosInOut[0].bHasMapping2); aVtxDataCapNeg[i] = new VertexData(nVertexHash, listVertices[i], v3CapNormalLocalNeg, v3TangentNeg, colWhite, v2Mapping, v2Mapping, true, true, listVertexDataNegInOut[0].bHasColor32, listVertexDataNegInOut[0].bHasMapping1, listVertexDataNegInOut[0].bHasMapping2); } listVertexDataPosInOut.AddRange(aVtxDataCapPos); listVertexDataNegInOut.AddRange(aVtxDataCapNeg); // Add indices for (int i = 0; i < listIndices.Count / 3; i++) { int nTriangleA = listIndices[i * 3 + 0]; int nTriangleB = listIndices[i * 3 + 1]; int nTriangleC = listIndices[i * 3 + 2]; int nHashPosA = listVertexDataPosInOut[nPositiveSideIndexStart + nTriangleA].nVertexHash; int nHashPosB = listVertexDataPosInOut[nPositiveSideIndexStart + nTriangleB].nVertexHash; int nHashPosC = listVertexDataPosInOut[nPositiveSideIndexStart + nTriangleC].nVertexHash; int nHashNegA = listVertexDataNegInOut[nNegativeSideIndexStart + nTriangleA].nVertexHash; int nHashNegB = listVertexDataNegInOut[nNegativeSideIndexStart + nTriangleB].nVertexHash; int nHashNegC = listVertexDataNegInOut[nNegativeSideIndexStart + nTriangleC].nVertexHash; if (nHashPosA != -1 && nHashPosB != -1 && nHashPosC != -1 && nHashNegA != -1 && nHashNegB != -1 && nHashNegC != -1) { int nMeshConnectivityHash = nForceMeshConnectivityHash == -1 ? MeshDataConnectivity.GetNewHash() : nForceMeshConnectivityHash; // New hash value to identify the 2 shared faces if (fracturedComponent.GenerateChunkConnectionInfo) { meshConnectivityPos.NotifyNewCapFace(nMeshConnectivityHash, nSplitCloseSubMesh, aListIndicesPosInOut[nSplitCloseSubMesh].Count / 3); } aListIndicesPosInOut[nSplitCloseSubMesh].Add(nPositiveSideIndexStart + nTriangleA); aListIndicesPosInOut[nSplitCloseSubMesh].Add(nPositiveSideIndexStart + nTriangleB); aListIndicesPosInOut[nSplitCloseSubMesh].Add(nPositiveSideIndexStart + nTriangleC); if (bConnectivityPostprocess) { faceConnectivityPos.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleA], listVertices[nTriangleB], nHashPosA, nHashPosB, nPositiveSideIndexStart + nTriangleA, nPositiveSideIndexStart + nTriangleB); faceConnectivityPos.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleB], listVertices[nTriangleC], nHashPosB, nHashPosC, nPositiveSideIndexStart + nTriangleB, nPositiveSideIndexStart + nTriangleC); faceConnectivityPos.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleC], listVertices[nTriangleA], nHashPosC, nHashPosA, nPositiveSideIndexStart + nTriangleC, nPositiveSideIndexStart + nTriangleA); } if (fracturedComponent.GenerateChunkConnectionInfo) { meshConnectivityNeg.NotifyNewCapFace(nMeshConnectivityHash, nSplitCloseSubMesh, aListIndicesNegInOut[nSplitCloseSubMesh].Count / 3); } aListIndicesNegInOut[nSplitCloseSubMesh].Add(nNegativeSideIndexStart + nTriangleA); aListIndicesNegInOut[nSplitCloseSubMesh].Add(nNegativeSideIndexStart + nTriangleC); aListIndicesNegInOut[nSplitCloseSubMesh].Add(nNegativeSideIndexStart + nTriangleB); if (bConnectivityPostprocess) { faceConnectivityNeg.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleA], listVertices[nTriangleC], nHashNegA, nHashNegC, nNegativeSideIndexStart + nTriangleA, nNegativeSideIndexStart + nTriangleC); faceConnectivityNeg.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleC], listVertices[nTriangleB], nHashNegC, nHashNegB, nNegativeSideIndexStart + nTriangleC, nNegativeSideIndexStart + nTriangleB); faceConnectivityNeg.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleB], listVertices[nTriangleA], nHashNegB, nHashNegA, nNegativeSideIndexStart + nTriangleB, nNegativeSideIndexStart + nTriangleA); } } } }
void Awake() { _fracturedObject = GetComponentInChildren <FracturedObject>(); _chunkList = GetComponentsInChildren <FracturedChunk>().ToList(); _changeColor = GetComponent <ChangeColor>(); }
// Use this for initialization void Start() { _fracturedObject = GetComponentInChildren <FracturedObject>(); _chunkList = GetComponentsInChildren <Transform>().Where(x => x.gameObject.layer != Layers.Radar.Index).ToList(); _trailRenderer = GetComponentInChildren <TrailRenderer>(); }