bool AttributeAttractRepelParticleAffector::affect(ParticleSystemRefPtr System, Int32 ParticleIndex, const Time& elps)
{
    if(System != NULL)
    {
        Vec3f Displacement(System->getSecPosition(ParticleIndex) - System->getPosition(ParticleIndex) );

        Real32 Distance(Displacement.squareLength());

        if((Distance > getMinDistance()*getMinDistance()) &&
           (Distance < getMaxDistance()*getMaxDistance()))
        {
            Distance = osgSqrt(Distance);
            Displacement.normalize();

            Real32 t((getQuadratic() * (Distance*Distance) + getLinear() * Distance + getConstant())*elps);
            if(t > Distance)
            {
                t=Distance;
            }

            System->setPosition(System->getPosition(ParticleIndex) + (Displacement * t),ParticleIndex) ;
        }
    }
    return false;
}
Ejemplo n.º 2
0
bool Line::intersect(const SphereVolume &sphere,
                           Real         &enter, 
                           Real         &exit  ) const
{
    Vec3r v;
    Pnt3r center;

    sphere.getCenter(center);

    Real radius;
    Real h;
    Real b;
    Real d;
    Real t1;
    Real t2;

    radius = sphere.getRadius();

    v = center - _pos;

    h = (v.dot(v))-(radius * radius);
    b = (v.dot(_dir));

    if(h >= 0.f && b <= 0.f)
        return false;

    d = b * b - h;

    if(d < 0.f)
        return false;

    d  = osgSqrt(d);
    t1 = b - d;

//    if (t1 > 1)
//        return false;

    t2 = b + d;

    if( t1 < TypeTraits<Real>::getDefaultEps() )
    {
        if( t2 < TypeTraits<Real>::getDefaultEps() /*|| t2 > 1*/)
        {
            return false;
        }
    }

    enter = t1;
    exit  = t2;

    return true;
}
void ShaderShadowMapEngine::calcPointLightRange(
    const PointLight *pointL,      Real32  lightThreshold,
          Real32      defaultNear, Real32  defaultFar,
          Real32     &outNear,     Real32 &outFar         )
{
    outNear = defaultNear;
    outFar  = defaultFar;

    Real32 kQ = pointL->getQuadraticAttenuation();
    Real32 kL = pointL->getLinearAttenuation   ();
    Real32 kC = pointL->getConstantAttenuation ();

    if(osgAbs(kQ) > TypeTraits<Real32>::getDefaultEps())
    {
        Real32 det = kL * kL  - 4.f * kQ * (kC - 1.f / lightThreshold);

        if(det >= 0)
        {
            det       = osgSqrt(det);
            Real32 r1 = - kL + det / (2.f * kQ);
            Real32 r2 = - kL - det / (2.f * kQ);

            if(r1 > 0.f && r2 > 0.f)
            {
                outFar = osgMin(r1, r2);
            }
            else if(r1 > 0.f)
            {
                outFar = r1;
            }
            else if(r2 > 0.f)
            {
                outFar = r2;
            }
        }
    }
    else if(osgAbs(kL) > TypeTraits<Real32>::getDefaultEps())
    {
        Real32 r = (1.f / lightThreshold - kC) / kL;

        if(r > 0.f)
        {
            outFar = r;
        }
    }
}
Vec3f CylinderDistribution3D::generate(void) const
{
    Vec3f Result;

    switch(getSurfaceOrVolume())
    {
    case SURFACE:
        {
            std::vector<Real32> Areas;
            //Min Cap
            Areas.push_back(0.5*osgAbs(getMaxTheta() - getMinTheta())*(getOuterRadius()*getOuterRadius() - getInnerRadius()*getInnerRadius()));
            //Max Cap
            Areas.push_back(Areas.back() + 0.5*osgAbs(getMaxTheta() - getMinTheta())*(getOuterRadius()*getOuterRadius() - getInnerRadius()*getInnerRadius()));
            //Inner Tube
            Areas.push_back(Areas.back() + getInnerRadius()*osgAbs(getMaxTheta() - getMinTheta()) * getHeight());
            //Outer Tube
            Areas.push_back(Areas.back() + getOuterRadius()*osgAbs(getMaxTheta() - getMinTheta()) * getHeight());

            bool HasTubeSides(osgAbs(getMaxTheta() - getMinTheta()) - 6.283185 < -0.000001);
            if(HasTubeSides)
            {
                //MinTheta Tube Side
                Areas.push_back(Areas.back() + (getOuterRadius() - getInnerRadius()) * getHeight());

                //MaxTheta Tube Side
                Areas.push_back(Areas.back() + (getOuterRadius() - getInnerRadius()) * getHeight());
            }

            Real32 PickEdge(RandomPoolManager::getRandomReal32(0.0,1.0));
            if(PickEdge < Areas[0]/Areas.back())
            {
                //Max Cap
                Real32 Temp(osgSqrt(RandomPoolManager::getRandomReal32(0.0,1.0)));
                Real32 Radius(getInnerRadius() + Temp*(getOuterRadius() - getInnerRadius()));
                Real32 Theta( RandomPoolManager::getRandomReal32(getMinTheta(),getMaxTheta()) );
                Result = getCenter().subZero()
                    + (Radius*osgSin(Theta))*getTangent()
                    + (Radius*osgCos(Theta))*getBinormal()
                    + (getHeight()/static_cast<Real32>(2.0))*getNormal();
            }
            else if(PickEdge < Areas[1]/Areas.back())
            {
                //Min Cap
                Real32 Temp(osgSqrt(RandomPoolManager::getRandomReal32(0.0,1.0)));
                Real32 Radius(getInnerRadius() + Temp*(getOuterRadius() - getInnerRadius()));
                Real32 Theta( RandomPoolManager::getRandomReal32(getMinTheta(),getMaxTheta()) );
                Result = getCenter().subZero()
                    + (Radius*osgSin(Theta))*getTangent()
                    + (Radius*osgCos(Theta))*getBinormal()
                    + (-getHeight()/static_cast<Real32>(2.0))*getNormal();
            }
            else if(PickEdge < Areas[2]/Areas.back())
            {
                //Inner Tube
                Real32 Theta( RandomPoolManager::getRandomReal32(getMinTheta(),getMaxTheta()) );
                Real32 Height(RandomPoolManager::getRandomReal32(-getHeight()/2.0,getHeight()/2.0));
                Result =  getCenter().subZero()
                    + getInnerRadius()*osgSin(Theta)*getTangent()
                    + getInnerRadius()*osgCos(Theta)*getBinormal()
                    + Height*getNormal();
            }
            else if(PickEdge < Areas[3]/Areas.back())
            {
                //Outer Tube
                Real32 Theta( RandomPoolManager::getRandomReal32(getMinTheta(),getMaxTheta()) );
                Real32 Height(RandomPoolManager::getRandomReal32(-getHeight()/2.0,getHeight()/2.0));
                Result =  getCenter().subZero()
                    + getOuterRadius()*osgSin(Theta)*getTangent()
                    + getOuterRadius()*osgCos(Theta)*getBinormal()
                    + Height*getNormal();
            }
            else if(HasTubeSides && PickEdge < Areas[4]/Areas.back())
            {
                //MinTheta Tube Side
                Real32 Temp(osgSqrt(RandomPoolManager::getRandomReal32(0.0,1.0)));
                Real32 Radius(getInnerRadius() + Temp*(getOuterRadius() - getInnerRadius()));
                Real32 Height(RandomPoolManager::getRandomReal32(-getHeight()/2.0,getHeight()/2.0));
                Result = getCenter().subZero()
                    + (Radius*osgSin(getMinTheta()))*getTangent()
                    + (Radius*osgCos(getMinTheta()))*getBinormal()
                    + Height*getNormal();
            }
            else if(HasTubeSides && PickEdge < Areas[5]/Areas.back())
            {
                //MaxTheta Tube Side
                Real32 Temp(osgSqrt(RandomPoolManager::getRandomReal32(0.0,1.0)));
                Real32 Radius(getInnerRadius() + Temp*(getOuterRadius() - getInnerRadius()));
                Real32 Height(RandomPoolManager::getRandomReal32(-getHeight()/2.0,getHeight()/2.0));
                Result = getCenter().subZero()
                    + (Radius*osgSin(getMaxTheta()))*getTangent()
                    + (Radius*osgCos(getMaxTheta()))*getBinormal()
                    + Height*getNormal();
            }
            else
            {
                assert(false && "Should never reach this point");
            }
            break;
        }
    case VOLUME:
    default:
        {
            //To get a uniform distribution across the disc get a uniformly distributed allong 0.0 - 1.0
            //Then Take the square root of that.  This gives a square root distribution from 0.0 - 1.0
            //This square root distribution is used for the random radius because the area of a disc is 
            //dependant on the square of the radius, i.e it is a quadratic function
            Real32 Temp(osgSqrt(RandomPoolManager::getRandomReal32(0.0,1.0)));
            Real32 Radius(getInnerRadius() + Temp*(getOuterRadius() - getInnerRadius()));
            Real32 Height(RandomPoolManager::getRandomReal32(-getHeight()/2.0,getHeight()/2.0));
            Real32 Theta( RandomPoolManager::getRandomReal32(getMinTheta(),getMaxTheta()) );
            Result = getCenter().subZero()
                   + (Radius*osgSin(Theta))*getTangent()
                   + (Radius*osgCos(Theta))*getBinormal()
                   + Height*getNormal();
            break;
        }
    }

    return Result;
}
/*! Calculates the trapezoidal transformation matrix \a matNT that transforms
    post projection light space so that shadow map resolution in the
    "foreground" is maximized.
    The major steps are:
      - compute the intersection of eyeFrust and lightFrust
      - construct a trapezoid that contains the intersection
      - determine the transformation that maps this trapezoid to the
        (-1, 1) square

    Returns \c true if the transform was computed, \c false otherwise (e.g. if
    the intersection of eyeFrust and lightFrust is empty).
    
    For details see "T. Martin, T.-S. Tan: Anti-aliasing and Continuity
                     with Trapezoidal Shadow Maps" 
 */
bool TrapezoidalShadowMapEngine::calcTrapezoidalTransform(
          Matrixr       &matNT,
    const Matrixr       &matEyeToWorld, 
    const Matrixr       &matLightFull,
    const FrustumVolume &eyeFrust,
    const FrustumVolume &lightFrust    )
{
    // obtain post proj. light space eye position
    Pnt3r eyePos;
    matEyeToWorld.mult    (eyePos, eyePos);
    matLightFull .multFull(eyePos, eyePos);

    // intersect eye and light frusta, get vertices and center of intersection
    std::vector<Pnt3r> intVerts;
    Pnt3r              intCenter;
    intersectFrusta(eyeFrust, lightFrust, intVerts, intCenter);

    if(intVerts.empty() == true)
        return false;

    // xform intCenter and intVerts to post proj. light space
    matLightFull.multFull(intCenter, intCenter);

    std::vector<Pnt3r>::iterator ivIt  = intVerts.begin();
    std::vector<Pnt3r>::iterator ivEnd = intVerts.end  ();

    for(; ivIt != ivEnd; ++ivIt)
        matLightFull.multFull(*ivIt, *ivIt);
    
    Pnt2r eyePos2D   (eyePos   [0], eyePos   [1]);
    Pnt2r intCenter2D(intCenter[0], intCenter[1]);

    // center line, normal, direction and distance from origin
    Vec2r clDir (intCenter2D - eyePos2D);
    clDir.normalize();
    Vec2r clNorm(-clDir[1], clDir[0]);

    // distance of the center line from the origin
    Real clDist = clNorm.dot(eyePos2D.subZero());

    // compute top and base lines:
    //  - project intVerts onto the center line.
    //  - top line is perpendicular to center line and goes through the
    //    projected point closest to eyePos
    //  - base line is perpendicular to center line and goes through the
    //    projected point farthest from eyePos

    Pnt2r tlBase;
    Pnt2r blBase;
    Real  topDist  = TypeTraits<Real>::getMax();
    Real  baseDist = TypeTraits<Real>::getMin();

    std::vector<Pnt3r>::const_iterator ivCIt  = intVerts.begin();
    std::vector<Pnt3r>::const_iterator ivCEnd = intVerts.end  ();

    for(; ivCIt != ivCEnd; ++ivCIt)
    {
        Pnt2r ivPnt((*ivCIt)[0], (*ivCIt)[1]);
        
        ivPnt = ivPnt - (clNorm.dot(ivPnt) - clDist) * clNorm;

        Real dist = (ivPnt - eyePos2D).squareLength();
        dist *= osgSgn(clDir.dot(ivPnt - eyePos2D));

        if(dist < topDist)
        {
            topDist = dist;
            tlBase  = ivPnt;
        }
        
        if(dist > baseDist)
        {
            baseDist = dist;
            blBase   = ivPnt;
        }
    }

    topDist  = osgSgn(topDist ) * osgSqrt(osgAbs(topDist ));
    baseDist = osgSgn(baseDist) * osgSqrt(osgAbs(baseDist));

    // compute side lines:
    //  - choose focusPnt (everything closer to the near plane is mapped to
    //    80% of the shadow map) - here we just take the point at 0.7 between
    //    tlBase and blBase
    //  - find a point (trapTip, q in the paper) on center line such that
    //    focusPnt is mapped the 80% line in the shadow map
    //  - choose lines through q that touch the convex hull of intVerts

    ivCIt  = intVerts.begin();
    ivCEnd = intVerts.end  ();

//    Real  centerDist = (intCenter2D - eyePos2D).length();

    Real  lambda     = baseDist   - topDist;
    Real  delta      = 0.5f * lambda;
    Real  xi         = -0.6f;
    Real  eta        = ((lambda * delta) + (lambda * delta * xi)) /
                       (lambda - 2.f * delta - lambda * xi      );
    Pnt2r trapTip    = tlBase - (eta   * clDir);
    Pnt2r focusPnt   = tlBase + (delta * clDir);

    // on both sides of the center line, find the point in intVerts that has
    // the smallest |cosine| (largest angle) between clDir and the vector
    // from trapTip to intVerts[i]
    Pnt2r posPnt;
    Real  posCos = 1.f;
    Pnt2r negPnt;
    Real  negCos = 1.f;

    for(UInt32 i = 0; ivCIt != ivCEnd; ++ivCIt, ++i)
    {
        Pnt2r ivPnt((*ivCIt)[0], (*ivCIt)[1]);
   
        Vec2r v       = ivPnt - trapTip;
        v.normalize();
        Real  currCos = osgAbs(clDir.dot(v));

        if(clNorm.dot(v) >= 0.f)
        {
            if(currCos <= posCos)
            {
                posPnt = ivPnt;
                posCos = currCos;
            }
        }
        else
        {
            if(currCos <= negCos)
            {
                negPnt = ivPnt;
                negCos = currCos;
            }
        }
    }

    // compute corners of trapezoid:
    Pnt2r trapVerts [4];
    Pnt2r extraVerts[2];
    Real  posTan = osgTan(osgACos(posCos));
    Real  negTan = osgTan(osgACos(negCos));

    trapVerts[0] = blBase - ((eta + lambda) * negTan * clNorm);
    trapVerts[1] = blBase + ((eta + lambda) * posTan * clNorm);
    trapVerts[2] = tlBase + ( eta           * posTan * clNorm);
    trapVerts[3] = tlBase - ( eta           * negTan * clNorm);

    extraVerts[0] = focusPnt + ((eta + delta) * posTan * clNorm);
    extraVerts[1] = focusPnt - ((eta + delta) * negTan * clNorm);

    // == xform trapezoid to unit square ==

    // M1 = R * T1  -- translate center of top line to origin and rotate
    Vec2r u = 0.5f * (trapVerts[2].subZero() + trapVerts[3].subZero());
    Vec2r v =         trapVerts[3]           - trapVerts[2];
    v.normalize();

    matNT.setValue( v[0],  v[1], 0.f, -(u[0] * v[0] + u[1] * v[1]),
                   -v[1],  v[0], 0.f,  (u[0] * v[1] - u[1] * v[0]),
                    0.f,   0.f,  1.f,  0.f,
                    0.f,   0.f,  0.f,  1.f);

    // M2 = T2 * M1  -- translate tip to origin
    matNT[3][0] = - (matNT[0][0] * trapTip[0] + matNT[1][0] * trapTip[1]);
    matNT[3][1] = - (matNT[0][1] * trapTip[0] + matNT[1][1] * trapTip[1]);

    // M3 = H * M2  -- shear to make it symmetric wrt to the y axis
    //    v = M2 * u
    v[0] = matNT[0][0] * u[0] + matNT[1][0] * u[1] + matNT[3][0];
    v[1] = matNT[0][1] * u[0] + matNT[1][1] * u[1] + matNT[3][1];
  
    Real a = - v[0] / v[1];
    
    //    matNT[*][0] : = mat[*][0] + a * mat[*][1]
    matNT[0][0] += a * matNT[0][1];
    matNT[1][0] += a * matNT[1][1];
    matNT[2][0] += a * matNT[2][1];
    matNT[3][0] += a * matNT[3][1];

    // M4 = S1 * M3  -- scale to make sidelines orthogonal and 
    //                  top line is at y == 1
    //    v = 1 / (M3 * t2)
    v[0] = 1.f / (matNT[0][0] * trapVerts[2][0] + matNT[1][0] * trapVerts[2][1] + matNT[3][0]);
    v[1] = 1.f / (matNT[0][1] * trapVerts[2][0] + matNT[1][1] * trapVerts[2][1] + matNT[3][1]);

    matNT[0][0] *= v[0];    matNT[0][1] *= v[1];
    matNT[1][0] *= v[0];    matNT[1][1] *= v[1];
    matNT[2][0] *= v[0];    matNT[2][1] *= v[1];
    matNT[3][0] *= v[0];    matNT[3][1] *= v[1];
    
    // M5 = N * M4  -- turn trapezoid into rectangle
    matNT[0][3] = matNT[0][1];
    matNT[1][3] = matNT[1][1];
    matNT[2][3] = matNT[2][1];
    matNT[3][3] = matNT[3][1];
    matNT[3][1] += 1.f;

    // M6 = T3 * M5  -- translate center to origin
    //    u = "M5 * t0"  - only y and w coordinates
    //    v = "M5 * t2"  - only y and w coordinates
    u[0] = matNT[0][1] * trapVerts[0][0] + matNT[1][1] * trapVerts[0][1] + matNT[3][1];
    u[1] = matNT[0][3] * trapVerts[0][0] + matNT[1][3] * trapVerts[0][1] + matNT[3][3];
    v[0] = matNT[0][1] * trapVerts[2][0] + matNT[1][1] * trapVerts[2][1] + matNT[3][1];
    v[1] = matNT[0][3] * trapVerts[2][0] + matNT[1][3] * trapVerts[2][1] + matNT[3][3];
    a    = - 0.5f * (u[0] / u[1] + v[0] / v[1]);

    matNT[0][1] += matNT[0][3] * a;
    matNT[1][1] += matNT[1][3] * a;
    matNT[2][1] += matNT[2][3] * a;
    matNT[3][1] += matNT[3][3] * a;

    // M7 = S2 * M6  -- scale to fill -1/+1 square
    //    u = "M6 * t0"  - only y and w coordinates
    u[0] = matNT[0][1] * trapVerts[0][0] + matNT[1][1] * trapVerts[0][1] + matNT[3][1];
    u[1] = matNT[0][3] * trapVerts[0][0] + matNT[1][3] * trapVerts[0][1] + matNT[3][3];
    a    = -u[1] / u[0];

    matNT[0][1] *= a;
    matNT[1][1] *= a;
    matNT[2][1] *= a;
    matNT[3][1] *= a;

    return true;
}
void FrustumVolume::setPlanes(const Matrix &objectClipMat)
{
    Vec4f  planeEquation[6];
    Real32 vectorLength;
    Vec3f  normal;

    planeEquation[0][0] = objectClipMat[0][3] - objectClipMat[0][0];
    planeEquation[0][1] = objectClipMat[1][3] - objectClipMat[1][0];
    planeEquation[0][2] = objectClipMat[2][3] - objectClipMat[2][0];
    planeEquation[0][3] = objectClipMat[3][3] - objectClipMat[3][0];

    planeEquation[1][0] = objectClipMat[0][3] + objectClipMat[0][0];
    planeEquation[1][1] = objectClipMat[1][3] + objectClipMat[1][0];
    planeEquation[1][2] = objectClipMat[2][3] + objectClipMat[2][0];
    planeEquation[1][3] = objectClipMat[3][3] + objectClipMat[3][0];

    planeEquation[2][0] = objectClipMat[0][3] + objectClipMat[0][1];
    planeEquation[2][1] = objectClipMat[1][3] + objectClipMat[1][1];
    planeEquation[2][2] = objectClipMat[2][3] + objectClipMat[2][1];
    planeEquation[2][3] = objectClipMat[3][3] + objectClipMat[3][1];

    planeEquation[3][0] = objectClipMat[0][3] - objectClipMat[0][1];
    planeEquation[3][1] = objectClipMat[1][3] - objectClipMat[1][1];
    planeEquation[3][2] = objectClipMat[2][3] - objectClipMat[2][1];
    planeEquation[3][3] = objectClipMat[3][3] - objectClipMat[3][1];

    planeEquation[4][0] = objectClipMat[0][3] + objectClipMat[0][2];
    planeEquation[4][1] = objectClipMat[1][3] + objectClipMat[1][2];
    planeEquation[4][2] = objectClipMat[2][3] + objectClipMat[2][2];
    planeEquation[4][3] = objectClipMat[3][3] + objectClipMat[3][2];

    planeEquation[5][0] = objectClipMat[0][3] - objectClipMat[0][2];
    planeEquation[5][1] = objectClipMat[1][3] - objectClipMat[1][2];
    planeEquation[5][2] = objectClipMat[2][3] - objectClipMat[2][2];
    planeEquation[5][3] = objectClipMat[3][3] - objectClipMat[3][2];

    for(Int32  i = 0; i < 6; i++) 
    {
        vectorLength = 
            osgSqrt(planeEquation[i][0] * planeEquation[i][0] +
                    planeEquation[i][1] * planeEquation[i][1] +
                    planeEquation[i][2] * planeEquation[i][2]);
 
        planeEquation[i][0] /=  vectorLength;
        planeEquation[i][1] /=  vectorLength;
        planeEquation[i][2] /=  vectorLength;
        planeEquation[i][3] /= -vectorLength;
    }

  // right
  _planeVec[3].set(planeEquation[0]);

  // left
  _planeVec[2].set(planeEquation[1]);

  // bottom
  _planeVec[5].set(planeEquation[2]);

  // top
  _planeVec[4].set(planeEquation[3]);

  // near
  _planeVec[0].set(planeEquation[4]);

  // far
  _planeVec[1].set(planeEquation[5]);
}
void BbqGeoRefdTerrainRenderer<HeightType, 
                               HeightDeltaType,
                               TextureType    >::render(      

                                        BbqTerrNode      *rootNode, 
                                  const BbqRenderOptions &options )
{
    _oStatistics.nodeCount       = 0;
    _oStatistics.triangleCount   = 0;
    
    traversalStack_.push_back(rootNode);
    
    // activate the shader:
//    glUseProgramObjectARB( terrainShader_.getProgramHandle() );
//    terrainShader_.activate(options.pDrawEnv);
//    fprintf(stderr, "Frame start\n");

    while(!traversalStack_.empty())
    {
        BbqTerrNode *node = traversalStack_.back();

        assert(node);
        
        traversalStack_.pop_back();
        
#ifdef GV_CHECK
        // cull this node->.
        if( options.enableFrustumCulling && 
            !isIntersecting( options.frustum, node->boundingBox ) )
        {
            // not visible at all
            _oStatistics.culledNodeCount++;
            continue;
        }
#endif
        
        const Real32 detailFactor = options.screenSpaceError;
        
        //todo: i need to use the distance to 

        Pnt3f bboxCenter;
        Vec3f dist;

        node->boundingBox.getCenter(bboxCenter);
        
/*
        fprintf(stderr, "%d %f %f %f\n",
                node->id,
                bboxCenter[0],
                bboxCenter[1],
                bboxCenter[2]);
 */

        dist = options.viewerpos - bboxCenter;

        const float distance = osgMax(dist.length(), 0.001f);

//        const float distance = osgMax( 
//            getMagnitude( options.frustum.getPosition() - 
//                          node->boundingBox.getCenter() ), 0.001f );
        
        //// todo: instead of the size of the node, use the maximum error bound

        Vec3f bboxSize;

        node->boundingBox.getSize(bboxSize);

//        const float nodeSize = node->boundingBox.getSize().x;
        const float nodeSize = bboxSize.x();
        
//        const float fovY = options.frustum.getFovY();
        const float fovY = options.fovy;
        const float screenResolution = float( options.screenSize.y() ) / fovY;
        
#if 0 //Unused
        const float nodeError = screenResolution * 
            ( ( nodeSize / float( _oDatabaseInfo.heightTileSize ) ) / distance );

        const float objectSpaceHeightError = 
            float( node->maxHeightError ) / 
            32767.0f * _oDatabaseInfo.heightScale + _oDatabaseInfo.heightOffset;
//            65535.0f * _oDatabaseInfo.heightScale + _oDatabaseInfo.heightOffset;

        const float screenSpaceHeightError = 
            ( objectSpaceHeightError / distance ) * screenResolution;

        const float screenFactor = 
            float( options.screenSize.y() ) / ( 2.0f * tanf( fovY / 2.0f ) );

        const float screenSpaceHeightError2 = 
            ( objectSpaceHeightError / distance ) * screenFactor;
        
        const float switchDistance2 =
            ( objectSpaceHeightError / detailFactor ) * screenFactor;
#endif

        // todo: geomorphing geht noch nicht richtig...
        
        Vec3f disp = options.viewerpos - bboxCenter;
//            options.frustum.getPosition() - node->boundingBox.getCenter();

//        Vec3f extent = node->boundingBox.getSize();
        Vec3f extent;

        node->boundingBox.getSize(extent);
            
        disp[0] = osgMax( 0.0f, fabsf( disp.x() ) - extent.x() );
        disp[1] = osgMax( 0.0f, fabsf( disp.y() ) - extent.y() );
        disp[2] = osgMax( 0.0f, fabsf( disp.z() ) - extent.z() );
        
        //  disp.y = 0; // for debugging
        
//        float d = 0;
//        d = osgSqrt( dot( disp, disp ) );
//        d = 
              osgSqrt( disp.dot(disp) );
        
        //  float 
        //      const float tan_half_FOV = tanf(0.5f * horizontal_FOV_degrees
        //      * (float) M_PI / 180.0f); 
        //
        //  const float K = screen_width_pixels / tan_half_FOV;
        
        //  // distance_LODmax is the distance below which we need to be
        //  // at the maximum LOD.  It's used in compute_lod(), which is
        //  // called by the chunks during update().
        //  m_distance_LODmax = ;

        //  return fmax(1, d / (objectSpaceHeightError / detailFactor) * K);
        //}
        
        //float switchDistance2 = ( objectSpaceHeightError / detailFactor ) *
        //screenFactor; 

        //float switchDistance = ( objectSpaceHeightError / detailFactor ) *
        //screenFactor; 

        float switchDistance = 
            ( nodeSize / float( _oDatabaseInfo.heightTileSize ) ) / 
            detailFactor * screenResolution;
        
        float geomorphStartDistance = switchDistance + 145.0f;
        
        //const bool hasEnoughDetail = nodeError < detailFactor;
        

/*
        fprintf(stderr, "%f | %f\n", 
                distance,
                geomorphStartDistance);
 */


        if( node->isLeafNode() || distance > geomorphStartDistance )
        {
            // render the node:
#ifndef GV_TEST
            Inherited::setGeoMorphingFactor( node );
#else
            _oTerrainShader.setUniform( "geoMorphFactor", 
                                        options.geoMorphFactor );
#endif

            renderNodeVbo( node, options.showSkirts, options );
            
            if( options.showBoundingBoxes )
            {
                glColor3f( 0, 0, 1 );
                this->renderBoundingBox( node->boundingBox, options );
            }
            
            if( options.showSwitchDistance )
            {
//                Pnt3f bboxCenter;

                node->boundingBox.getCenter(bboxCenter);

                glColor3f( 0, 1, 0 );
                Inherited::renderSphere(bboxCenter , switchDistance, options );
            }
        }
        else
        {
            // compute the geomorphing factor:
            //const float innerSwitchDistance = switchDistance -
            //switchDistance / 4.0f; 

            node->geoMorphingFactor = 
                clamp( 1.0f - ( switchDistance - distance ) / 
                       ( geomorphStartDistance - switchDistance ), 0.0f, 1.0f );
            //node->geoMorphingFactor = 1.0f;
            
            // push the child nodes:
            
            // todo: push the nearest child last.. (to get a rough front to
            // back rendering order) 

            static int order[ 4 ] = { 0, 1, 2, 3 };
            //static float dist[ 4 ];
            
            //if( options.sortChildren )
            //{
            //  for( int i = 0; i < 4; ++i )
            //  {
            //      dist[ i ] = getMagnitude( node->children[ i
            //]->boundingBox.getCenter() - options.frustum.getPosition() ); 
            
            //      for( int j = 0; j < i; ++j )
            //      {
            //          if( dist[ i ] <
            //      }
            //  }
            //}
            
            traversalStack_.push_back( node->children[ order[ 0 ] ] );
            traversalStack_.push_back( node->children[ order[ 1 ] ] );
            traversalStack_.push_back( node->children[ order[ 2 ] ] );
            traversalStack_.push_back( node->children[ order[ 3 ] ] );
        }
    }


    glColor3f(1.f, 0.f, 0.f);
    glBegin(GL_QUADS);
    {
        glVertex3f(rootNode->boundingBox.getMin().x(),
                   0.f,
                   rootNode->boundingBox.getMin().z());
        glVertex3f(rootNode->boundingBox.getMax().x(),
                   0.f,
                   rootNode->boundingBox.getMin().z());
        glVertex3f(rootNode->boundingBox.getMax().x(),
                   0.f,
                   rootNode->boundingBox.getMax().z());
        glVertex3f(rootNode->boundingBox.getMin().x(),
                   0.f,
                   rootNode->boundingBox.getMax().z());
    }
    glEnd();


    static bool dumpBox = false;

    if(dumpBox == false)
    {
        fprintf(stderr, "%f %f | %f %f\n",
                rootNode->boundingBox.getMin().x(),
                rootNode->boundingBox.getMin().z(),
                rootNode->boundingBox.getMax().x(),
                rootNode->boundingBox.getMax().z());

        dumpBox = true;
    }


//    glUseProgramObjectARB( 0 );
//    _oTerrainShader.deactivate(options.pDrawEnv);
}
Ejemplo n.º 8
0
bool Line::intersect(const CylinderVolume &cyl, 
                           Real           &enter,  
                           Real           &exit ) const
{
    Real  radius = cyl.getRadius();

    Vec3r adir;
    Vec3r o_adir;
    Pnt3r apos;

    cyl.getAxis(apos, adir);

    o_adir = adir;
    adir.normalize();

    bool isect;

    Real  ln;
    Real  dl;
    Vec3r RC;
    Vec3r n;
    Vec3r D;

    RC = _pos - apos;

    n  = _dir.cross (adir);
    ln =  n  .length(    );

    if(ln == 0.f)    // IntersectionLine is parallel to CylinderAxis
    {
        D  = RC - (RC.dot(adir)) * adir;
        dl = D.length();

        if(dl <= radius)   // line lies in cylinder
        {
            enter = 0.f;
            exit  = Inf;
        }
        else
        {
            return false;
        }
    }
    else
    {
        n.normalize();

        dl    = osgAbs(RC.dot(n));        //shortest distance
        isect = (dl <= radius);

        if(isect)
        {                 // if ray hits cylinder
            Real  t;
            Real  s;
            Vec3r O;

            O = RC.cross(adir);
            t = - (O.dot(n)) / ln;
            O = n.cross(adir);

            O.normalize();

            s = osgAbs (
                (osgSqrt ((radius * radius) - (dl * dl))) / (_dir.dot(O)));

            exit = t + s;

            if(exit < 0.f)
                return false;

            enter = t - s;

            if(enter < 0.f)
                enter = 0.f;
        }
        else
        {
            return false;
        }
    }

    Real t;

    Plane bottom(-adir, apos);

    if(bottom.intersect(*this, t))
    {
        if(bottom.isInHalfSpace(_pos))
        {
            if(t > enter) 
                enter = t;
        }
        else
        {
            if(t < exit) 
                exit = t;
        }
    }
    else
    {
        if(bottom.isInHalfSpace(_pos))
            return false;
    }
    
    Plane top(adir, apos + o_adir);

    if(top.intersect(*this, t))
    {
        if(top.isInHalfSpace(_pos))
        {
            if(t > enter)
                enter = t;
        }
        else
        {
            if(t < exit)
                exit = t;
        }
    }
    else
    {
        if(top.isInHalfSpace(_pos))
            return false;
    }

    return (enter < exit);
}