# Creating Procedural Planets In Unity — Part 2 A semi-arid world, created by extruding polygons to create oceans and multiple layers of hills.
`public class Polygon{  public List<int>     m_Vertices;  public List<Polygon> m_Neighbors;  public Color32       m_Color;  public bool          m_SmoothNormals;  public Polygon(int a, int b, int c)  {    m_Vertices      = new List<int>() { a, b, c };    m_Neighbors     = new List<Polygon>();    // This will determine whether a polygon's normals smoothly    // blend into its neighbors, or if it should have sharp edges.    m_SmoothNormals = true;    // Hot Pink is an excellent default color because you'll     // notice instantly if you forget to set it to something else.    m_Color = new Color32(255, 0, 255, 255);  }  public bool IsNeighborOf(Polygon other_poly)  {    int shared_vertices = 0;    foreach (int vertex in m_Vertices)    {      if (other_poly.m_Vertices.Contains(vertex))        shared_vertices++;    }    // A polygon and its neighbor will share exactly    // two vertices. Ergo, if this poly shares two    // vertices with the other, then they are neighbors.    return shared_vertices == 2;  }  // Mr. Roger's voice: Please won't you replace my neighbor.  public void ReplaceNeighbor(Polygon oldNeighbor,                               Polygon newNeighbor)  {    for(int i = 0; i < m_Neighbors.Count; i++)    {      if(oldNeighbor == m_Neighbors[i])      {        m_Neighbors[i] = newNeighbor;        return;      }    }  }}`
`public class Planet{    ...    public void CalculateNeighbors()    {         foreach (Polygon poly in m_Polygons)         {              foreach (Polygon other_poly in m_Polygons)             {                  if (poly == other_poly)                     continue;                  if (poly.IsNeighborOf (other_poly))                     poly.m_Neighbors.Add(other_poly);             }         }    }}`
`public class Edge{  // The Poly that's inside the Edge. This is the one   // we'll be extruding or insetting.  public Polygon m_InnerPoly;   // The Poly that's outside the Edge. We'll be leaving   // this one alone.  public Polygon m_OuterPoly;  //The vertices along this edge, according to the Outer poly.  public List<int> m_OuterVerts;  //The vertices along this edge, according to the Inner poly.  public List<int> m_InnerVerts;  public Edge(Polygon inner_poly, Polygon outer_poly)  {    m_InnerPoly  = inner_poly;    m_OuterPoly  = outer_poly;    m_OuterVerts = new List<int>(2);    m_InnerVerts = new List<int>(2);    //Find which vertices these polys share.    foreach (int vertex in inner_poly.m_Vertices)    {      if (outer_poly.m_Vertices.Contains(vertex))        m_InnerVerts.Add(vertex);    }    // For consistency, we want the 'winding order' of the     // edge to be the same as that of the inner polygon.    // So the vertices in the edge are stored in the same order    // that you would encounter them if you were walking clockwise    // around the polygon. That means the pair of edge vertices     // will be:    // [1st inner poly vertex, 2nd inner poly vertex] or    // [2nd inner poly vertex, 3rd inner poly vertex] or    // [3rd inner poly vertex, 1st inner poly vertex]    //    // The formula above will give us [1st inner poly vertex,     // 3rd inner poly vertex] though, so we check for that     // situation and reverse the vertices.    if(m_InnerVerts == inner_poly.m_Vertices &&       m_InnerVerts == inner_poly.m_Vertices)    {      int temp = m_InnerVerts;      m_InnerVerts = m_InnerVerts;      m_InnerVerts = temp;    }    // No manipulations have happened yet, so the outer and     // inner Polygons still share the same vertices.    // We can instantiate m_OuterVerts as a copy of m_InnerVerts.    m_OuterVerts = new List<int>(m_InnerVerts);  }}`
`public class EdgeSet : HashSet<Edge>{  // Split - Given a list of original vertex indices and a list of  // replacements, update m_InnerVerts to use the new replacement  // vertices.  public void Split(List<int> oldVertices, List<int> newVertices)  {    foreach(Edge edge in this)    {      for(int i = 0; i < 2; i++)      {        edge.m_InnerVerts[i] = newVertices[ oldVertices.IndexOf(                               edge.m_OuterVerts[i])];      }    }  }  // GetUniqueVertices - Get a list of all the vertices referenced  // in this edge loop, with no duplicates.  public List<int> GetUniqueVertices()  {    List<int> vertices = new List<int>();    foreach (Edge edge in this)    {      foreach (int vert in edge.m_OuterVerts)      {        if (!vertices.Contains(vert))          vertices.Add(vert);      }    }    return vertices;  }}`
`public class PolySet : HashSet<Polygon>{  //Given a set of Polys, calculate the set of Edges  //that surround them.  public EdgeSet CreateEdgeSet()  {    EdgeSet edgeSet = new EdgeSet();    foreach (Polygon poly in this)    {      foreach (Polygon neighbor in poly.m_Neighbors)      {        if (this.Contains(neighbor))          continue;                // If our neighbor isn't in our PolySet, then        // the edge between us and our neighbor is one        // of the edges of this PolySet.        Edge edge = new Edge(poly, neighbor);        edgeSet.Add(edge);      }    }    return edgeSet;  }  // GetUniqueVertices calculates a list of the vertex indices   // used by these Polygons with no duplicates.  public List<int> GetUniqueVertices()  {    List<int> verts = new List<int>();    foreach (Polygon poly in this)    {      foreach (int vert in poly.m_Vertices)      {        if (!verts.Contains(vert))          verts.Add(vert);      }    }    return verts;  }}`
`public class Planet{    ....    public List<int> CloneVertices(List<int> old_verts)    {        List<int> new_verts = new List<int>();        foreach(int old_vert in old_verts)         {            Vector3 cloned_vert = m_Vertices [old_vert];            new_verts.Add(m_Vertices.Count);            m_Vertices.Add(cloned_vert);        }        return new_verts;    }}`
`public class Planet{    ....    public PolySet StitchPolys(PolySet polys)    {      PolySet stichedPolys = new PolySet();      var edgeSet       = polys.CreateEdgeSet();      var originalVerts = edgeSet.GetUniqueVertices();      var newVerts      = CloneVertices(originalVerts);      edgeSet.Split(originalVerts, newVerts);      foreach (Edge edge in edgeSet)      {        // Create new polys along the stitched edge. These        // will connect the original poly to its former        // neighbor.        var stitch_poly1 = new Polygon(edge.m_OuterVerts,                                       edge.m_OuterVerts,                                       edge.m_InnerVerts);        var stitch_poly2 = new Polygon(edge.m_OuterVerts,                                       edge.m_InnerVerts,                                       edge.m_InnerVerts);        // Add the new stitched faces as neighbors to        // the original Polys.        edge.m_InnerPoly.ReplaceNeighbor(edge.m_OuterPoly,                                         stitch_poly2);        edge.m_OuterPoly.ReplaceNeighbor(edge.m_InnerPoly,                                         stitch_poly1);        m_Polygons.Add(stitch_poly1);        m_Polygons.Add(stitch_poly2);        stichedPolys.Add(stitch_poly1);        stichedPolys.Add(stitch_poly2);      }      //Swap to the new vertices on the inner polys.      foreach (Polygon poly in polys)      {        for (int i = 0; i < 3; i++)        {          int vert_id = poly.m_Vertices[i];          if (!originalVerts.Contains(vert_id))            continue;                    int vert_index = originalVerts.IndexOf(vert_id);          poly.m_Vertices[i] = newVerts[vert_index];        }      }    return stichedPolys;  }}`
`public class Planet{    ....  public PolySet Extrude(PolySet polys, float height)  {    PolySet stitchedPolys = StitchPolys(polys);    List<int> verts = polys.GetUniqueVertices();    // Take each vertex in this list of polys, and push it    // away from the center of the Planet by the height    // parameter.    foreach (int vert in verts)    {      Vector3 v = m_Vertices[vert];      v = v.normalized * (v.magnitude + height);      m_Vertices[vert] = v;    }    return stitchedPolys;  }}`
`public class Planet{    ....  public PolySet Inset(PolySet polys, float interpolation)  {    PolySet stitchedPolys = StitchPolys(polys);    List<int> verts = polys.GetUniqueVertices();    //Calculate the average center of all the vertices    //in these Polygons.    Vector3 center = Vector3.zero;    foreach (int vert in verts)      center += m_Vertices[vert];    center /= verts.Count;    // Pull each vertex towards the center, then correct    // it's height so that it's as far from the center of    // the planet as it was before.    foreach (int vert in verts)    {      Vector3 v = m_Vertices[vert];      float height = v.magnitude;      v = Vector3.Lerp(v, center, interpolation);      v = v.normalized * height;      m_Vertices[vert] = v;    }    return stitchedPolys;  }}`
`public class Planet{  ....     public PolySet GetPolysInSphere(Vector3 center,                                   float radius,                                   IEnumerable<Polygon> source)  {    PolySet newSet = new PolySet();    foreach(Polygon p in source)    {      foreach(int vertexIndex in p.m_Vertices)      {        float distanceToSphere = Vector3.Distance(center,                                 m_Vertices[vertexIndex]);         if (distanceToSphere <= radius)        {          newSet.Add(p);          break;        }      }    }    return newSet;  }}`

--

--