예제 #1
0
		public void BuildContours (float maxError, int maxEdgeLength, VoxelContourSet cset, int buildFlags) {
			
			AstarProfiler.StartProfile ("Build Contours");
			
			AstarProfiler.StartProfile ("- Init");
			int w = voxelArea.width;
			int d = voxelArea.depth;
			
			int wd = w*d;
			
			//cset.bounds = voxelArea.bounds;
			
			int maxContours = Mathf.Max (8/*Max Regions*/,8);
			
			
			//cset.conts = new VoxelContour[maxContours];
			List<VoxelContour> contours = new List<VoxelContour>(maxContours);
			
			AstarProfiler.EndProfile ("- Init");
			AstarProfiler.StartProfile ("- Mark Boundaries");
			
			//cset.nconts = 0;
			
			//NOTE: This array may contain any data, but since we explicitly set all data in it before we use it, it's OK.
			ushort[] flags = voxelArea.tmpUShortArr;
			if (flags.Length < voxelArea.compactSpanCount) {
				flags = voxelArea.tmpUShortArr = new ushort[voxelArea.compactSpanCount];
			}
			
			// Mark boundaries. (@?)
			for (int z=0;z < wd;z += voxelArea.width) {
				for (int x=0;x < voxelArea.width;x++) {
					
					CompactVoxelCell c = voxelArea.compactCells[x+z];
					
					for (int i= (int)c.index, ci = (int)(c.index+c.count); i < ci; i++) {
						
						ushort res = 0;
						CompactVoxelSpan s = voxelArea.compactSpans[i];
						
						if (s.reg == 0 || (s.reg & BorderReg) == BorderReg) {
							flags[i] = 0;
							continue;
						}
						
						for (int dir=0;dir < 4; dir++) {
							int r = 0;
							
							if (s.GetConnection (dir) != NotConnected) {
								int nx = x + voxelArea.DirectionX[dir];
								int nz = z + voxelArea.DirectionZ[dir];
								
								int ni = (int)voxelArea.compactCells[nx+nz].index + s.GetConnection (dir);
								r = voxelArea.compactSpans[ni].reg;
								
								
							}
							
							//@TODO - Why isn't this inside the previous IF
							if (r == s.reg) {
								res |= (ushort)(1 << dir);
								
							}
						}
						
						//Inverse, mark non connected edges.
						flags[i] = (ushort)(res ^ 0xf);
							
					}
					
				}
			}
			
			AstarProfiler.EndProfile ("- Mark Boundaries");
			
			AstarProfiler.StartProfile ("- Simplify Contours");
			List<int> verts = ListPool<int>.Claim(256);//new List<int> (256);
			List<int> simplified = ListPool<int>.Claim(64);//new List<int> (64);
			
			for (int z=0;z < wd;z += voxelArea.width) {
				for (int x=0;x < voxelArea.width;x++) {
					
					CompactVoxelCell c = voxelArea.compactCells[x+z];
					
					for (int i= (int)c.index, ci = (int)(c.index+c.count); i < ci; i++) {
						
						//CompactVoxelSpan s = voxelArea.compactSpans[i];
						
						if (flags[i] == 0 || flags[i] == 0xf)
						{
							flags[i] = 0;
							continue;
						}
						
						int reg = voxelArea.compactSpans[i].reg;
						
						if (reg == 0 || (reg & BorderReg) == BorderReg) {
							continue;
						}
						
						int area = voxelArea.areaTypes[i];
						
						verts.Clear ();
						simplified.Clear ();
						
						WalkContour(x, z, i, flags, verts);
						
						SimplifyContour(verts, simplified, maxError, maxEdgeLength, buildFlags);
						RemoveDegenerateSegments (simplified);
						
						VoxelContour contour = new VoxelContour ();
						contour.verts = ClaimIntArr(simplified.Count,false);//simplified.ToArray ();
						for (int j=0;j<simplified.Count;j++) contour.verts[j] = simplified[j];
#if ASTAR_RECAST_INCLUDE_RAW_VERTEX_CONTOUR
						//Not used at the moment, just debug stuff
						contour.rverts = ClaimIntArr(verts.Count);
						for (int j=0;j<verts.Count;j++) contour.rverts[j] = verts[j];
#endif
						contour.nverts = simplified.Count/4;
						contour.reg = reg;
						contour.area = area;
						
						contours.Add (contour);
						
						#if ASTARDEBUG
						for (int q=0, j = (simplified.Count/4)-1;q<(simplified.Count/4);j=q, q++) {
				
							int i4 = q*4;
							int j4 = j*4;
							
							Vector3 p1 = Vector3.Scale (
							new Vector3 (
								simplified[i4+0],
								simplified[i4+1],
								(simplified[i4+2]/(float)voxelArea.width)
							),
							cellScale)
							+voxelOffset;
							
							Vector3 p2 = Vector3.Scale (
							new Vector3 (
								simplified[j4+0],
								simplified[j4+1],
								(simplified[j4+2]/(float)voxelArea.width)
							)
							,cellScale)
							+voxelOffset;
							
							
							if (CalcAreaOfPolygon2D(contour.verts, contour.nverts) > 0) {
								Debug.DrawLine (p1,p2,AstarMath.IntToColor (reg,0.5F));
							} else {
								Debug.DrawLine (p1,p2,Color.red);
								
							}
							
						}
						#endif
					}
				}
			}
			
			ListPool<int>.Release(verts);
			ListPool<int>.Release(simplified);
			
			AstarProfiler.EndProfile ("- Simplify Contours");
			
			AstarProfiler.StartProfile ("- Fix Contours");
			
			// Check and merge droppings.
			// Sometimes the previous algorithms can fail and create several contours
			// per area. This pass will try to merge the holes into the main region.
			for (int i = 0; i < contours.Count; i++)
			{
				VoxelContour cont = contours[i];
				// Check if the contour is would backwards.
				if (CalcAreaOfPolygon2D(cont.verts, cont.nverts) < 0)
				{
					// Find another contour which has the same region ID.
					int mergeIdx = -1;
					for (int j = 0; j < contours.Count; j++)
					{
						if (i == j) continue;
						if (contours[j].nverts > 0 && contours[j].reg == cont.reg)
						{
							// Make sure the polygon is correctly oriented.
							if (CalcAreaOfPolygon2D(contours[j].verts, contours[j].nverts) > 0)
							{
								mergeIdx = j;
								break;
							}
						}
					}
					if (mergeIdx == -1)
					{
						Debug.LogError ("rcBuildContours: Could not find merge target for bad contour "+i+".");
					}
					else
					{
						// Debugging
						//Debug.LogWarning ("Fixing contour");

						VoxelContour mcont = contours[mergeIdx];
						// Merge by closest points.
						int ia = 0, ib = 0;
						GetClosestIndices(mcont.verts, mcont.nverts, cont.verts, cont.nverts, ref ia, ref ib);
						
						if (ia == -1 || ib == -1)
						{
							Debug.LogWarning ("rcBuildContours: Failed to find merge points for "+i+" and "+mergeIdx+".");
							continue;
						}
						
#if ASTARDEBUG
						int p4 = ia*4;
						int p42 = ib*4;
							
						Vector3 p12 = Vector3.Scale (
							new Vector3 (
								mcont.verts[p4+0],
								mcont.verts[p4+1],
								(mcont.verts[p4+2]/(float)voxelArea.width)
							),
							cellScale)
							+voxelOffset;
							
							Vector3 p22 = Vector3.Scale (
							new Vector3 (
								cont.verts[p42+0],
								cont.verts[p42+1],
								(cont.verts[p42+2]/(float)voxelArea.width)
							)
							,cellScale)
							+voxelOffset;
						
						Debug.DrawLine (p12,p22,Color.green);
#endif
						
						if (!MergeContours(ref mcont, ref cont, ia, ib))
						{
							Debug.LogWarning ("rcBuildContours: Failed to merge contours "+i+" and "+mergeIdx+".");
							continue;
						}
						
						contours[mergeIdx] = mcont;
						contours[i] = cont;
						
						#if ASTARDEBUG
						Debug.Log (mcont.nverts);
						
						for (int q=0, j = (mcont.nverts)-1;q<(mcont.nverts);j=q, q++) {
							int i4 = q*4;
							int j4 = j*4;
							
							Vector3 p1 = Vector3.Scale (
							new Vector3 (
								mcont.verts[i4+0],
								mcont.verts[i4+1],
								(mcont.verts[i4+2]/(float)voxelArea.width)
							),
							cellScale)
							+voxelOffset;
							
							Vector3 p2 = Vector3.Scale (
							new Vector3 (
								mcont.verts[j4+0],
								mcont.verts[j4+1],
								(mcont.verts[j4+2]/(float)voxelArea.width)
							)
							,cellScale)
							+voxelOffset;
							
							Debug.DrawLine (p1,p2,Color.red);
						//}
						}
						#endif
					}
				}
			}
		
			cset.conts = contours;
			
			AstarProfiler.EndProfile ("- Fix Contours");
			
			AstarProfiler.EndProfile ("Build Contours");
		}
예제 #2
0
		public static bool MergeContours(ref VoxelContour ca, ref VoxelContour cb, int ia, int ib) {
			
			int maxVerts = ca.nverts + cb.nverts + 2;
			
			int[] verts = ClaimIntArr(maxVerts*4,false);//new int[maxVerts*4];
			
			//if (!verts)
			//	return false;
		
			int nv = 0;
		
			// Copy contour A.
			for (int i = 0; i <= ca.nverts; i++)
			{
				int dst = nv*4;
				int src = ((ia+i) % ca.nverts)*4;
				verts[dst+0] = ca.verts[src+0];
				verts[dst+1] = ca.verts[src+1];
				verts[dst+2] = ca.verts[src+2];
				verts[dst+3] = ca.verts[src+3];
				nv++;
			}
		
			// Copy contour B
			for (int i = 0; i <= cb.nverts; i++)
			{
				int dst = nv*4;
				int src = ((ib+i) % cb.nverts)*4;
				verts[dst+0] = cb.verts[src+0];
				verts[dst+1] = cb.verts[src+1];
				verts[dst+2] = cb.verts[src+2];
				verts[dst+3] = cb.verts[src+3];
				nv++;
			}
			
			//rcFree(ca.verts);
			//rcFree(cb.verts);
			ReleaseIntArr(ca.verts);
			ReleaseIntArr(cb.verts);
			
			ca.verts = verts;
			ca.nverts = nv;
			
			cb.verts = emptyArr;
			cb.nverts = 0;
			
			return true;
		}