⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wmlboundingvolumetree.cpp

📁 3D Game Engine Design Source Code非常棒
💻 CPP
字号:
// Magic Software, Inc.
// http://www.magic-software.com
// http://www.wild-magic.com
// Copyright (c) 2003.  All Rights Reserved
//
// The Wild Magic Library (WML) source code is supplied under the terms of
// the license agreement http://www.magic-software.com/License/WildMagic.pdf
// and may not be copied or disclosed except in accordance with the terms of
// that agreement.

// #define _DEBUG_TEST

#include "WmlBoundingVolumeTree.h"
using namespace Wml;

//----------------------------------------------------------------------------
BoundingVolumeTree::BoundingVolumeTree (BoundingVolume::Type eType,
    int iVertexCount, const Vector3f* akVertex, int iTriangleCount,
    const int* aiConnect, int iMaxTrisPerLeaf, bool bStoreInteriorTris)
{
    assert( eType != BoundingVolume::BV_QUANTITY );
    m_pkWorldBound = NULL;

    // Centroids of triangles are used for splitting a mesh.  The centroids
    // are projected onto a splitting axis and sorted.  The split is based
    // on the median of the projections.
    Vector3f* akCentroid = new Vector3f[iTriangleCount];
    const float fOneThird = 1.0f/3.0f;
    int i = 0, iT;
    for (iT = 0; iT < iTriangleCount; iT++)
    {
        int i0 = aiConnect[i++];
        int i1 = aiConnect[i++];
        int i2 = aiConnect[i++];
        akCentroid[iT] = fOneThird*(akVertex[i0]+akVertex[i1]+akVertex[i2]);
    }

    // Initialize binary-tree arrays for storing triangle indices.  These
    // are used to store the indices when the mesh is split.
    int* aiISplit = new int[iTriangleCount];
    int* aiOSplit = new int[iTriangleCount];
    for (iT = 0; iT < iTriangleCount; iT++)
        aiISplit[iT] = iT;

    CreateTree(eType,iVertexCount,akVertex,iTriangleCount,aiConnect,
        iMaxTrisPerLeaf,bStoreInteriorTris,akCentroid,0,iTriangleCount-1,
        aiISplit,aiOSplit);

    delete[] akCentroid;
    delete[] aiISplit;
    delete[] aiOSplit;

#ifdef _DEBUG_TEST
    if ( bStoreInteriorTris )
    {
        float fEpsilon = 1e-05f;
        bool bSuccess = ContainsLeafData(akVertex,aiConnect,fEpsilon);
        assert( bSuccess );
    }
#endif
}
//----------------------------------------------------------------------------
BoundingVolumeTree::BoundingVolumeTree ()
{
    m_pkModelBound = NULL;
    m_pkWorldBound = NULL;
    m_pkLChild = NULL;
    m_pkRChild = NULL;
    m_iTriangleQuantity = 0;
    m_aiTriangle = NULL;
}
//----------------------------------------------------------------------------
BoundingVolumeTree::~BoundingVolumeTree ()
{
    delete m_pkModelBound;
    delete m_pkWorldBound;
    delete[] m_aiTriangle;
    delete m_pkLChild;
    delete m_pkRChild;
}
//----------------------------------------------------------------------------
void BoundingVolumeTree::CreateTree (BoundingVolume::Type eType,
    int iVertexCount, const Vector3f* akVertex, int iTriangleCount,
    const int* aiConnect, int iMaxTrisPerLeaf, bool bStoreInteriorTris,
    const Vector3f* akCentroid, int i0, int i1, int* aiISplit, int* aiOSplit)
{
    assert( i0 <= i1 );

    Vector3f kOrigin, kDirection;
    m_pkModelBound = BoundingVolume::Create(eType,iVertexCount,akVertex,
        aiConnect,i0,i1,aiISplit,kOrigin,kDirection);

    if ( i1 - i0 < iMaxTrisPerLeaf )
    {
        // leaf node
        m_iTriangleQuantity = i1 - i0 + 1;
        m_aiTriangle = new int[m_iTriangleQuantity];
        memcpy(m_aiTriangle,&aiISplit[i0],m_iTriangleQuantity*sizeof(int));

        m_pkLChild = NULL;
        m_pkRChild = NULL;
    }
    else
    {
        // interior node
        if ( bStoreInteriorTris )
        {
            m_iTriangleQuantity = i1 - i0 + 1;
            m_aiTriangle = new int[m_iTriangleQuantity];
            memcpy(m_aiTriangle,&aiISplit[i0],
                m_iTriangleQuantity*sizeof(int));
        }
        else
        {
            m_iTriangleQuantity = 0;
            m_aiTriangle = NULL;
        }

        int j0, j1;
        SplitTriangles(akCentroid,i0,i1,aiISplit,j0,j1,aiOSplit,kOrigin,
            kDirection);

        m_pkLChild = new BoundingVolumeTree;
        m_pkLChild->CreateTree(eType,iVertexCount,akVertex,iTriangleCount,
            aiConnect,iMaxTrisPerLeaf,bStoreInteriorTris,akCentroid,i0,j0,
            aiOSplit,aiISplit);

        m_pkRChild = new BoundingVolumeTree;
        m_pkRChild->CreateTree(eType,iVertexCount,akVertex,iTriangleCount,
            aiConnect,iMaxTrisPerLeaf,bStoreInteriorTris,akCentroid,j1,i1,
            aiOSplit,aiISplit);
    }
}
//----------------------------------------------------------------------------
int BoundingVolumeTree::Compare (const void* pvElement0,
    const void* pvElement1)
{
    const ProjectionInfo* pInfo0 = (const ProjectionInfo*) pvElement0;
    const ProjectionInfo* pInfo1 = (const ProjectionInfo*) pvElement1;

    if ( pInfo0->m_fProjection < pInfo1->m_fProjection )
        return -1;

    if ( pInfo0->m_fProjection > pInfo1->m_fProjection )
        return +1;

    return 0;
}
//----------------------------------------------------------------------------
void BoundingVolumeTree::SplitTriangles (const Vector3f* akCentroid,
    int i0, int i1, int* aiISplit, int& rj0, int& rj1, int* aiOSplit,
    const Vector3f& rkOrigin, const Vector3f& rkDirection)
{
    // project onto specified line
    int iQuantity = i1 - i0 + 1;
    ProjectionInfo* akInfo = new ProjectionInfo[iQuantity];
    int i, j;
    for (i = i0, j = 0; i <= i1; i++, j++)
    {
        int iTriangle = aiISplit[i];
        Vector3f kDiff = akCentroid[iTriangle] - rkOrigin;
        akInfo[j].m_iTriangle = iTriangle;
        akInfo[j].m_fProjection = rkDirection.Dot(kDiff);
    }

    // find median of projections by sorting
    qsort(akInfo,iQuantity,sizeof(ProjectionInfo),Compare);
    int iMedian = (iQuantity-1)/2;

    // partition the triangles by the median
    for (j = 0, rj0 = i0-1; j <= iMedian; j++)
        aiOSplit[++rj0] = akInfo[j].m_iTriangle;
    for (rj1 = i1+1; j < iQuantity; j++)
        aiOSplit[--rj1] = akInfo[j].m_iTriangle;

    delete[] akInfo;
}
//----------------------------------------------------------------------------
BoundingVolume* BoundingVolumeTree::GetWorldBound ()
{
    if ( !m_pkWorldBound )
    {
        m_pkWorldBound = BoundingVolume::Create(m_pkModelBound->GetType());
        m_pkWorldBound->Invalidate();
    }

    return m_pkWorldBound;
}
//----------------------------------------------------------------------------
void BoundingVolumeTree::InvalidateWorldBounds ()
{
    if ( m_pkWorldBound && m_pkWorldBound->IsValid() )
    {
        m_pkWorldBound->Invalidate();
        if ( m_pkLChild )
            m_pkLChild->InvalidateWorldBounds();
        if ( m_pkRChild )
            m_pkRChild->InvalidateWorldBounds();
    }
}
//----------------------------------------------------------------------------

#ifdef _DEBUG_TEST
//----------------------------------------------------------------------------
bool BoundingVolumeTree::ContainsLeafData (const Vector3f* akVertex,
    const int* aiConnect, float fEpsilon) const
{
    if ( m_pkLChild )
    {
        if ( !m_pkLChild->ContainsLeafData(akVertex,aiConnect,fEpsilon) )
            return false;
    }

    if ( m_pkRChild )
    {
        if ( !m_pkRChild->ContainsLeafData(akVertex,aiConnect,fEpsilon) )
            return false;
    }

    for (int iT = 0; iT < m_iTriangleQuantity; iT++)
    {
        int iIndex = 3*m_aiTriangle[iT];
        for (int i = 0; i < 3; i++)
        {
            Vector3f kPoint = akVertex[aiConnect[iIndex++]];
            if ( !m_pkModelBound->Contains(kPoint,fEpsilon) )
                return false;
        }
    }

    return true;
}
//----------------------------------------------------------------------------
#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -