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

📄 mgctubesurfaceg.cpp

📁 《3D游戏引擎设计》的源码
💻 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
//
// FREE SOURCE CODE
// http://www.magic-software.com/License/free.pdf

#include "MgcMultipleCurve3.h"
#include "MgcTubeSurfaceG.h"

//----------------------------------------------------------------------------
MgcTubeSurfaceG::MgcTubeSurfaceG (MgcMultipleCurve3* pkMedial,
    RadialFunction oRadial, bool bClosed, unsigned int uiMedialSamples,
    unsigned int uiSliceSamples, bool bSampleByArcLength, bool bWantNormals,
    const MgcVector3* pkUpVector)
{
    assert( pkMedial && oRadial );

    m_pkMedial = pkMedial;
    m_oRadial = oRadial;
    m_bClosed = bClosed;
    m_uiVertexQuantity = 0;
    m_akVertex = 0;
    m_akNormal = 0;
    m_uiTriangleQuantity = 0;
    m_auiConnect = 0;

    // default tessellation
    Tessellate(uiMedialSamples,uiSliceSamples,bSampleByArcLength,bWantNormals,
        pkUpVector);
}
//----------------------------------------------------------------------------
MgcTubeSurfaceG::MgcTubeSurfaceG ()
{
    m_pkMedial = 0;
    m_oRadial = 0;
    m_bClosed = false;
    m_uiVertexQuantity = 0;
    m_akVertex = 0;
    m_akNormal = 0;
    m_uiTriangleQuantity = 0;
    m_auiConnect = 0;
}
//----------------------------------------------------------------------------
MgcTubeSurfaceG::~MgcTubeSurfaceG ()
{
    delete m_pkMedial;
    delete[] m_akVertex;
    delete[] m_akNormal;
    delete[] m_auiConnect;
}
//----------------------------------------------------------------------------
unsigned int MgcTubeSurfaceG::Index (unsigned short uiS, unsigned short uiM)
{
    return uiS + (m_uiSliceSamples+1)*uiM;
}
//----------------------------------------------------------------------------
void MgcTubeSurfaceG::ComputeVertices ()
{
    if ( m_bClosed )
        m_uiVertexQuantity = (m_uiSliceSamples+1)*(m_uiMedialSamples+1);
    else
        m_uiVertexQuantity = (m_uiSliceSamples+1)*m_uiMedialSamples;

    delete[] m_akVertex;
    m_akVertex = new MgcVector3[m_uiVertexQuantity];

    // Compute slice vertex coefficients.  The first and last coefficients
    // are duplicated to allow a closed cross section that has two different
    // pairs of texture coordinates at the shared vertex.
    MgcReal* afSin = new MgcReal[m_uiSliceSamples + 1];
    MgcReal* afCos = new MgcReal[m_uiSliceSamples + 1];
    unsigned int uiS;
    for (uiS = 0; uiS < m_uiSliceSamples; uiS++)
    {
        MgcReal fAngle = uiS*MgcMath::TWO_PI/m_uiSliceSamples;
        afCos[uiS] = MgcMath::Cos(fAngle);
        afSin[uiS] = MgcMath::Sin(fAngle);
    }
    afSin[m_uiSliceSamples] = afSin[0];
    afCos[m_uiSliceSamples] = afCos[0];

    // compute vertices
    MgcReal fTMin = m_pkMedial->GetMinTime();
    MgcReal fTRange = m_pkMedial->GetMaxTime() - fTMin;
    MgcReal fTotalLength;
    if ( m_bClosed )
        fTotalLength = m_pkMedial->GetTotalLength();
    else
        fTotalLength = 0.0;

    for (unsigned int uiM = 0, uiV = 0; uiM < m_uiMedialSamples; uiM++)
    {
        MgcReal fT;
        if ( m_bClosed )
        {
            if ( m_bSampleByArcLength )
            {
                fT = m_pkMedial->GetTime(
                    uiM*fTotalLength/MgcReal(m_uiMedialSamples));
            }
            else
            {
                fT = fTMin + uiM*fTRange/MgcReal(m_uiMedialSamples);
            }
        }
        else
        {
            if ( m_bSampleByArcLength )
            {
                fT = m_pkMedial->GetTime(
                    uiM*fTotalLength/MgcReal(m_uiMedialSamples-1));
            }
            else
            {
                fT = fTMin + uiM*fTRange/MgcReal(m_uiMedialSamples-1);
            }
        }

        MgcReal fRadius = m_oRadial(fT);

        // compute frame (position P, tangent T, normal N, binormal B)
        MgcVector3 kP, kT, kN, kB;
        if ( m_pkUpVector )
        {
            // Always use 'up' vector N rather than curve normal.  You must
            // constrain the curve so that T and N are never parallel.  To
            // build the frame from this, let
            //     B = Cross(T,N)/Length(Cross(T,N))
            // and replace
            //     N = Cross(B,T)/Length(Cross(B,T)).
            kP = m_pkMedial->GetPosition(fT);
            kT = m_pkMedial->GetTangent(fT);
            kB = kT.UnitCross(MgcVector3::UNIT_Z);
            kN = kB.UnitCross(kT);
        }
        else
        {
            // use Frenet frame to create slices
            m_pkMedial->GetFrame(fT,kP,kT,kN,kB);
        }

        // compute slice vertices, duplication at end point as noted earlier
        unsigned int uiSave = uiV;
        for (uiS = 0; uiS < m_uiSliceSamples; uiS++)
        {
            m_akVertex[uiV] = kP + fRadius*(afCos[uiS]*kN + afSin[uiS]*kB);
            uiV++;
        }
        m_akVertex[uiV] = m_akVertex[uiSave];
        uiV++;
    }

    if ( m_bClosed )
    {
        for (uiS = 0; uiS <= m_uiSliceSamples; uiS++)
        {
            unsigned int uiI1 = Index(uiS,m_uiMedialSamples);
            unsigned int uiI0 = Index(uiS,0);
            m_akVertex[uiI1] = m_akVertex[uiI0];
        }
    }

    delete[] afSin;
    delete[] afCos;
}
//----------------------------------------------------------------------------
void MgcTubeSurfaceG::ComputeNormals ()
{
    delete[] m_akNormal;
    m_akNormal = new MgcVector3[m_uiVertexQuantity];

    unsigned int uiSm, uiSp, uiMm, uiMp;
    MgcVector3 kDir0, kDir1;
    unsigned int uiS;

    // interior normals (central differences)
    for (unsigned int uiM = 1; uiM <= m_uiMedialSamples-2; uiM++)
    {
        for (uiS = 0; uiS < m_uiSliceSamples; uiS++)
        {
            uiSm = ( uiS > 0 ? uiS-1 : m_uiSliceSamples-1 );
            uiSp = uiS + 1;
            uiMm = uiM - 1;
            uiMp = uiM + 1;
            kDir0 = m_akVertex[Index(uiSm,uiM)] - m_akVertex[Index(uiSp,uiM)];
            kDir1 = m_akVertex[Index(uiS,uiMm)] - m_akVertex[Index(uiS,uiMp)];
            m_akNormal[Index(uiS,uiM)] = kDir0.UnitCross(kDir1);
        }
        m_akNormal[Index(m_uiSliceSamples,uiM)] = m_akNormal[Index(0,uiM)];
    }

    // boundary normals
    if ( m_bClosed )
    {
        // central differences
        for (uiS = 0; uiS < m_uiSliceSamples; uiS++)
        {
            uiSm = ( uiS > 0 ? uiS-1 : m_uiSliceSamples-1 );
            uiSp = uiS + 1;

            // m = 0
            kDir0 = m_akVertex[Index(uiSm,0)] - m_akVertex[Index(uiSp,0)];
            kDir1 = m_akVertex[Index(uiS,m_uiMedialSamples-1)] -
                m_akVertex[Index(uiS,1)];
            m_akNormal[uiS] = kDir0.UnitCross(kDir1);

            // m = max
            m_akNormal[Index(uiS,m_uiMedialSamples)] =
                m_akNormal[Index(uiS,0)];
        }
        m_akNormal[Index(m_uiSliceSamples,0)] = m_akNormal[Index(0,0)];
        m_akNormal[Index(m_uiSliceSamples,m_uiMedialSamples)] =
            m_akNormal[Index(0,m_uiMedialSamples)];
    }
    else
    {
        // one-sided finite differences

        // m = 0
        for (uiS = 0; uiS < m_uiSliceSamples; uiS++)
        {
            uiSm = ( uiS > 0 ? uiS-1 : m_uiSliceSamples-1 );
            uiSp = uiS + 1;
            kDir0 = m_akVertex[Index(uiSm,0)] - m_akVertex[Index(uiSp,0)];
            kDir1 = m_akVertex[Index(uiS,0)] - m_akVertex[Index(uiS,1)];
            m_akNormal[Index(uiS,0)] = kDir0.UnitCross(kDir1);
        }
        m_akNormal[Index(m_uiSliceSamples,0)] = m_akNormal[Index(0,0)];

        // m = max-1
        for (uiS = 0; uiS < m_uiSliceSamples; uiS++)
        {
            uiSm = ( uiS > 0 ? uiS-1 : m_uiSliceSamples-1 );
            uiSp = uiS + 1;
            kDir0 = m_akVertex[Index(uiSm,m_uiMedialSamples-1)] -
                m_akVertex[Index(uiSp,m_uiMedialSamples-1)];
            kDir1 = m_akVertex[Index(uiS,m_uiMedialSamples-2)] -
                m_akVertex[Index(uiS,m_uiMedialSamples-1)];
            m_akNormal[uiS] = kDir0.UnitCross(kDir1);
        }
        m_akNormal[Index(m_uiSliceSamples,m_uiMedialSamples-1)] =
            m_akNormal[Index(0,m_uiMedialSamples-1)];
    }
}
//----------------------------------------------------------------------------
void MgcTubeSurfaceG::ComputeConnectivity ()
{
    m_uiTriangleQuantity = 2*m_uiSliceSamples*m_uiMedialSamples;
    delete[] m_auiConnect;
    m_auiConnect = new unsigned int[3*m_uiTriangleQuantity];

    unsigned int* puiConnect = m_auiConnect;
    for (unsigned int uiM = 0, uiMStart = 0; uiM < m_uiMedialSamples; uiM++)
    {
        unsigned int uiI0 = uiMStart;
        unsigned int uiI1 = uiI0 + 1;
        uiMStart += m_uiSliceSamples + 1;
        unsigned int uiI2 = uiMStart;
        unsigned int uiI3 = uiI2 + 1;
        for (unsigned int uiS = 0; uiS < m_uiSliceSamples; uiS++)
        {
            // TO DO.  The ordering of the vertices assumes you want to view
            // the tube from the inside.  If you want a view from the outside
            // or if you want a double-sided tube, this function must change.
            *puiConnect++ = uiI0;
            *puiConnect++ = uiI2;
            *puiConnect++ = uiI1;
            *puiConnect++ = uiI1;
            *puiConnect++ = uiI2;
            *puiConnect++ = uiI3;
            uiI0++;
            uiI1++;
            uiI2++;
            uiI3++;
        }
    }
}
//----------------------------------------------------------------------------
void MgcTubeSurfaceG::Tessellate (unsigned int uiMedialSamples,
    unsigned int uiSliceSamples, bool bSampleByArcLength, bool bWantNormals,
    const MgcVector3* pkUpVector)
{
    m_uiMedialSamples = uiMedialSamples;
    m_uiSliceSamples = uiSliceSamples;
    m_bSampleByArcLength = bSampleByArcLength;
    m_bWantNormals = bWantNormals;
    m_pkUpVector = pkUpVector;

    ComputeVertices();

    if ( m_bWantNormals )
        ComputeNormals();

    ComputeConnectivity();
}
//----------------------------------------------------------------------------

⌨️ 快捷键说明

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