/// <summary> /// 临时缓存的三角形集合 /// </summary> unsafe void Collapse(VertexStruct u, int v, NativeArray <StructRelevanceSphere> aRelevanceSpheres) { if (v == -1) //v=9779 坍塌目标 { u.Destructor(); //析构掉 return; } int i; //u临近的顶点 把临近顶点添加到tmpVertices队列里面 tmpVerticesList.Clear(); for (i = 0; i < u.currentNeightCount; i++) //u是一个顶点 { int nb = u.pneighbors.Get <int>(i); if (nb != u.ID) { tmpVerticesList.Add(nb); } } //Debug tempTriangleList.Clear(); for (i = 0; i < u.currentFaceCount; i++) { if (GetTriangles(u.pfaces.Get <int>(i)).HasVertex(v)) //获取到三角形 { tempTriangleList.Add(u.pfaces.Get <int>(i)); } } // Delete triangles on edge uv for (i = tempTriangleList.Length - 1; i >= 0; i--) { TriangleStruct t = GetTriangles(tempTriangleList[i]); //获取t的三个顶点信息 t.Destructor(ref m_VertexHeap, ref triangles, ref u, idToHeapIndex); triangles[tempTriangleList[i]] = t; } // Update remaining triangles to have v instead of u //缓存vNew VertexStruct vNewVertex = m_VertexHeap[idToHeapIndex[v]]; for (i = u.currentFaceCount - 1; i >= 0; i--) { TriangleStruct t = GetTriangles(u.pfaces.Get <int>(i)); t.ReplaceVertex(ref m_VertexHeap, u, ref vNewVertex, idToHeapIndex); triangles[u.pfaces.Get <int>(i)] = t; //更新 } //更新VNewIndex m_VertexHeap[idToHeapIndex[v]] = vNewVertex; u.Destructor(); // Recompute the edge collapse costs for neighboring vertices for (i = 0; i < tmpVerticesList.Length; i++) { VertexStruct st = m_VertexHeap[idToHeapIndex[tmpVerticesList[i]]]; ComputeEdgeCostAtVertex(ref st, aRelevanceSpheres); m_VertexHeap[idToHeapIndex[tmpVerticesList[i]]] = st; m_VertexHeap.ModifyValue(st.HeapIndex, st); } }
float ComputeEdgeCollapseCost(VertexStruct u, VertexStruct v, float fRelevanceBias) { bool bUseEdgeLength = UseEdgeLength; bool bUseCurvature = UseCurvature; float borderCurvature = fBorderCurvature; int i; float fEdgeLength = bUseEdgeLength ? (Vector3.Magnitude(v.Position - u.Position) / OriginalMeshSize) : 1.0f; float fCurvature = 0.001f; if (fEdgeLength < float.Epsilon) { return(borderCurvature * (1 - Vector3.Dot(u.Normal, v.Normal) + 2 * Vector3.Distance(u.UV, v.UV))); } else { List <TriangleStruct> sides = new List <TriangleStruct>(); for (i = 0; i < u.currentFaceCount; i++) { TriangleStruct ut = GetTriangles(u.pfaces.Get <int>(i)); if (HasVertex(ut, v.ID)) { sides.Add(ut); } } if (bUseCurvature) { for (i = 0; i < u.currentFaceCount; i++) { float fMinCurv = 1.0f; for (int j = 0; j < sides.Count; j++) { float dotprod = Vector3.Dot(GetTriangles(u.pfaces.Get <int>(i)).Normal, sides[j].Normal); fMinCurv = Mathf.Min(fMinCurv, (1.0f - dotprod) / 2.0f); } fCurvature = Mathf.Max(fCurvature, fMinCurv); } } bool isBorder = u.IsBorder(triangles); if (isBorder && sides.Count > 1) { fCurvature = 1.0f; } if (borderCurvature > 1 && isBorder) { fCurvature = borderCurvature; } } fCurvature += fRelevanceBias; return(fEdgeLength * fCurvature); }
public TriangleStruct GetTriangleStruct(uint address) { if (_triangleCache.ContainsKey(address)) { return(_triangleCache[address]); } TriangleStruct triStruct = new TriangleStruct(address); _triangleCache.Add(address, triStruct); return(triStruct); }
static int IndexOf(TriangleStruct t, int v) { for (int i = 0; i < 3; i++) { if (t.vertexs[i] == v) { return(i); } } return(-1); }
public static List <TriangleStruct> GetTrianglesInRange(uint startAddress, int numTriangles) { List <TriangleStruct> triangleList = new List <TriangleStruct>(); for (int i = 0; i < numTriangles; i++) { uint address = startAddress + (uint)(i * TriangleConfig.TriangleStructSize); TriangleStruct triangle = new TriangleStruct(address); triangleList.Add(triangle); } return(triangleList); }
public bool IsBorder(NativeArray <TriangleStruct> triangles) { int i, j; for (i = 0; i < currentNeightCount; i++) { int nCount = 0; for (j = 0; j < currentFaceCount; j++) { TriangleStruct st = triangles[pfaces.Get <int>(j)]; if (st.HasVertex(pneighbors.Get <int>(i))) { nCount++; } } if (nCount == 1) { return(true); } } return(false); }
public void SetTriangles(List <TriangleStruct> triangleList) { labelTitle.Text = "Triangles"; textBoxTriangleInfo.Text = TriangleStruct.GetFieldNameString() + "\n" + String.Join("\n", triangleList); }
void Start() { leftmesh = new Mesh(); rightmesh = new Mesh(); ArrayList leftpoints = new ArrayList(); ArrayList rightpoints = new ArrayList(); // Add middle rectangle middlepoints.Add(new Vector2(-1f, -4f)); middlepoints.Add(new Vector2(1f, -4f)); middlepoints.Add(new Vector2(-1f, 1.5f)); middlepoints.Add(new Vector2(1f, 1.5f)); // Create triangle that represents the middle Vector3[] toppoints = new Vector3[2]; toppoints [0] = new Vector2(-1f, 1.5f); toppoints [1] = new Vector2(1f, 1.5f); toptriangle = new TriangleStruct(new Vector3(0, -1, 0), toppoints [0], toppoints [1]); // Add a straight line where the mountain slope will be on each side leftpoints.Add(new Vector2(-5f, -4f)); leftpoints.Add(new Vector2(-1f, 1.5f)); rightpoints.Add(new Vector2(1f, 1.5f)); rightpoints.Add(new Vector2(5f, -4f)); // Subdivide mountain sides for (int i = 0; i < SUBDIVISIONS; i++) { // Left ArrayList templeftpoints = new ArrayList(); for (int j = 0; j < leftpoints.Count - 1; j++) { // get a midpoint and randomly scale by normal (based on line length) Vector2 leftfirstpoint = (Vector2)leftpoints [j]; Vector2 leftsecondpoint = (Vector2)leftpoints [j + 1]; Vector2 leftline = leftsecondpoint - leftfirstpoint; Vector2 leftnormal = new Vector2(-leftline.y, leftline.x); leftnormal = leftnormal.normalized; Vector2 leftmidpoint = Vector2.Scale(leftfirstpoint, new Vector2(0.5f, 0.5f)) + Vector2.Scale(leftsecondpoint, new Vector2(0.5f, 0.5f)); float leftnorm = leftline.magnitude; float leftbumpscale = leftnorm / 5; float leftbumpoffset = UnityEngine.Random.Range(-leftbumpscale * (0.8f), leftbumpscale); Vector2 newleftpoint = leftmidpoint + (Vector2.Scale(leftnormal, new Vector2(leftbumpoffset, leftbumpoffset))); templeftpoints.Add(leftfirstpoint); templeftpoints.Add(newleftpoint); templeftpoints.Add(leftsecondpoint); } leftpoints = templeftpoints; // Right side ArrayList temprightpoints = new ArrayList(); for (int j = 0; j < rightpoints.Count - 1; j++) { Vector2 rightfirstpoint = (Vector2)rightpoints [j]; Vector2 rightsecondpoint = (Vector2)rightpoints [j + 1]; Vector2 rightline = rightsecondpoint - rightfirstpoint; Vector2 rightnormal = new Vector2(-rightline.y, rightline.x); rightnormal = rightnormal.normalized; Vector2 rightmidpoint = Vector2.Scale(rightfirstpoint, new Vector2(0.5f, 0.5f)) + Vector2.Scale(rightsecondpoint, new Vector2(0.5f, 0.5f)); float rightnorm = rightline.magnitude; float rightbumpscale = rightnorm / 5; float rightbumpoffset = UnityEngine.Random.Range(-rightbumpscale * (0.8f), rightbumpscale); Vector2 newrightpoint = rightmidpoint + (Vector2.Scale(rightnormal, new Vector2(rightbumpoffset, rightbumpoffset))); temprightpoints.Add(rightfirstpoint); temprightpoints.Add(newrightpoint); temprightpoints.Add(rightsecondpoint); } rightpoints = temprightpoints; } // Create lists of triangles all with the same base poin. Triangles (b, 1, 2), (b, 2, 3), (b, 3, 4) etc... Vector2 leftbase = new Vector3(-1f, -4f, 0); Vector2 rightbase = new Vector3(1f, -4f, 0); Vector2[] templeft = Array.ConvertAll(leftpoints.ToArray(), new Converter <object, Vector2>(ObjToVector)); Vector2[] tempright = Array.ConvertAll(rightpoints.ToArray(), new Converter <object, Vector2>(ObjToVector)); // Converting to 3d points Vector3[] leftvertices = new Vector3[templeft.Length + 1]; leftvertices [0] = leftbase; for (int i = 0; i < templeft.Length; i++) { leftvertices[i + 1] = new Vector3(templeft[i].x, templeft[i].y, 0); } Vector3[] rightvertices = new Vector3[tempright.Length + 1]; rightvertices [0] = rightbase; for (int i = 0; i < tempright.Length; i++) { rightvertices[i + 1] = new Vector3(tempright[i].x, tempright[i].y, 0); } List <int> leftindexlist = new List <int>(); List <int> rightindexlist = new List <int>(); for (int i = 1; i <= templeft.Length - 1; i++) { leftindexlist.Add(0); leftindexlist.Add(i); leftindexlist.Add(i + 1); } for (int i = 1; i <= tempright.Length - 1; i++) { rightindexlist.Add(0); rightindexlist.Add(i); rightindexlist.Add(i + 1); } int[] leftindices = leftindexlist.ToArray(); int[] rightindices = rightindexlist.ToArray(); // Creating the meshes leftmesh.vertices = leftvertices; leftmesh.triangles = leftindices; leftmesh.RecalculateNormals(); leftmesh.RecalculateBounds(); rightmesh.vertices = rightvertices; rightmesh.triangles = rightindices; rightmesh.RecalculateNormals(); rightmesh.RecalculateBounds(); // Add Meshes to Gameobjects GameObject leftmountain = GameObject.Find("MountainLeft"); MeshFilter leftfilter = leftmountain.transform.GetComponent <MeshFilter> (); leftfilter.mesh = leftmesh; GameObject rightmountain = GameObject.Find("MountainRight"); MeshFilter rightfilter = rightmountain.transform.GetComponent <MeshFilter> (); rightfilter.mesh = rightmesh; GameObject middlemountain = GameObject.Find("MountainMiddle"); middlemountain.transform.position = new Vector3(0, -1.25f, 0); middlemountain.transform.localScale = new Vector3(2f, 5.5f, 1f); // Creating lists of Triangle Structures int[] lefttriindices = leftmesh.triangles; Vector3[] lefttrivertices = leftmesh.vertices; lefttriangles = new TriangleStruct[leftindices.Length / 3]; for (int i = 0; i < lefttriangles.Length; i++) { Vector3 leftbasepoint = leftvertices [leftindices [3 * i]]; Vector3 leftpointone = leftvertices [leftindices [3 * i + 1]]; Vector3 leftpointtwo = leftvertices [leftindices [3 * i + 2]]; TriangleStruct leftt = new TriangleStruct(leftbasepoint, leftpointone, leftpointtwo); lefttriangles [i] = leftt; } int[] righttriindices = rightmesh.triangles; Vector3[] righttrivertices = rightmesh.vertices; righttriangles = new TriangleStruct[rightindices.Length / 3]; for (int i = 0; i < righttriangles.Length; i++) { Vector3 rightbasepoint = rightvertices [rightindices [3 * i]]; Vector3 rightpointone = rightvertices [rightindices [3 * i + 1]]; Vector3 rightpointtwo = rightvertices [rightindices [3 * i + 2]]; TriangleStruct rightt = new TriangleStruct(rightbasepoint, rightpointone, rightpointtwo); righttriangles [i] = rightt; } }
public unsafe void Compute(List <Vertex> vertices, Mesh m_OriginalMesh, TriangleList[] triangleArray, RelevanceSphere[] aRelevanceSpheres, float[] costs, int[] collapses, int[] m_aVertexPermutation, int[] m_VertexHeap, bool bUseEdgeLength, bool bUseCurvature, float bBorderCurvature, float fOriginalMeshSize) { computerHeapJob = new ComputeHeapJob(); this.m_aVertexPermutation = m_aVertexPermutation; this.m_VertexHeap = m_VertexHeap; computerHeapJob.UseEdgeLength = bUseEdgeLength; computerHeapJob.UseCurvature = bUseCurvature; computerHeapJob.fBorderCurvature = bBorderCurvature; computerHeapJob.OriginalMeshSize = fOriginalMeshSize; computerHeapJob.m_aVertexPermutation = new NativeArray <int>(m_aVertexPermutation, Allocator.TempJob); computerHeapJob.m_aVertexMap = new NativeArray <int>(m_VertexHeap, Allocator.TempJob); computerHeapJob.idToHeapIndex = new NativeArray <int>(vertices.Count, Allocator.TempJob); computerHeapJob.tempTriangleList = new NativeList <int>(Allocator.TempJob); computerHeapJob.tmpVerticesList = new NativeList <int>(Allocator.TempJob); NativeHeap <VertexStruct> minNativeHeap = NativeHeap <VertexStruct> .CreateMinHeap(vertices.Count, Allocator.TempJob); int intSize = UnsafeUtility.SizeOf <int>(); int intAlignment = UnsafeUtility.AlignOf <int>(); //------------------------顶点数据--------------------------------- for (int i = 0; i < vertices.Count; i++) { Vertex v = vertices[i]; VertexStruct sv = new VertexStruct() { ID = v.m_nID, m_fObjDist = costs[i], Position = v.m_v3Position, collapse = collapses[i] == -1 ? -1 : vertices[collapses[i]].m_nID, isBorder = v.IsBorder() ? 1 : 0, Normal = v.Normal, UV = v.UV, }; sv.NewVertexNeighbors(v.m_listNeighbors.Count, intSize, intAlignment, Allocator.TempJob); sv.NewFaceTriangle(v.m_listFaces.Count, intSize, intAlignment, Allocator.TempJob); sv.idToHeapIndex = computerHeapJob.idToHeapIndex; for (int j = 0; j < v.m_listNeighbors.Count; j++) { sv.AddNeighborVertex(v.m_listNeighbors[j].m_nID); } for (int j = 0; j < v.m_listFaces.Count; j++) { sv.AddFaceTriangle(v.m_listFaces[j].Index); } minNativeHeap.Insert(sv); } //------------------------顶点数据结束----------------------------- //------------------------三角形数据------------------------------- List <TriangleStruct> structTrangle = new List <TriangleStruct>(); for (int n = 0; n < triangleArray.Length; n++) { List <Triangle> triangles = triangleArray[n].m_listTriangles; for (int i = 0; i < triangles.Count; i++) { Triangle t = triangles[i]; TriangleStruct st = new TriangleStruct() { Index = t.Index, Indices = (int *)UnsafeUtility.Malloc(t.Indices.Length * intAlignment, intAlignment, Allocator.TempJob), Normal = t.Normal, faceIndex = (int *)UnsafeUtility.Malloc(t.FaceIndex.Length * intSize, intAlignment, Allocator.TempJob), vertexs = t.Vertices.Length == 0 ? null : (int *)UnsafeUtility.Malloc(t.Vertices.Length * intSize, intAlignment, Allocator.TempJob), }; for (int j = 0; j < t.Indices.Length; j++) { st.Indices[j] = t.Indices[j]; } for (int j = 0; j < t.FaceIndex.Length; j++) { st.faceIndex[j] = t.FaceIndex[j]; } for (int j = 0; j < t.Vertices.Length; j++) { st.vertexs[j] = t.Vertices[j].m_nID; } structTrangle.Add(st); } } //------------------------三角形数据结束 computerHeapJob.Spheres = new NativeArray <StructRelevanceSphere>(aRelevanceSpheres.Length, Allocator.TempJob); for (int i = 0; i < aRelevanceSpheres.Length; i++) { RelevanceSphere rs = aRelevanceSpheres[i]; StructRelevanceSphere srs = new StructRelevanceSphere() { Transformation = Matrix4x4.TRS(rs.m_v3Position, rs.m_q4Rotation, rs.m_v3Scale), Relevance = rs.m_fRelevance, }; computerHeapJob.Spheres[i] = srs; } computerHeapJob.triangles = new NativeArray <TriangleStruct>(structTrangle.ToArray(), Allocator.TempJob); computerHeapJob.m_VertexHeap = minNativeHeap; handle = computerHeapJob.Schedule(); //Debug.Log(" computerHeapJob.m_VertexHeap.Length" + computerHeapJob.m_VertexHeap.Length); }
static bool HasVertex(TriangleStruct t, int v) { return(IndexOf(t, v) >= 0); //>=0 }
/// <summary> /// 析构方法 /// </summary> public void Destructor(ref NativeHeap <VertexStruct> vertexHeap, ref NativeArray <TriangleStruct> triangleArray, ref VertexStruct vold, NativeArray <int> idToHeapIndex) { //动态数组 int i; for (i = 0; i < 3; i++) { if (vertexs[i] != -1) { VertexStruct v; if (vertexs[i] == vold.ID) { v = vold; } else { v = vertexHeap[idToHeapIndex[vertexs[i]]]; } Pointer ptr = v.pfaces; int triangleIndices = ptr.Get <int>(v.currentFaceCount - 1); ptr.Set <int>(faceIndex[i], triangleIndices); TriangleStruct t = triangleArray[triangleIndices]; t.faceIndex[t.IndexOf(v.ID)] = faceIndex[i]; //修改完重新赋值 v.RemoveAtTriangele(v.currentFaceCount - 1); //直接修改里面的内容了 triangleArray[triangleIndices] = t; v.pfaces = ptr; if (vertexs[i] == vold.ID) { vold = v; } else { vertexHeap[idToHeapIndex[vertexs[i]]] = v; } } } for (i = 0; i < 3; i++) { int i2 = (i + 1) % 3; if (vertexs[i] == -1 || vertexs[i2] == -1) { continue; } VertexStruct v; VertexStruct v2; int indexI = -1; int indexI2 = -1; if (vertexs[i] == vold.ID) { v = vold; } else { indexI = 1; v = vertexHeap[idToHeapIndex[vertexs[i]]]; } if (vertexs[i2] == vold.ID) { v2 = vold; } else { indexI2 = 1; v2 = vertexHeap[idToHeapIndex[vertexs[i2]]]; } v.RemoveIfNonNeighbor(vertexs[i2], triangleArray); if (indexI != -1) { vertexHeap[idToHeapIndex[vertexs[i]]] = v; } else { vold = v; } v2.RemoveIfNonNeighbor(vertexs[i], triangleArray); if (indexI2 != -1) { vertexHeap[idToHeapIndex[vertexs[i2]]] = v2; } else { vold = v2; } } }
// Update is called once per frame void Update() { // ball is not moving if (velocity.x == 0 && velocity.y == 0) { sphere.transform.position = pos; // wait x seconds before deleting alivetime -= Time.deltaTime; if (alivetime < 0) { Destroy(gameObject); } return; } // Calculate a new position with velocity, airresistance, gravity, wind TriangleStruct[] lefttriangles = mountain.lefttriangles; TriangleStruct[] righttriangles = mountain.righttriangles; float gravity = props.GetGravity(); float airres = props.GetAirRes(); float windspeed = props.GetWindforce(); velocity = velocity + new Vector3(0, gravity, 0); if (velocity.x > 0) { velocity = velocity + new Vector3(-airres, 0, 0); } else { velocity = velocity + new Vector3(airres, 0, 0); } velocity = velocity + new Vector3(windspeed, 0, 0); Vector3 newpos = pos + velocity; // Collision Detection + Response // Check for goats Transform goats = goatspawner.transform; // Get each goat instance foreach (Transform goat in goats) { GoatPoints gp = (GoatPoints)goat.GetComponent("GoatPoints"); // surround each goat by a generous sphere bounding box and check that first float r = gp.radius; PointMass c = gp.center; if ((c.position - (new Vector2(pos.x, pos.y))).magnitude > r) { continue; } // Check each point in the goat for a collision ArrayList points = gp.points; for (int i = 0; i < points.Count; i++) { PointMass p = (PointMass)points [i]; if (HitGoat(p)) { // If there is a collision, delete this ball and unanchor the goat (giving it the ball's velocity) Vector2 velocity2d = new Vector2(velocity.x, velocity.y); gp.Unhinge(); p.GiveVelocity(velocity2d); Destroy(gameObject); } } } // bounding boxes for mountains if (pos.y - radius <= 2.0f) { // left if (pos.x + radius >= -5.0f && pos.x - radius <= -1.0f) { // left mountain triangles for (int i = 0; i < lefttriangles.Length; i++) { TriangleStruct lefttri = lefttriangles [i]; if (lefttri.left == lefttri.right) { continue; } // If there is a collision, change the velocity and recursively calulate a new position (up to 'counter' times) if (lefttri.SphereCollides(newpos, radius)) { ChangeVelocity(lefttri.getNormal()); trycounter++; Update(); return; } } } // right if (pos.x + radius >= 1.0f && pos.x - radius <= 5.0f) { // right mountain triangles for (int i = 0; i < righttriangles.Length; i++) { TriangleStruct righttri = righttriangles [i]; if (righttri.left == righttri.right) { continue; } if (righttri.SphereCollides(newpos, radius)) { ChangeVelocity(righttri.getNormal()); trycounter++; Update(); return; } } } // middle if (pos.x + radius >= -1.0f && pos.x - radius <= 1.0f) { // top of mountain TriangleStruct toptriangle = mountain.toptriangle; if (toptriangle.SphereCollides(newpos, radius)) { ChangeVelocity(toptriangle.getNormal()); trycounter++; Update(); return; } } } // Update Position pos = newpos; sphere.transform.position = pos; trycounter = 0; }
// called multiple times per frame public bool SolveConstraints() { // Stretch or pull all points from links for (int i = 0; i < links.Count; i++) { PointLink currlink = (PointLink)links [i]; currlink.Solve(); } // Skip most if point is anchored (cannot change) if (!anchored) { // Boundary Constraints, true return deletes the goat if (position.y < -4f) { return(true); } if (position.y > 11f) { return(true); } if (position.x > 11f) { return(true); } if (position.x < -11f) { return(true); } // Constraints to hit mountain CreateMountain mountain = (CreateMountain)gi.GetComponent("CreateMountain"); TriangleStruct[] left = mountain.lefttriangles; TriangleStruct[] right = mountain.righttriangles; TriangleStruct top = mountain.toptriangle; if (position.y <= 2.0f) { // left if (position.x >= -5.0f && position.x <= -1.0f) { for (int i = 0; i < left.Length; i++) { TriangleStruct lefttri = (TriangleStruct)left [i]; if (lefttri.PointInTriangle(position)) { position = lefttri.Relocate(position); if (isAnchor) { anchored = true; anchor = position; } } } } // right else if (position.x >= 1.0f && position.x <= 5.0f) { for (int i = 0; i < right.Length; i++) { TriangleStruct righttri = (TriangleStruct)right [i]; if (righttri.PointInTriangle(position)) { position = righttri.Relocate(position); if (isAnchor) { anchored = true; anchor = position; } } } } // middle else if (position.x >= -1.0f && position.x <= 1.0f) { if (top.PointInTriangle(position)) { position = top.Relocate(position); if (isAnchor) { anchored = true; anchor = position; } } } } } // pin to mountain if anchored by a foot if (anchored) { position = anchor; } return(false); }