📄 roamsphere.cpp
字号:
if(nOppositeVertex == 65535)
return false;
pTriangleVertex = CVertex::Array[nTriangleVertex];
pOppositeVertex = CVertex::Array[nOppositeVertex];
memcpy(pOppositeVertex, pTriangleVertex, sizeof(CVertex));
if(m_pSurfaceMap)
m_pSurfaceMap->GetTextureCoordinates(pOppositeVertex->m_vPosition, pOpposite->GetTriangleFace(), pOppositeVertex->m_fTexCoord[2], pOppositeVertex->m_fTexCoord[3]);
}
// Now create two new triangles for the split
static CROAMTriangle *pNewTriangle[2];
pNewTriangle[0] = new CROAMTriangle;
pNewTriangle[1] = new CROAMTriangle;
// Split the first one from pTriangle
pTriangle->SetPriorityWait(0);
pNewTriangle[0]->m_nFlags = pTriangle->m_nFlags;
pNewTriangle[0]->InsertAfter(pTriangle);
//m_llTriangle[pTriangle->GetTriangleFace()].AddTail(pNewTriangle[0]);
pNewTriangle[0]->SetVertices(pTriangle->m_nVertex[2], nTriangleVertex, pTriangle->m_nVertex[1]);
pTriangle->SetVertices(pTriangle->m_nVertex[1], nTriangleVertex, pTriangle->m_nVertex[0]);
pNewTriangle[0]->SetEdges(pOpposite, pTriangle, pTriangle->m_pEdge[1]);
pTriangle->m_pEdge[1]->ReplaceEdge(pTriangle, pNewTriangle[0]);
pTriangle->SetEdges(pNewTriangle[0], pNewTriangle[1], pTriangle->m_pEdge[0]);
if(pNewTriangle[0]->m_pEdge[2]->m_pEdge[2] == pNewTriangle[0])
pNewTriangle[0]->CopyPriorityInfo(pNewTriangle[0]->m_pEdge[2]);
else
UpdateTriangleOffset(pNewTriangle[0]);
if(pTriangle->m_pEdge[2]->m_pEdge[2] == pTriangle)
pTriangle->CopyPriorityInfo(pTriangle->m_pEdge[2]);
else
UpdateTriangleOffset(pTriangle);
// Split the second one from pOpposite
pOpposite->SetPriorityWait(0);
pNewTriangle[1]->m_nFlags = pOpposite->m_nFlags;
pNewTriangle[1]->InsertAfter(pOpposite);
//m_llTriangle[pOpposite->GetTriangleFace()].AddTail(pNewTriangle[1]);
pNewTriangle[1]->SetVertices(pOpposite->m_nVertex[2], nOppositeVertex, pOpposite->m_nVertex[1]);
pOpposite->SetVertices(pOpposite->m_nVertex[1], nOppositeVertex, pOpposite->m_nVertex[0]);
pNewTriangle[1]->SetEdges(pTriangle, pOpposite, pOpposite->m_pEdge[1]);
pOpposite->m_pEdge[1]->ReplaceEdge(pOpposite, pNewTriangle[1]);
pOpposite->SetEdges(pNewTriangle[1], pNewTriangle[0], pOpposite->m_pEdge[0]);
if(pNewTriangle[1]->m_pEdge[2]->m_pEdge[2] == pNewTriangle[1])
pNewTriangle[1]->CopyPriorityInfo(pNewTriangle[1]->m_pEdge[2]);
else
UpdateTriangleOffset(pNewTriangle[1]);
if(pOpposite->m_pEdge[2]->m_pEdge[2] == pOpposite)
pOpposite->CopyPriorityInfo(pOpposite->m_pEdge[2]);
else
UpdateTriangleOffset(pOpposite);
// Calculate the new vertex's normal vector
#define SPLIT_NORMAL // Updates the normal of all vertices affected by the split
#ifdef SPLIT_NORMAL
pTriangle->UpdateVertexNormals();
pOpposite->UpdateVertexNormals();
#else
pTriangleVertex->m_vNormal = pTriangle->GetNormal() + pOpposite->GetNormal() + pNewTriangle[0]->GetNormal() + pNewTriangle[1]->GetNormal();
CVertex::Array.UpdateElement(nTriangleVertex);
if(nTriangleVertex != nOppositeVertex)
{
pOppositeVertex->m_vNormal = pTriangleVertex->m_vNormal;
CVertex::Array.UpdateElement(nOppositeVertex);
}
#endif
// Set up parent pointers
pNewTriangle[0]->m_pParent = pTriangle;
pNewTriangle[1]->m_pParent = pOpposite;
// If either of the original triangles was part of a diamond, it has been destroyed.
if(pTriangle->m_pDiamond)
delete pTriangle->m_pDiamond;
if(pOpposite->m_pDiamond)
delete pOpposite->m_pDiamond;
// A new diamond must be created with the 4 new triangles.
m_llDiamond.AddTail(new CROAMDiamond(pTriangle, pOpposite, pNewTriangle[0], pNewTriangle[1]));
m_nTriangles += 2;
return true;
}
void CROAMSphere::Merge(CROAMDiamond *pDiamond)
{
// First, get the vertex all the triangles share and the parent triangles that the children will be merged into
unsigned short nVertex = pDiamond->m_pParent[0]->m_nVertex[1];
unsigned short nOpposite = pDiamond->m_pParent[1]->m_nVertex[1];
CVertex *pVertex = CVertex::Array[nVertex];
// Loop twice to merge two child triangles into their parents
for(int i=0; i<2; i++)
{
// Start by updating the parent's vertices and edges, then deleting the child
CROAMTriangle *pParent = pDiamond->m_pParent[i];
CROAMTriangle *pChild = pDiamond->m_pChild[i];
pParent->SetVertices(pParent->m_nVertex[2], pParent->m_nVertex[0], pChild->m_nVertex[0]);
pParent->SetEdges(pParent->m_pEdge[2], pChild->m_pEdge[2], pDiamond->m_pParent[1-i]);
pChild->m_pEdge[2]->ReplaceEdge(pChild, pParent);
delete pChild;
// Then update the priority information
if(i == 0)
{
CVector v = pParent->Vertex(0)->m_vPosition.Midpoint(pParent->Vertex(2)->m_vPosition);
pParent->m_vMidpoint = v;
float fHeight = (float)v.Magnitude();
pParent->m_fOffset = (float)pVertex->m_vPosition.Magnitude() - fHeight;
}
else
pParent->CopyPriorityInfo(pParent->m_pEdge[2]);
// Then see if the merged parent forms a new diamond
CROAMTriangle *p[4];
pParent->m_pDiamond = NULL;
p[0] = pParent;
p[1] = p[0]->m_pEdge[0];
p[2] = p[1]->m_pEdge[0];
p[3] = p[2]->m_pEdge[0];
if(p[3]->m_pEdge[0] == p[0])
{
// If it does, make sure parents and children match up
if(p[1]->m_pParent == p[0] && p[3]->m_pParent == p[2])
m_llDiamond.AddTail(new CROAMDiamond(p[0], p[2], p[1], p[3]));
if(p[2]->m_pParent == p[1] && p[0]->m_pParent == p[3])
m_llDiamond.AddTail(new CROAMDiamond(p[1], p[3], p[2], p[0]));
}
}
#define MERGE_NORMAL // Updates the normal of all vertices affected by the merge
#ifdef MERGE_NORMAL
pDiamond->m_pParent[0]->UpdateVertexNormals();
pDiamond->m_pParent[1]->UpdateVertexNormals();
#endif
pDiamond->m_pParent[0] = pDiamond->m_pParent[1] = NULL;
pDiamond->m_pChild[0] = pDiamond->m_pChild[1] = NULL;
delete pDiamond;
CVertex::Array.UnlockElement(nVertex);
if(nOpposite != nVertex)
CVertex::Array.UnlockElement(nOpposite);
m_nTriangles -= 2;
}
void CROAMSphere::Init(CHeightMap *pHeightMap, CSurfaceMap *pSurfaceMap)
{
// Build a fresh cube and set up the initial vertices/triangles
m_pHeightMap = pHeightMap;
m_pSurfaceMap = pSurfaceMap;
BuildCube();
int nFace, i;
for(nFace=0; nFace<6; nFace++)
{
for(CROAMTriangle *pTriangle=m_llTriangle[nFace].GetHead(); pTriangle->IsInList(); pTriangle = pTriangle->GetNext())
{
for(i=0; i<3; i++)
{
pTriangle->Vertex(i)->m_vPosition.Normalize();
float fHeight = m_pHeightMap->GetHeightNormalized(pTriangle->Vertex(i)->m_vPosition);
pTriangle->Vertex(i)->m_vPosition *= fHeight;
if(m_pSurfaceMap)
{
m_pSurfaceMap->GetRawTextureCoordinates(pTriangle->Vertex(i)->m_vPosition, fHeight, pTriangle->Vertex(i)->m_fTexCoord[0], pTriangle->Vertex(i)->m_fTexCoord[1]);
m_pSurfaceMap->GetTextureCoordinates(pTriangle->Vertex(i)->m_vPosition, nFace, pTriangle->Vertex(i)->m_fTexCoord[2], pTriangle->Vertex(i)->m_fTexCoord[3]);
}
}
UpdateTriangleOffset(pTriangle);
}
}
}
void CROAMSphere::Update(CVector vPosition, CVector vHeading, float fHorizon, float fMaxError)
{
m_fMaxError = fMaxError;
const float fHalfError = m_fMaxError * 0.5f;
const float fTwiceError = m_fMaxError * 2.0f;
float fPriority;
// Go through the list of diamonds, merging where necessary
CROAMDiamond *pDiamond, *pOld;
for(pDiamond=m_llDiamond.GetHead(); pDiamond->IsInList(); pDiamond = pDiamond->GetNext())
{
if(pDiamond->GetPriorityWait())
pDiamond->SetPriorityWait(pDiamond->GetPriorityWait()-1);
else
{
fPriority = pDiamond->GetPriority(vPosition, vHeading, fHorizon);
if(fPriority < m_fMaxError)
{
pOld = pDiamond;
pDiamond = pDiamond->GetPrevious();
Merge(pOld);
}
else
{
pDiamond->SetPriorityWait(fPriority >= fTwiceError ? 2 : 1);
}
}
}
// Go through the list of triangles, splitting where necessary
for(int nFace=0; nFace<6; nFace++)
{
for(CROAMTriangle *pTriangle=m_llTriangle[nFace].GetHead(); pTriangle->IsInList(); pTriangle = pTriangle->GetNext())
{
if(pTriangle->GetPriorityWait())
pTriangle->SetPriorityWait(pTriangle->GetPriorityWait()-1);
else
{
fPriority = pTriangle->GetPriority(vPosition, vHeading, fHorizon);
if(fPriority >= m_fMaxError)
Split(pTriangle);
else
{
pTriangle->SetPriorityWait(fPriority < DELTA ? 3 : fPriority < fHalfError ? 2 : 1);
}
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -