Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
109 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

Don't fill gaps, don't have gaps!

We only perform the displacement if our neighbour has children. Additionally, we tell the neighboring children that share this point, they can now be displaced, as it's guaranteed they haven't been if we're not split yet. Worth noting is the above code becomes one very simple line once you index your mesh, as you don't need to use the magic-relationship to seek out the point on each triangle, you just need to find it for one.

for(int i=0; i<3; i++)
{
  //here, even if were not raising the point to the radius+detail,
  //prepare the texturing, colouring etc as if we were
  //...
  if(t->e[i]->bHasChildren())
  {
    n[i].vNormalize(); n[i] *= radius;
    //and tell neighboring children sharing point they can raise from midpoint
    int it0=t->e[i]->iSharesEdge(t);
    int it1=it0+1; if(it1>2)it1=0;
    int it3=it1+1; if(it3>2)it3=0;
    t->e[i]->child[it0]->p[it1]=n[i];
    t->e[i]->child[it1]->p[it0]=n[i];
    t->e[i]->child[3]->p[it3]=n[i];
  }
}

Now we can construct our children and set up our child, parent pointers.

t->child[0] = new cLoDTri(t->p[0],n[0],n[2]);
t->child[1] = new cLoDTri(n[0],t->p[1],n[1]);
t->child[2] = new cLoDTri(n[2],n[1],t->p[2]);
t->child[3] = new cLoDTri(n[1],n[2],n[0]);

for(int i=0;i<4;i++)
  t->child[i]->pParent=t;

t->child[0]->e[1]=t->child[3];
t->child[1]->e[2]=t->child[3];
t->child[2]->e[0]=t->child[3];

"Neighbour's... Everybody needs good..."

We can also set up child[3]'s edge pointers as it simply points to the other children.

t->child[3]->SetEdgePointers(t->child[2],t->child[0],t->child[1]);

Setting up the other children's edge pointers is slightly less trivial because of the variable orientations of neighboring tris. Rather than use a big switch() setup dealing with the neighbor orientations on a case by case business though, the math-magical relationship saves us again and makes it trivial (and plenty fast enough for a split operation).

for(int i=0; i<3; i++)
{
  if(t->e[i]) //non-closed surface trap
  if(t->e[i]->bHasChildren())
  {
    //triangle has children we can point our children too.
    int j=i+1; if(j>2) j=0;
    int sharedEdge=t->e[i]->iSharesEdge(t);
    if(sharedEdge!=-1)
    {
      int k=sharedEdge+1; if(k>2)k=0;
      t->child[i]->e[i]=t->e[i]->child[k];
      t->child[j]->e[i]=t->e[i]->child[sharedEdge];
      t->e[i]->child[sharedEdge]->e[sharedEdge]=t->child[j];
      t->e[i]->child[k]->e[sharedEdge]=t->child[i];
    }
  }
}

the function iSharesEdge is simply defined as:

int cLoDTri::iSharesEdge(cLoDTri* t)
{
  for(int i=0;i<3;i++)
    if(e[i]==t) return i;
  return -1;
}

This is fairly intuitive if you stare at the diagram for a little while. All thats left is to put the children into the mesh, and take the parent out.

m_llMesh.AddHead(t->child[0]);
m_llMesh.AddHead(t->child[1]);
m_llMesh.AddHead(t->child[2]);
m_llMesh.AddHead(t->child[3]);

t->Remove();
m_llParents.AddHead(t);




The Big Picture

Contents
  Data Structure
  A Math-Magic Relationship
  Don't fill gaps...
  The Big Picture

  Printable version
  Discuss this article

The Series
  Structure