//----------------------------------------------------------------------------
void SEIntrTriangle3Triangle3f::ProjectOntoAxis(const SETriangle3f& rTri, 
    const SEVector3f& rAxis, float& rfMin, float& rfMax)
{
    float fDot0 = rAxis.Dot(rTri.V[0]);
    float fDot1 = rAxis.Dot(rTri.V[1]);
    float fDot2 = rAxis.Dot(rTri.V[2]);

    rfMin = fDot0;
    rfMax = rfMin;

    if( fDot1 < rfMin )
    {
        rfMin = fDot1;
    }
    else if( fDot1 > rfMax )
    {
        rfMax = fDot1;
    }

    if( fDot2 < rfMin )
    {
        rfMin = fDot2;
    }
    else if( fDot2 > rfMax )
    {
        rfMax = fDot2;
    }
}
Example #2
0
void UFO::onUpdate()
{
	SE_TRANSFORM[ty] = 16.0f;
	SEVector3f dir = (playerPos - SE_TRANSFORM.translation()) / 10.0f;
	float power = dir.lengthSqaure() - 150.0f;
	if (power > 300.0f) power = 300.0f;
	SE_RIGIDBODY.resetVelocity(se_data::AXIS_Y);
	SE_RIGIDBODY.applyForce(dir.unify() * power * UFO_SPEED);
}
Example #3
0
void Bot::onUpdate()
{
    SEVector3f dir = (playerPos - SE_TRANSFORM.translation()) / 10.0f;

    float power = (dir.lengthSqaure() - 150.0f) / 2.0f;
    if (power > 90) power = 90.0f;
    dir[1] = 0.0f;
    dir = SE_MATRIX_ROTATE4(se_data::AXIS_Y, 90.0f - power)* SEVector4f(dir);
    SE_RIGIDBODY.applyForce(dir.unify() * BOT_SPEED);
}
//----------------------------------------------------------------------------
bool SEIntrLine3Box3f::DoClipping(float fT0, float fT1, const SEVector3f& 
    rOrigin, const SEVector3f& rDirection, const SEBox3f& rBox, bool bSolid, 
    int& riCount, SEVector3f aPoint[2], int& riIntrType)
{
    SE_ASSERT( fT0 < fT1 );

    // 把linear component变换到box坐标体系下.
    SEVector3f vec3fDiff = rOrigin - rBox.Center;
    SEVector3f vec3fBOrigin(
        vec3fDiff.Dot(rBox.Axis[0]),
        vec3fDiff.Dot(rBox.Axis[1]),
        vec3fDiff.Dot(rBox.Axis[2])
    );
    SEVector3f vec3fBDirection(
        rDirection.Dot(rBox.Axis[0]),
        rDirection.Dot(rBox.Axis[1]),
        rDirection.Dot(rBox.Axis[2])
    );

    float fSaveT0 = fT0, fSaveT1 = fT1;
    bool bNotAllClipped =
        Clip(+vec3fBDirection.X, -vec3fBOrigin.X-rBox.Extent[0], fT0, fT1) &&
        Clip(-vec3fBDirection.X, +vec3fBOrigin.X-rBox.Extent[0], fT0, fT1) &&
        Clip(+vec3fBDirection.Y, -vec3fBOrigin.Y-rBox.Extent[1], fT0, fT1) &&
        Clip(-vec3fBDirection.Y, +vec3fBOrigin.Y-rBox.Extent[1], fT0, fT1) &&
        Clip(+vec3fBDirection.Z, -vec3fBOrigin.Z-rBox.Extent[2], fT0, fT1) &&
        Clip(-vec3fBDirection.Z, +vec3fBOrigin.Z-rBox.Extent[2], fT0, fT1);

    if( bNotAllClipped && (bSolid || fT0 != fSaveT0 || fT1 != fSaveT1) )
    {
        if( fT1 > fT0 )
        {
            riIntrType = IT_SEGMENT;
            riCount = 2;
            aPoint[0] = rOrigin + fT0*rDirection;
            aPoint[1] = rOrigin + fT1*rDirection;
        }
        else
        {
            riIntrType = IT_POINT;
            riCount = 1;
            aPoint[0] = rOrigin + fT0*rDirection;
        }
    }
    else
    {
        riCount = 0;
        riIntrType = IT_EMPTY;
    }

    return riIntrType != IT_EMPTY;
}
//----------------------------------------------------------------------------
static SESpectrum EstimateIrradianceWithPhotonMap(SEKdTree<SEBNPhoton>* map, 
    int count, int lookupCount, SEBNClosePhoton* lookupBuf, 
    float maxDistSquared, const SEVector3f& p, const SEVector3f& n)
{
    if( !map )
    {
        return 0.0f;
    }

    // Lookup nearby photons at irradiance computation point.
    SEBNPhotonProcess proc(lookupCount, lookupBuf);
    float md2 = maxDistSquared;
    map->Lookup(p, proc, md2);
    SE_ASSERT( md2 > 0.0f );

    if( proc.FoundCount == 0 )
    {
        return SESpectrum(0.0f);
    }

    // Accumulate irradiance value from nearby photons.
    SEBNClosePhoton* photons = proc.Photons;
    SESpectrum E(0.0f);
    for( SE_UInt32 i = 0; i < proc.FoundCount; ++i )
    {
        float d = n.Dot(photons[i].Photon->Wi);
        if( d > 0.0f )
        {
            E += photons[i].Photon->Alpha;
        }
    }

    return E / (count * md2 * SEMathf::PI);
}
//----------------------------------------------------------------------------
bool SEIntrTriangle3Triangle3f::TestOverlap(const SEVector3f& rAxis, 
    float fTMax, const SEVector3f& rVelocity, float& rfTFirst, 
    float& rfTLast)
{
    float fMin0, fMax0, fMin1, fMax1;
    ProjectOntoAxis(*m_pTriangle0, rAxis, fMin0, fMax0);
    ProjectOntoAxis(*m_pTriangle1, rAxis, fMin1, fMax1);
    float fSpeed = rVelocity.Dot(rAxis);

    return TestOverlap(fTMax, fSpeed, fMin0, fMax0, fMin1, fMax1, rfTFirst, 
        rfTLast);
}
//----------------------------------------------------------------------------
bool SEIntrTriangle3Triangle3f::FindOverlap(const SEVector3f& rAxis, 
    float fTMax, const SEVector3f& rVelocity, ContactSide& reSide, 
    SEConfiguration& rTCfg0, SEConfiguration& rTCfg1, float& rfTFirst, 
    float& rfTLast)
{
    SEConfiguration tempCfg0, tempCfg1;
    ProjectOntoAxis(*m_pTriangle0, rAxis, tempCfg0);
    ProjectOntoAxis(*m_pTriangle1, rAxis, tempCfg1);
    float fSpeed = rVelocity.Dot(rAxis);

    return FindOverlap(fTMax, fSpeed, tempCfg0, tempCfg1, reSide, rTCfg0, 
        rTCfg1, rfTFirst, rfTLast);
}
Example #8
0
//----------------------------------------------------------------------------
bool Lighting::OnInitialize()
{
    if( !SEWindowApplication3::OnInitialize() )
    {
        return false;
    }

    m_spCamera->SetFrustum(-0.55f, 0.55f, -0.4125f, 0.4125f, 1.0f, 100.0f);
    SEVector3f tempCLoc(0.0f, 9.0f, -20.0f);
    SEVector3f tempCDir(0.0f, -0.2f, 1.0f);
    tempCDir.Normalize();
    SEVector3f tempCUp(0.0f, 1.0f, 0.0f);
    SEVector3f tempCRight = tempCUp.Cross(tempCDir);
    tempCRight.Normalize();
    tempCUp = tempCDir.Cross(tempCRight);
    tempCUp.Normalize();
    m_spCamera->SetFrame(tempCLoc, tempCRight, tempCUp, tempCDir);

    CreateScene();

    // initial update of objects
    m_spScene->UpdateGS();
    m_spScene->UpdateRS();

    // initial culling of scene
    m_Culler.SetCamera(m_spCamera);
    m_Culler.ComputeUnculledSet(m_spScene);

#if defined(SE_USING_OES2)
    InitializeCameraMotion(0.1f, 0.01f);
#else
    InitializeCameraMotion(0.01f, 0.001f);
#endif
    InitializeObjectMotion(m_spScene);

    return true;
}
//----------------------------------------------------------------------------
void SEExtremalQuery3PRJf::GetExtremeVertices(const SEVector3f& rDirection, 
    int& riPositiveDirection, int& riNegativeDirection)
{
    SEVector3f vec3fDiff = m_pPolytope->GetVertex(0) - m_Centroid;
    float fMin = rDirection.Dot(vec3fDiff), fMax = fMin;
    riNegativeDirection = 0;
    riPositiveDirection = 0;

    for( int i = 1; i < m_pPolytope->GetVCount(); i++ )
    {
        vec3fDiff = m_pPolytope->GetVertex(i) - m_Centroid;
        float fDot = rDirection.Dot(vec3fDiff);
        if( fDot < fMin )
        {
            riNegativeDirection = i;
            fMin = fDot;
        }
        else if( fDot > fMax )
        {
            riPositiveDirection = i;
            fMax = fDot;
        }
    }
}
//----------------------------------------------------------------------------
static SESpectrum EstimateRadianceWithPhotonMap(SEKdTree<SEBNPhoton>* map, 
    int pathCount, int lookupCount, SEBNClosePhoton* lookupBuf, SEBSDF* bsdf, 
    SERandomNumberGenerator& rng, const SEBNIntersection& isect, 
    const SEVector3f& wo, float maxDistSquared)
{
    SESpectrum L(0.0f);

    SEBxDF::BxDFType nonSpecular = SEBxDF::BxDFType(SEBxDF::BSDF_REFLECTION |
        SEBxDF::BSDF_TRANSMISSION | SEBxDF::BSDF_DIFFUSE | 
        SEBxDF::BSDF_GLOSSY);

    if( map && bsdf->GetComponentCount(nonSpecular) > 0 )
    {
        // Do photon map lookup at intersection point.
        SEBNPhotonProcess proc(lookupCount, lookupBuf);
        map->Lookup(isect.DG.p, proc, maxDistSquared);

        // Estimate reflected radiance due to incident photons.
        SEBNClosePhoton* photons = proc.Photons;
        int nFound = proc.FoundCount;
        SEVector3f Nf; 
        SEVector3f::Faceforward(bsdf->DGShading.nn, wo, Nf);
        if( bsdf->GetComponentCount(SEBxDF::BxDFType(SEBxDF::BSDF_REFLECTION |
            SEBxDF::BSDF_TRANSMISSION | SEBxDF::BSDF_GLOSSY)) > 0 )
        {
            // Compute exitant radiance from photons for glossy surface.

            for( int i = 0; i < nFound; ++i )
            {
                const SEBNPhoton* p = photons[i].Photon;
                float k = Kernel(p, isect.DG.p, maxDistSquared);
                L += (k / (pathCount * maxDistSquared)) * 
                    bsdf->f(wo, p->Wi) * p->Alpha;
            }
        }
        else
        {
            // Compute exitant radiance from photons for diffuse surface.

            SESpectrum Lr(0.0f), Lt(0.0f);
            for( int i = 0; i < nFound; ++i )
            {
                float d = Nf.Dot(photons[i].Photon->Wi);
                if( d > 0.0f )
                {
                    float k = Kernel(photons[i].Photon, isect.DG.p, 
                        maxDistSquared);
                    Lr += (k / (pathCount * maxDistSquared)) * 
                        photons[i].Photon->Alpha;
                }
                else
                {
                    float k = Kernel(photons[i].Photon, isect.DG.p, 
                        maxDistSquared);
                    Lt += (k / (pathCount * maxDistSquared)) * 
                        photons[i].Photon->Alpha;
                }
            }
            L += Lr * bsdf->rho(wo, rng, SEBxDF::BSDF_ALL_REFLECTION) * 
                SEMathf::INV_PI + 
                Lt * bsdf->rho(wo, rng, SEBxDF::BSDF_ALL_TRANSMISSION) * 
                SEMathf::INV_PI;
        }
    }

    return L;
}
//----------------------------------------------------------------------------
void SEPhotonShootingTask::DoWork()
{
    // Declare local variables for the task.
    SEMemoryArena arena;
    SERandomNumberGenerator rng(31 * TaskNum);
    std::vector<SEBNPhoton> localDirectPhotons;
    std::vector<SEBNPhoton> localIndirectPhotons;
    std::vector<SEBNPhoton> localCausticPhotons;
    std::vector<SEBNRadiancePhoton> localRadiancePhotons;
    SE_UInt32 totalPaths = 0;
    bool causticDone = (PhotonMapShader->CausticPhotonsWantedCount == 0);
    bool indirectDone = (PhotonMapShader->IndirectPhotonsWantedCount == 0);
    SEPermutedHalton halton(6, rng);
    std::vector<SESpectrum> localRpReflectances;
    std::vector<SESpectrum> localRpTransmittances;

    while( true )
    {
        // Follow photon paths for a block of samples.
        const SE_UInt32 blockSize = 4096;
        for( SE_UInt32 i = 0; i < blockSize; ++i )
        {
            float u[6];
            halton.Sample(++totalPaths, u);

            // Choose light to shoot photon from.
            float lightPdf;
            int lightNum = LightDistribution->SampleDiscrete(u[0], &lightPdf);
            const SEBNLight* light = Scene->Lights[lightNum];

            // Generate photonRay from light source.
            SERayDifferential photonRay;
            float pdf;
            SEBNLightSample lightSample(u[1], u[2], u[3]);
            SEVector3f lightSurfaceNormal;
            SESpectrum Le = light->Sample_L(Scene, lightSample, u[4], u[5],
                Time, &photonRay, &lightSurfaceNormal, &pdf);
            if( pdf == 0.0f || Le.IsBlack() )
            {
                continue;
            }

            // Initialize alpha value.
            float absCostheta = 
                fabsf(lightSurfaceNormal.Dot(photonRay.Direction));
            SESpectrum alpha = Le * (absCostheta / (pdf * lightPdf));

            if( !alpha.IsBlack() )
            {
                // Follow photon path through scene and record intersections.

                bool specularPath = true;
                SEBNIntersection photonIsect;
                int nIntersections = 0;
                while( Scene->Intersect(photonRay, &photonIsect) )
                {
                    ++nIntersections;

                    // Handle photon/surface intersection.

                    alpha *= Renderer->Transmittance(Scene, photonRay, 0, rng, 
                        arena);

                    // Determine if none specular component exists.
                    SEBSDF* photonBSDF = photonIsect.GetBSDF(photonRay, arena);
                    SEBxDF::BxDFType specularType = SEBxDF::BxDFType(
                        SEBxDF::BSDF_REFLECTION | SEBxDF::BSDF_TRANSMISSION | 
                        SEBxDF::BSDF_SPECULAR);
                    bool hasNonSpecular = (photonBSDF->GetComponentCount() >
                        photonBSDF->GetComponentCount(specularType));

                    SEVector3f wo = -photonRay.Direction;
                    if( hasNonSpecular )
                    {
                        // Deposit photon at surface that has non-specular BSDF
                        // component.

                        SEBNPhoton photon(photonIsect.DG.p, alpha, wo);
                        bool depositedPhoton = false;
                        if( specularPath && nIntersections > 1 )
                        {
                            if( !causticDone )
                            {
                                // Deposit caustic photon at surface.
                                depositedPhoton = true;
                                localCausticPhotons.push_back(photon);
                            }
                        }
                        else
                        {
                            // Deposit either direct or indirect photon.
                            // Stop depositing direct photons once indirectDone
                            // is true; don't want to waste memory storing too 
                            // many if we're going a long time trying to get 
                            // enough caustic photons desposited.
                            if( nIntersections == 1 && !indirectDone && 
                                PhotonMapShader->FinalGather )
                            {
                                // Deposit direct photon at surface.
                                depositedPhoton = true;
                                localDirectPhotons.push_back(photon);
                            }
                            else if( nIntersections > 1 && !indirectDone )
                            {
                                // Deposit indirect photon at surface.
                                depositedPhoton = true;
                                localIndirectPhotons.push_back(photon);
                            }
                        }

                        // Possibly create radiance photon at photon 
                        // intersection point.
                        if( depositedPhoton && PhotonMapShader->FinalGather &&
                            rng.RandomFloat() < 0.125f )
                        {
                            SEVector3f n = photonIsect.DG.nn;
                            SEVector3f::Faceforward(n, -photonRay.Direction, n);
                            SEBNRadiancePhoton radiancePhoton(photonIsect.DG.p, 
                                n);
                            localRadiancePhotons.push_back(radiancePhoton);

                            SESpectrum rho_r = photonBSDF->rho(rng, 
                                SEBxDF::BSDF_ALL_REFLECTION);
                            localRpReflectances.push_back(rho_r);

                            SESpectrum rho_t = photonBSDF->rho(rng, 
                                SEBxDF::BSDF_ALL_TRANSMISSION);
                            localRpTransmittances.push_back(rho_t);
                        }
                    }

                    // Stop bouncing if max photon depth has been reached.
                    if( nIntersections >= PhotonMapShader->MaxPhotonDepth )
                    {
                        break;
                    }

                    // Sample new photon ray direction.
                    SEVector3f wi;
                    float _pdf;
                    SEBxDF::BxDFType flags;
                    SESpectrum fr = photonBSDF->Sample_f(wo, &wi, 
                        SEBSDFSample(rng), &_pdf, SEBxDF::BSDF_ALL, &flags);
                    if( fr.IsBlack() || _pdf == 0.0f )
                    {
                        break;
                    }

                    float absCosi = fabsf(wi.Dot(photonBSDF->DGShading.nn));
                    SESpectrum anew = alpha * fr * (absCosi / _pdf);

                    // Possibly terminate photon path with Russian roulette.
                    float luminanceRatio = anew.y() / alpha.y();
                    float continueProb = SE_MIN(1.0f, luminanceRatio);
                    if( rng.RandomFloat() > continueProb )
                    {
                        break;
                    }

                    alpha = anew / continueProb;
                    specularPath &= ((flags & SEBxDF::BSDF_SPECULAR) != 0);
                    
                    if( indirectDone && !specularPath )
                    {
                        break;
                    }

                    photonRay = SERayDifferential(photonIsect.DG.p, wi, 
                        photonRay, photonIsect.RayEpsilon);
                }
            }

            arena.FreeAll();
        }

        // Merge local photon data with data in photon map shader.
        {
            // Begin mutex scope.

            SEMutexLock lock(Mutex);

            // Give up if we're not storing enough photons.
            if( AbortTasks )
            {
                return;
            }

            bool causticUnsuccessful = Unsuccessful(
                PhotonMapShader->CausticPhotonsWantedCount, 
                CausticPhotons.size(), blockSize);

            bool indirectUnsuccessful = Unsuccessful(
                PhotonMapShader->IndirectPhotonsWantedCount,
                IndirectPhotons.size(), blockSize);

            if( ShotCount > SEBNPhotonMapShader::MAX_PHOTON_PATH_SHOT_COUNT 
                && (causticUnsuccessful || indirectUnsuccessful) )
            {
                // Unable to store enough photons. Giving up.
                CausticPhotons.erase(CausticPhotons.begin(), 
                    CausticPhotons.end());
                IndirectPhotons.erase(IndirectPhotons.begin(), 
                    IndirectPhotons.end());
                RadiancePhotons.erase(RadiancePhotons.begin(), 
                    RadiancePhotons.end());

                // Notify all the other tasks to stop.
                AbortTasks = true;

                return;
            }

            ProgressReporter.Update(localIndirectPhotons.size() + 
                localCausticPhotons.size());
            ShotCount += blockSize;

            // Merge direct and indirect photons into shared array.
            if( !indirectDone )
            {
                PhotonMapShader->IndirectPathsCount += blockSize;
                for( SE_UInt32 i = 0; i < localIndirectPhotons.size(); ++i )
                {
                    IndirectPhotons.push_back(localIndirectPhotons[i]);
                }
                localIndirectPhotons.erase(localIndirectPhotons.begin(),
                    localIndirectPhotons.end());

                if( IndirectPhotons.size() >= 
                    PhotonMapShader->IndirectPhotonsWantedCount )
                {
                    indirectDone = true;
                }

                DirectPathsCount += blockSize;
                for( SE_UInt32 i = 0; i < localDirectPhotons.size(); ++i )
                {
                    DirectPhotons.push_back(localDirectPhotons[i]);
                }
                localDirectPhotons.erase(localDirectPhotons.begin(),
                    localDirectPhotons.end());
            }

            // Merge caustic, and radiance photons into shared array.
            if( !causticDone )
            {
                PhotonMapShader->CausticPathsCount += blockSize;
                for( SE_UInt32 i = 0; i < localCausticPhotons.size(); ++i )
                {
                    CausticPhotons.push_back(localCausticPhotons[i]);
                }
                localCausticPhotons.erase(localCausticPhotons.begin(), 
                    localCausticPhotons.end());

                if( CausticPhotons.size() >= 
                    PhotonMapShader->CausticPhotonsWantedCount )
                {
                    causticDone = true;
                }
            }
        
            for( SE_UInt32 i = 0; i < localRadiancePhotons.size(); ++i )
            {
                RadiancePhotons.push_back(localRadiancePhotons[i]);
            }
            localRadiancePhotons.erase(localRadiancePhotons.begin(), 
                localRadiancePhotons.end());

            for( SE_UInt32 i = 0; i < localRpReflectances.size(); ++i )
            {
                RadiancePhotonReflectances.push_back(localRpReflectances[i]);
            }
            localRpReflectances.erase(localRpReflectances.begin(), 
                localRpReflectances.end());

            for( SE_UInt32 i = 0; i < localRpTransmittances.size(); ++i )
            {
                RadiancePhotonTransmittances.push_back(
                    localRpTransmittances[i]);
            }
            localRpTransmittances.erase(localRpTransmittances.begin(), 
                localRpTransmittances.end());

            // End mutex scope.
        }

        // Exit task if enough photons have been found.
        if( indirectDone && causticDone )
        {
            break;
        }
    }
}
Example #12
0
//----------------------------------------------------------------------------
SEPlane3f::SEPlane3f(const SEVector3f& rNormal, const SEVector3f& rP0)
    : Normal(rNormal)
{
    Constant = rNormal.Dot(rP0);
}
//----------------------------------------------------------------------------
void SEIntrTriangle3Triangle3f::ProjectOntoAxis(const SETriangle3f& rTri, 
    const SEVector3f& rAxis, SEConfiguration& rCfg)
{
    // find projections of vertices onto potential separating axis
    float fD0 = rAxis.Dot(rTri.V[0]);
    float fD1 = rAxis.Dot(rTri.V[1]);
    float fD2 = rAxis.Dot(rTri.V[2]);

    // explicit sort of vertices to construct a SEConfiguration object
    if( fD0 <= fD1 )
    {
        if( fD1 <= fD2 ) // D0 <= D1 <= D2
        {
            if( fD0 != fD1 )
            {
                if( fD1 != fD2 )
                {
                    rCfg.Map = M111;
                }
                else
                {
                    rCfg.Map = M12;
                }
            }
            else // ( D0 == D1 )
            {
                if( fD1 != fD2 )
                {
                    rCfg.Map = M21;
                }
                else
                {
                    rCfg.Map = M3;
                }
            }
            rCfg.Index[0] = 0;
            rCfg.Index[1] = 1;
            rCfg.Index[2] = 2;
            rCfg.Min = fD0;
            rCfg.Max = fD2;
        }
        else if( fD0 <= fD2 ) // D0 <= D2 < D1
        {
            if( fD0 != fD2 )
            {
                rCfg.Map = M111;
                rCfg.Index[0] = 0;
                rCfg.Index[1] = 2;
                rCfg.Index[2] = 1;
            }
            else
            {
                rCfg.Map = M21;
                rCfg.Index[0] = 2;
                rCfg.Index[1] = 0;
                rCfg.Index[2] = 1;
            }
            rCfg.Min = fD0;
            rCfg.Max = fD1;
        }
        else // D2 < D0 <= D1
        {
            if( fD0 != fD1 )
            {
                rCfg.Map = M111;
            }
            else
            {
                rCfg.Map = M12;
            }

            rCfg.Index[0] = 2;
            rCfg.Index[1] = 0;
            rCfg.Index[2] = 1;
            rCfg.Min = fD2;
            rCfg.Max = fD1;
        }
    }
    else if( fD2 <= fD1 ) // D2 <= D1 < D0
    {
        if( fD2 != fD1 )
        {
            rCfg.Map = M111;
            rCfg.Index[0] = 2;
            rCfg.Index[1] = 1;
            rCfg.Index[2] = 0;
        }
        else
        {
            rCfg.Map = M21;
            rCfg.Index[0] = 1;
            rCfg.Index[1] = 2;
            rCfg.Index[2] = 0;

        }
        rCfg.Min = fD2;
        rCfg.Max = fD0;
    }
    else if( fD2 <= fD0 ) // D1 < D2 <= D0
    {
        if( fD2 != fD0 ) 
        {
            rCfg.Map = M111;
        }
        else
        {
            rCfg.Map = M12;
        }

        rCfg.Index[0] = 1;
        rCfg.Index[1] = 2;
        rCfg.Index[2] = 0;
        rCfg.Min = fD1;
        rCfg.Max = fD0;
    }
    else // D1 < D0 < D2
    {
        rCfg.Map = M111;
        rCfg.Index[0] = 1;
        rCfg.Index[1] = 0;
        rCfg.Index[2] = 2;
        rCfg.Min = fD1;
        rCfg.Max = fD2;
    }
}