📄 mgcclodmesh.cpp
字号:
// Magic Software, Inc.
// http://www.magic-software.com
// Copyright (c) 2000, All Rights Reserved
//
// Source code from Magic Software is supplied under the terms of a license
// agreement and may not be copied or disclosed except in accordance with the
// terms of that agreement. The various license agreements may be found at
// the Magic Software web site. This file is subject to the license
//
// RESTRICTED USE SOURCE CODE
// http://www.magic-software.com/License/restricted.pdf
#include "MgcCLodMesh.h"
#include "MgcRenderer.h"
MgcImplementRTTI(MgcCLodMesh,MgcTriMesh);
MgcImplementStream(MgcCLodMesh);
//----------------------------------------------------------------------------
MgcCLodMesh::MgcCLodMesh (unsigned int uiVertexQuantity, MgcVector3* akVertex,
MgcVector3* akNormal, MgcColor* akColor, MgcVector2* akTexture,
unsigned int uiTriangleQuantity, unsigned int* auiConnect)
:
MgcTriMesh(uiVertexQuantity,akVertex,akNormal,akColor,akTexture,
uiTriangleQuantity,auiConnect)
{
m_fLastUpdateTime = -MgcMath::INFINITY;
m_uiInitialTriangleQuantity = m_uiTriangleQuantity;
m_iTargetRecord = -1;
ComputeRecords();
}
//----------------------------------------------------------------------------
MgcCLodMesh::MgcCLodMesh ()
{
m_fLastUpdateTime = -MgcMath::INFINITY;
m_uiInitialTriangleQuantity = 0;
m_iTargetRecord = -1;
m_iCurrentRecord = -1;
m_akRecord = 0;
}
//----------------------------------------------------------------------------
MgcCLodMesh::~MgcCLodMesh ()
{
delete[] m_akRecord;
}
//----------------------------------------------------------------------------
void MgcCLodMesh::SelectLevelOfDetail (MgcRenderer& rkRenderer)
{
MgcTriMesh::UpdateWorldData(m_fLastUpdateTime);
// Get target record. The virtual function may be overridden by a derived
// class to obtain a desired automated change in the target.
int iTargetRecord = GetAutomatedTargetRecord();
// collapse mesh (if necessary)
unsigned int uiV, uiI;
while ( m_iCurrentRecord < iTargetRecord )
{
m_iCurrentRecord++;
// replace indices in connectivity array
Record& rkRecord = m_akRecord[m_iCurrentRecord];
for (uiV = 0; uiV < rkRecord.m_uiVertexQuantity; uiV++)
{
uiI = rkRecord.m_auiIndex[uiV];
assert( m_auiConnect[uiI] == rkRecord.m_uiI1 );
m_auiConnect[uiI] = rkRecord.m_uiI0;
}
// TO DO. When ReorderVertices() is implemented, enable this.
// reduce vertex count (vertices are properly ordered)
//m_uiVertexQuantity -= rkRecord.m_uiVertexQuantity;
// reduce triangle count (triangles are properly ordered)
m_uiTriangleQuantity = rkRecord.m_uiTriangleQuantity;
}
// expand mesh (if necessary)
while ( m_iCurrentRecord > iTargetRecord )
{
// restore indices in connectivity array
Record& rkRecord = m_akRecord[m_iCurrentRecord];
for (uiV = 0; uiV < rkRecord.m_uiVertexQuantity; uiV++)
{
uiI = rkRecord.m_auiIndex[uiV];
assert( m_auiConnect[uiI] == rkRecord.m_uiI0 );
m_auiConnect[uiI] = rkRecord.m_uiI1;
}
m_iCurrentRecord--;
// TO DO. When ReorderVertices() is implemented, enable this.
// increase vertex count (vertices are properly ordered)
//m_uiVertexQuantity += rkRecord.m_uiVertexQuantity;
// increase triangle count (triangles are properly ordered)
if ( m_iCurrentRecord > -1 )
{
m_uiTriangleQuantity =
m_akRecord[m_iCurrentRecord].m_uiTriangleQuantity;
}
else
{
m_uiTriangleQuantity = m_uiInitialTriangleQuantity;
}
}
}
//----------------------------------------------------------------------------
void MgcCLodMesh::UpdateWorldData (MgcReal fAppTime)
{
// Save the update time. The update is deferred until Draw so that the
// CLOD mesh is selected only when it is visible. At this time the
// update time is needed to pass to the UpdateGS call.
m_fLastUpdateTime = fAppTime;
// The deferred update means that none of the children world data is
// computed by a recursive traversal. Just compute the world bound.
UpdateWorldBound();
}
//----------------------------------------------------------------------------
void MgcCLodMesh::Draw (MgcRenderer& rkRenderer)
{
SelectLevelOfDetail(rkRenderer);
MgcTriMesh::Draw(rkRenderer);
}
//----------------------------------------------------------------------------
MgcCLodMesh::Record::Record ()
{
m_uiI0 = 0;
m_uiI1 = 0;
m_uiTriangleQuantity = 0;
m_uiVertexQuantity = 0;
m_auiIndex = 0;
}
//----------------------------------------------------------------------------
MgcCLodMesh::Record::~Record ()
{
delete[] m_auiIndex;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// record calculations
//----------------------------------------------------------------------------
MgcCLodMesh::ErrorMatrix* MgcCLodMesh::ComputeVertexErrorMatrices ()
{
ErrorMatrix* akQ = new ErrorMatrix[m_uiVertexQuantity];
memset(akQ,0,m_uiVertexQuantity*sizeof(ErrorMatrix));
for (unsigned int uiT = 0; uiT < m_uiTriangleQuantity; uiT++)
{
unsigned int uiK = 3*uiT;
unsigned int uiI0 = m_auiConnect[uiK++];
unsigned int uiI1 = m_auiConnect[uiK++];
unsigned int uiI2 = m_auiConnect[uiK];
MgcVector3 kE0 = m_akVertex[uiI1] - m_akVertex[uiI0];
MgcVector3 kE1 = m_akVertex[uiI2] - m_akVertex[uiI0];
MgcVector3 kNormal = kE0.UnitCross(kE1);
MgcReal fConstant = kNormal.Dot(m_akVertex[uiI0]);
ErrorMatrix kError;
kError[0] = kNormal.x*kNormal.x;
kError[1] = kNormal.x*kNormal.y;
kError[2] = kNormal.x*kNormal.z;
kError[3] = kNormal.x*fConstant;
kError[4] = kNormal.y*kNormal.y;
kError[5] = kNormal.y*kNormal.z;
kError[6] = kNormal.y*fConstant;
kError[7] = kNormal.z*kNormal.z;
kError[8] = kNormal.z*fConstant;
kError[9] = fConstant*fConstant;
for (uiK = 0; uiK < 10; uiK++)
{
akQ[uiI0][uiK] += kError[uiK];
akQ[uiI1][uiK] += kError[uiK];
akQ[uiI2][uiK] += kError[uiK];
}
}
return akQ;
}
//----------------------------------------------------------------------------
MgcCLodMesh::HeapType* MgcCLodMesh::ComputeEdgeErrorMetrics (
ErrorMatrix* akQ)
{
HeapType* pkHeap = new HeapType(3*m_uiTriangleQuantity);
for (unsigned int uiT = 0; uiT < m_uiTriangleQuantity; uiT++)
{
unsigned int uiK = 3*uiT;
unsigned int uiI0 = m_auiConnect[uiK++];
unsigned int uiI1 = m_auiConnect[uiK++];
unsigned int uiI2 = m_auiConnect[uiK];
// edge <I0,I1>
ErrorMatrix kSum;
MgcReal fMetric;
KeyType kKey(uiI0,uiI1);
if ( !pkHeap->GetAt(kKey,fMetric) )
{
for (uiK = 0; uiK < 10; uiK++)
kSum[uiK] = akQ[uiI0][uiK] + akQ[uiI1][uiK];
MgcVector3& rkV = m_akVertex[kKey.m_uiI0];
fMetric =
rkV.x*(kSum[0]*rkV.x+kSum[1]*rkV.y+kSum[2]*rkV.z+kSum[3]) +
rkV.y*(kSum[1]*rkV.x+kSum[4]*rkV.y+kSum[5]*rkV.z+kSum[6]) +
rkV.z*(kSum[2]*rkV.x+kSum[5]*rkV.y+kSum[7]*rkV.z+kSum[8]) +
(kSum[3]*rkV.x+kSum[6]*rkV.y+kSum[8]*rkV.z+kSum[9]);
pkHeap->SetAt(kKey,fMetric);
}
// edge <I0,I2>
kKey = KeyType(uiI0,uiI2);
if ( !pkHeap->GetAt(kKey,fMetric) )
{
for (uiK = 0; uiK < 10; uiK++)
kSum[uiK] = akQ[uiI0][uiK] + akQ[uiI2][uiK];
MgcVector3& rkV = m_akVertex[kKey.m_uiI0];
fMetric =
rkV.x*(kSum[0]*rkV.x+kSum[1]*rkV.y+kSum[2]*rkV.z+kSum[3]) +
rkV.y*(kSum[1]*rkV.x+kSum[4]*rkV.y+kSum[5]*rkV.z+kSum[6]) +
rkV.z*(kSum[2]*rkV.x+kSum[5]*rkV.y+kSum[7]*rkV.z+kSum[8]) +
(kSum[3]*rkV.x+kSum[6]*rkV.y+kSum[8]*rkV.z+kSum[9]);
pkHeap->SetAt(kKey,fMetric);
}
// edge <I1,I2>
kKey = KeyType(uiI1,uiI2);
if ( !pkHeap->GetAt(kKey,fMetric) )
{
for (uiK = 0; uiK < 10; uiK++)
kSum[uiK] = akQ[uiI1][uiK] + akQ[uiI2][uiK];
MgcVector3& rkV = m_akVertex[kKey.m_uiI0];
fMetric =
rkV.x*(kSum[0]*rkV.x+kSum[1]*rkV.y+kSum[2]*rkV.z+kSum[3]) +
rkV.y*(kSum[1]*rkV.x+kSum[4]*rkV.y+kSum[5]*rkV.z+kSum[6]) +
rkV.z*(kSum[2]*rkV.x+kSum[5]*rkV.y+kSum[7]*rkV.z+kSum[8]) +
(kSum[3]*rkV.x+kSum[6]*rkV.y+kSum[8]*rkV.z+kSum[9]);
pkHeap->SetAt(kKey,fMetric);
}
}
return pkHeap;
}
//----------------------------------------------------------------------------
bool MgcCLodMesh::TriangleContainsEdge (unsigned int uiT, unsigned int uiI0,
unsigned int uiI1)
{
unsigned int uiK = 3*uiT;
unsigned int uiJ0 = m_auiConnect[uiK++];
unsigned int uiJ1 = m_auiConnect[uiK++];
unsigned int uiJ2 = m_auiConnect[uiK];
return ((uiJ0 == uiI0 && uiJ1 == uiI1) || (uiJ0 == uiI1 && uiJ1 == uiI0))
|| ((uiJ0 == uiI0 && uiJ2 == uiI1) || (uiJ0 == uiI1 && uiJ2 == uiI0))
|| ((uiJ1 == uiI0 && uiJ2 == uiI1) || (uiJ1 == uiI1 && uiJ2 == uiI0));
}
//----------------------------------------------------------------------------
void MgcCLodMesh::MoveTrianglesToEnd ()
{
Record& rkRecord = m_akRecord[m_iCurrentRecord];
unsigned int uiQuantity;
if ( m_iCurrentRecord > 0 )
uiQuantity = m_akRecord[m_iCurrentRecord-1].m_uiTriangleQuantity;
else
uiQuantity = m_uiTriangleQuantity;
// Repack connectivity into two subsets, the first corresponding to those
// triangles not containing the removed edge and the second corresponding
// to those triangles containing the removed edge.
unsigned int* auiIndex = new unsigned int[3*uiQuantity];
unsigned int uiI;
for (uiI = 0; uiI < 3*uiQuantity; uiI++)
auiIndex[uiI] = uiI;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -