Пример #1
0
//----------------------------------------------------------------------------
Vector3f BouncingTetrahedra::ClosestEdge (const Vector3f* vertices,
        const Vector3f& closest, Vector3f& otherVertex)
{
	// Find the edge of the tetrahedra nearest to the contact point.  If
	// otherVertexB is ZERO, then ClosestEdge skips the calculation of an
	// unneeded other-vertex for the tetrahedron B.

	Vector3f closestEdge;
	float minDist = Mathf::MAX_REAL;
	for (int i = 0; i < 3; ++i)
	{
		for (int j = i + 1; j < 4; ++j)
		{
			Vector3f edge = vertices[j] - vertices[i];
			Vector3f diff = closest - vertices[i];
			float DdE = diff.Dot(edge);
			float edgeLength = edge.Length();
			float diffLength = diff.Length();
			float dist = Mathf::FAbs(DdE/(edgeLength*diffLength) - 1.0f);
			if (dist < minDist)
			{
				minDist = dist;
				closestEdge = edge;
				for (int k = 0; otherVertex != Vector3f::ZERO && k < 3; ++k)
				{
					if (k != i && k != j)
					{
						otherVertex = vertices[k];
						continue;
					}
				}
			}
		}
	}
	return closestEdge;
}
Пример #2
0
void BoundingSphere::Encapsulate(const Vector3f &v)
{
	// TODO : check if this is correct
	Vector3f diff = v - center;
	float	dist = diff.Dot(diff);

	if (dist > radiusSq)
	{
		Vector3f diff2	= diff.Normalized() * radius;
		Vector3f delta	= 0.5f * (diff - diff2);
		center		   += delta;
		radius	       += delta.Length();
		radiusSq		= radius*radius;
	}
}
Пример #3
0
void Viewer3D::Rotate(int winX, int winY)
{
    to.x = winX * view.fw - 1.0f;
    to.y = winY * view.fh - 1.0f;

    Vector3f delta = from - to;
    delta.y = -delta.y;
    float length = delta.Length();
    if (length < 1e-5) return;
    delta /= length;

    float rotDist = 0.5f * max(view.w, view.h) * view.s;
    float angle = length / rotDist * 180.0f;
    Vector3f axis = Vector3f(delta.y, -delta.x, 0.0f);

    qRotation = Quaternion(axis, angle) * qRotation;
    from = to;
    changed = true;
}
Пример #4
0
void TrackballCamera::Rotate(int winX, int winY)
{
	to.x = winX * view.fw - 1.0f;
	to.y = winY * view.fh - 1.0f;

	Vector3f delta = to - from;
	float length = delta.Length();
	if (length < 1e-5) return;
	delta /= length;

	float rotDist = isConstSpeed ? constSpeedValue : 
		0.5f * max(view.w, view.h) * view.s;
	float angle = length / rotDist * 180.0f;
	Vector3f axis = Vector3f(delta.y, delta.x, 0.0f);

	qRotation = Quaternion(axis, angle) * qRotation;
	from = to;
	changed = true;
}
        // This is a simple predictive filter based only on extrapolating the smoothed, current angular velocity.
        // Note that both QP (the predicted future orientation) and Q (the current orientation) are both maintained.
Quatf       SensorFusion::GetPredictedOrientation()
{		
	Lock::Locker lockScope(Handler.GetHandlerLock());
	Quatf qP = QUncorrected;
	if (EnablePrediction) {
#if 1
	    Vector3f angVelF  = FAngV.SavitzkyGolaySmooth8();
        float    angVelFL = angVelF.Length();
            
        if (angVelFL > 0.001f)
        {
            Vector3f    rotAxisP      = angVelF / angVelFL;  
            float       halfRotAngleP = angVelFL * PredictionDT * 0.5f;
            float       sinaHRAP      = sin(halfRotAngleP);
		    Quatf       deltaQP(rotAxisP.x*sinaHRAP, rotAxisP.y*sinaHRAP,
                                rotAxisP.z*sinaHRAP, cos(halfRotAngleP));
            qP = QUncorrected * deltaQP;
        }
#else
        Quatd qpd = Quatd(Q.x,Q.y,Q.z,Q.w);
        int predictionStages = (int)(PredictionDT / DeltaT);
        Vector3f  aa = FAngV.SavitzkyGolayDerivative12();
        Vector3d  aad     = Vector3d(aa.x,aa.y,aa.z);
        Vector3f angVelF  = FAngV.SavitzkyGolaySmooth8();
        Vector3d  avkd    = Vector3d(angVelF.x,angVelF.y,angVelF.z);
        for (int i = 0; i < predictionStages; i++)
        {
            double angVelLengthd = avkd.Length();
            Vector3d rotAxisd      = avkd / angVelLengthd;
            double halfRotAngled = angVelLengthd * DeltaT * 0.5;
            double sinHRAd       = sin(halfRotAngled);
            Quatd  deltaQd       = Quatd(rotAxisd.x*sinHRAd, rotAxisd.y*sinHRAd, rotAxisd.z*sinHRAd,
                                         cos(halfRotAngled));
            qpd =  qpd * deltaQd;
            // Update vel
            avkd += aad;
        }
        qP = Quatf((float)qpd.x,(float)qpd.y,(float)qpd.z,(float)qpd.w);
#endif
	}
    return qP;
}    
Spectrum SpecularReflection::Sample_f( const Vector3f& wo , const Vector3f& n , Vector3f* wi , const Point2f& samplePoint , float* pdf , bool& bNoOccur ) const
{
	*wi = Normalize( 2 * Dot( wo , n ) / n.Length() * Normalize( n ) - wo );

	*pdf = 1.0;

	Spectrum F = fresnel->Evalute( wo * n );

	// 经验设定
	// 参考该问题的答案:http://www.opengpu.org/forum.php?mod=viewthread&tid=18099&extra=page%3D1
	float P = 0.25f + 0.5f * F[0];

	if( RNG::Get().GetFloat() > /*F[0]*/P )
	{
		// 无反射
		bNoOccur = true;
		return Spectrum( 0 );
	}

	return F / P * R / AbsDot( *wi , n );
}
Пример #7
0
void FPSController::UpdateStatic(float deltaTime)
{
    if (mBody.get() == 0)
        {
            return;
        }

    Matrix matrix;
    Matrix fwd;
    Vector3f vec;
    PrepareUpdate(matrix, fwd, vec);

    mBody->SetRotation(matrix);

    Vector3f bodyVel = mBody->GetVelocity() + (deltaTime * vec * STATIC_ACCELERATION);
    bodyVel *= STATIC_VELOCITY_DECAY;

    Vector3f velocity =
        vec.y() * fwd.Up() +
        vec.x() * fwd.Right() +
        vec.z() * Vector3f(0,0,1);

    matrix.Pos() = mBody->GetPosition() + velocity * bodyVel.Length();

    mBody->SetPosition(matrix.Pos());
    mBody->SetVelocity(velocity);

    shared_ptr<BaseNode> bodyParent = shared_static_cast<BaseNode>
        (mBody->GetParent().lock());

    if (bodyParent.get() != 0)
        {
            mBody->SynchronizeParent();
            bodyParent->UpdateHierarchy();
        }

    mHAngleDelta = 0.0;
    mVAngleDelta = 0.0;
}
Пример #8
0
void Explosion::Update(float dt) {
    this->elapsedLifetime -= dt;
    if (this->elapsedLifetime < 0.0f) {
        this->exists = false;
        std::cout << "КОНЕЦ ВЗРЫВА!\n";
    }

    // Обработка взрыва
    //float currRadius = ((totalLifetime - elapsedLifetime) / totalLifetime) * this->maxRadius;

    for (int i = 0; i < owner->GetParticleSystem()->GetParticlesCount(); i++) {
        ParticleHandle<ParticleInfo> blockParticle = owner->GetParticleSystem()->GetParticle(size_t(i));

        Vector3f distance = blockParticle.GetPos() - this->pos;
        //if (distance.Length() <= currRadius) {
        //this->force = desc.force;
        //float force = 1.0f;
        float a = distance.Length();
        float offset = force / (a * a * a);
        Vector3f resultAcceleration = blockParticle.GetAcceleration() + offset * distance.GetNorm();
        blockParticle.SetAcceleration(resultAcceleration);
        //}
    }
}
Пример #9
0
//  A predictive filter based on extrapolating the smoothed, current angular velocity
Quatf SensorFusion::GetPredictedOrientation(float pdt)
{		
    Lock::Locker lockScope(Handler.GetHandlerLock());
    Quatf        qP = Q;
    
    if (EnablePrediction)
    {
        // This method assumes a constant angular velocity
        Vector3f angVelF  = FAngV.SavitzkyGolaySmooth8();
        float    angVelFL = angVelF.Length();

        // Force back to raw measurement
        angVelF  = AngV;
        angVelFL = AngV.Length();

        // Dynamic prediction interval: Based on angular velocity to reduce vibration
        const float minPdt   = 0.001f;
        const float slopePdt = 0.1f;
        float       newpdt   = pdt;
        float       tpdt     = minPdt + slopePdt * angVelFL;
        if (tpdt < pdt)
            newpdt = tpdt;
        //LogText("PredictonDTs: %d\n",(int)(newpdt / PredictionTimeIncrement + 0.5f));

        if (angVelFL > 0.001f)
        {
            Vector3f    rotAxisP      = angVelF / angVelFL;  
            float       halfRotAngleP = angVelFL * newpdt * 0.5f;
            float       sinaHRAP      = sin(halfRotAngleP);
            Quatf       deltaQP(rotAxisP.x*sinaHRAP, rotAxisP.y*sinaHRAP,
                                rotAxisP.z*sinaHRAP, cos(halfRotAngleP));
            qP = Q * deltaQP;
        }
    }
    return qP;
}    
Пример #10
0
 void DebugRenderer::AddLine(const Vector3f& a, const Vector3f& b, const Color& color, Lifespan lifespan) {
     Vector3f dir = b - a;
     AddLine(a, dir, dir.Length(), color, lifespan);
 }
Пример #11
0
Vector3f lzmath::Normalize(const Vector3f &v)
{
	return (v /  v.Length());
}
Пример #12
0
void SensorFusion::handleMessage(const MessageBodyFrame& msg)
{
    if (msg.Type != Message_BodyFrame || !IsMotionTrackingEnabled())
        return;

    // Put the sensor readings into convenient local variables
    Vector3f gyro  = msg.RotationRate; 
    Vector3f accel = msg.Acceleration;
    Vector3f mag   = msg.MagneticField;

    // Insert current sensor data into filter history
    FRawMag.AddElement(mag);
    FAngV.AddElement(gyro);

    // Apply the calibration parameters to raw mag
    Vector3f calMag = MagCalibrated ? GetCalibratedMagValue(FRawMag.Mean()) : FRawMag.Mean();

    // Set variables accessible through the class API
    DeltaT = msg.TimeDelta;
    AngV   = gyro;
    A      = accel;
    RawMag = mag;  
    CalMag = calMag;

    // Keep track of time
    Stage++;
    RunningTime += DeltaT;

    // Small preprocessing
    Quatf Qinv = Q.Inverted();
    Vector3f up = Qinv.Rotate(Vector3f(0, 1, 0));

    Vector3f gyroCorrected = gyro;

    // Apply integral term
    // All the corrections are stored in the Simultaneous Orthogonal Rotations Angle representation,
    // which allows to combine and scale them by just addition and multiplication
    if (EnableGravity || EnableYawCorrection)
        gyroCorrected -= GyroOffset;

    if (EnableGravity)
    {
        const float spikeThreshold = 0.01f;
        const float gravityThreshold = 0.1f;
        float proportionalGain     = 5 * Gain; // Gain parameter should be removed in a future release
        float integralGain         = 0.0125f;

        Vector3f tiltCorrection = SensorFusion_ComputeCorrection(accel, up);

        if (Stage > 5)
        {
            // Spike detection
            float tiltAngle = up.Angle(accel);
            TiltAngleFilter.AddElement(tiltAngle);
            if (tiltAngle > TiltAngleFilter.Mean() + spikeThreshold)
                proportionalGain = integralGain = 0;
            // Acceleration detection
            const float gravity = 9.8f;
            if (fabs(accel.Length() / gravity - 1) > gravityThreshold)
                integralGain = 0;
        }
        else // Apply full correction at the startup
        {
            proportionalGain = 1 / DeltaT;
            integralGain = 0;
        }

        gyroCorrected += (tiltCorrection * proportionalGain);
        GyroOffset -= (tiltCorrection * integralGain * DeltaT);
    }

    if (EnableYawCorrection && MagCalibrated && RunningTime > 2.0f)
    {
        const float maxMagRefDist = 0.1f;
        const float maxTiltError = 0.05f;
        float proportionalGain   = 0.01f;
        float integralGain       = 0.0005f;

        // Update the reference point if needed
        if (MagRefIdx < 0 || calMag.Distance(MagRefsInBodyFrame[MagRefIdx]) > maxMagRefDist)
        {
            // Delete a bad point
            if (MagRefIdx >= 0 && MagRefScore < 0)
            {
                MagNumReferences--;
                MagRefsInBodyFrame[MagRefIdx] = MagRefsInBodyFrame[MagNumReferences];
                MagRefsInWorldFrame[MagRefIdx] = MagRefsInWorldFrame[MagNumReferences];
            }
            // Find a new one
            MagRefIdx = -1;
            MagRefScore = 1000;
            float bestDist = maxMagRefDist;
            for (int i = 0; i < MagNumReferences; i++)
            {
                float dist = calMag.Distance(MagRefsInBodyFrame[i]);
                if (bestDist > dist)
                {
                    bestDist = dist;
                    MagRefIdx = i;
                }
            }
            // Create one if needed
            if (MagRefIdx < 0 && MagNumReferences < MagMaxReferences)
            {
                MagRefIdx = MagNumReferences;
                MagRefsInBodyFrame[MagRefIdx] = calMag;
                MagRefsInWorldFrame[MagRefIdx] = Q.Rotate(calMag).Normalized();
                MagNumReferences++;
            }
        }

        if (MagRefIdx >= 0)
        {
            Vector3f magEstimated = Qinv.Rotate(MagRefsInWorldFrame[MagRefIdx]);
            Vector3f magMeasured  = calMag.Normalized();

            // Correction is computed in the horizontal plane (in the world frame)
            Vector3f yawCorrection = SensorFusion_ComputeCorrection(magMeasured.ProjectToPlane(up), 
                                                                    magEstimated.ProjectToPlane(up));

            if (fabs(up.Dot(magEstimated - magMeasured)) < maxTiltError)
            {
                MagRefScore += 2;
            }
            else // If the vertical angle is wrong, decrease the score
            {
                MagRefScore -= 1;
                proportionalGain = integralGain = 0;
            }
            gyroCorrected += (yawCorrection * proportionalGain);
            GyroOffset -= (yawCorrection * integralGain * DeltaT);
        }
    }

    // Update the orientation quaternion based on the corrected angular velocity vector
    Q = Q * Quatf(gyroCorrected, gyroCorrected.Length() * DeltaT);

    // The quaternion magnitude may slowly drift due to numerical error,
    // so it is periodically normalized.
    if (Stage % 500 == 0)
        Q.Normalize();
}
Пример #13
0
//----------------------------------------------------------------------------
void GelatinCube::CreateSprings ()
{
    // The inner 4-by-4-by-4 particles are used as the control points of a
    // B-spline volume.  The outer layer of particles are immovable to
    // prevent the cuboid from collapsing into itself.
    int iSlices = 6;
    int iRows = 6;
    int iCols = 6;

    // Viscous forces applied.  If you set viscosity to zero, the cuboid
    // wiggles indefinitely since there is no dissipation of energy.  If
    // the viscosity is set to a positive value, the oscillations eventually
    // stop.  The length of time to steady state is inversely proportional
    // to the viscosity.
#ifdef _DEBUG
    float fStep = 0.1f;
#else
    float fStep = 0.01f;  // simulation needs to run slower in release mode
#endif
    float fViscosity = 0.01f;
    m_pkModule = new PhysicsModule(iSlices,iRows,iCols,fStep,fViscosity);

    // The initial cuboid is axis-aligned.  The outer shell is immovable.
    // All other masses are constant.
    float fSFactor = 1.0f/(float)(iSlices-1);
    float fRFactor = 1.0f/(float)(iRows-1);
    float fCFactor = 1.0f/(float)(iCols-1);
    int iSlice, iRow, iCol;
    for (iSlice = 0; iSlice < iSlices; iSlice++)
    {
        for (iRow = 0; iRow < iRows; iRow++)
        {
            for (iCol = 0; iCol < iCols; iCol++)
            {
                m_pkModule->Position(iSlice,iRow,iCol) =
                    Vector3f(iCol*fCFactor,iRow*fRFactor,iSlice*fSFactor);

                if ( 1 <= iSlice && iSlice < iSlices-1
                &&   1 <= iRow && iRow < iRows-1
                &&   1 <= iCol && iCol < iCols-1 )
                {
                    m_pkModule->SetMass(iSlice,iRow,iCol,1.0f);
                    m_pkModule->Velocity(iSlice,iRow,iCol) =
                        0.1f*Vector3f(Mathf::SymmetricRandom(),
                        Mathf::SymmetricRandom(),Mathf::SymmetricRandom());
                }
                else
                {
                    m_pkModule->SetMass(iSlice,iRow,iCol,Mathf::MAX_REAL);
                    m_pkModule->Velocity(iSlice,iRow,iCol) = Vector3f::ZERO;
                }
            }
        }
    }

    // springs are at rest in the initial configuration
    const float fConstant = 10.0f;
    Vector3f kDiff;

    for (iSlice = 0; iSlice < iSlices-1; iSlice++)
    {
        for (iRow = 0; iRow < iRows; iRow++)
        {
            for (iCol = 0; iCol < iCols; iCol++)
            {
                m_pkModule->ConstantS(iSlice,iRow,iCol) = fConstant;
                kDiff = m_pkModule->Position(iSlice+1,iRow,iCol) -
                    m_pkModule->Position(iSlice,iRow,iCol);
                m_pkModule->LengthS(iSlice,iRow,iCol) = kDiff.Length();
            }
        }
    }

    for (iSlice = 0; iSlice < iSlices; iSlice++)
    {
        for (iRow = 0; iRow < iRows-1; iRow++)
        {
            for (iCol = 0; iCol < iCols; iCol++)
            {
                m_pkModule->ConstantR(iSlice,iRow,iCol) = fConstant;
                kDiff = m_pkModule->Position(iSlice,iRow+1,iCol) -
                    m_pkModule->Position(iSlice,iRow,iCol);
                m_pkModule->LengthR(iSlice,iRow,iCol) = kDiff.Length();
            }
        }
    }

    for (iSlice = 0; iSlice < iSlices; iSlice++)
    {
        for (iRow = 0; iRow < iRows; iRow++)
        {
            for (iCol = 0; iCol < iCols-1; iCol++)
            {
                m_pkModule->ConstantC(iSlice,iRow,iCol) = fConstant;
                kDiff = m_pkModule->Position(iSlice,iRow,iCol+1) -
                    m_pkModule->Position(iSlice,iRow,iCol);
                m_pkModule->LengthC(iSlice,iRow,iCol) = kDiff.Length();
            }
        }
    }
}
Пример #14
0
//----------------------------------------------------------------------------
void Cloth::CreateSprings ()
{
    // set up the mass-spring system
    int iRows = 8;
    int iCols = 16;
    float fStep = 0.01f;
    Vector3f kGravity(0.0f,0.0f,-1.0f);
    Vector3f kWind(0.5f,0.0f,0.0f);
    float fViscosity = 10.0f;
    float fMaxAmplitude = 2.0f;
    m_pkModule = new PhysicsModule(iRows,iCols,fStep,kGravity,kWind,
        fViscosity,fMaxAmplitude);

    // The top row of the mesh is immovable (infinite mass).  All other
    // masses are constant.
    int iRow, iCol;
    for (iCol = 0; iCol < iCols; iCol++)
        m_pkModule->SetMass(iRows-1,iCol,Mathf::MAX_REAL);
    for (iRow = 0; iRow < iRows-1; iRow++)
    {
        for (iCol = 0; iCol < iCols; iCol++)
            m_pkModule->SetMass(iRow,iCol,1.0f);
    }

    // initial position on a vertical axis-aligned rectangle, zero velocity
    float fRFactor = 1.0f/(float)(iRows-1);
    float fCFactor = 1.0f/(float)(iCols-1);
    for (iRow = 0; iRow < iRows; iRow++)
    {
        for (iCol = 0; iCol < iCols; iCol++)
        {
            m_pkModule->Position(iRow,iCol) =
                Vector3f(iCol*fCFactor,0.0f,iRow*fRFactor);
            m_pkModule->Velocity(iRow,iCol) = Vector3f::ZERO;
        }
    }

    // springs are at rest in the initial configuration
    const float fRConstant = 1000.0f;
    const float fBConstant = 100.0f;
    Vector3f kDiff;
    for (iRow = 0; iRow < iRows; iRow++)
    {
        for (iCol = 0; iCol < iCols-1; iCol++)
        {
            m_pkModule->ConstantC(iRow,iCol) = fRConstant;
            kDiff = m_pkModule->Position(iRow,iCol+1) -
                m_pkModule->Position(iRow,iCol);
            m_pkModule->LengthC(iRow,iCol) = kDiff.Length();
        }
    }

    for (iRow = 0; iRow < iRows-1; iRow++)
    {
        for (iCol = 0; iCol < iCols; iCol++)
        {
            m_pkModule->ConstantR(iRow,iCol) = fBConstant;
            kDiff = m_pkModule->Position(iRow,iCol) -
                m_pkModule->Position(iRow+1,iCol);
            m_pkModule->LengthR(iRow,iCol) = kDiff.Length();
        }
    }
}
void SensorFusion::handleMessage(const MessageBodyFrame& msg)
{
    if (msg.Type != Message_BodyFrame)
        return;
  
    // Put the sensor readings into convenient local variables
    Vector3f angVel    = msg.RotationRate; 
    Vector3f rawAccel  = msg.Acceleration;
    Vector3f mag       = msg.MagneticField;

    // Set variables accessible through the class API
	DeltaT = msg.TimeDelta;
    AngV = msg.RotationRate;
    AngV.y *= YawMult;  // Warning: If YawMult != 1, then AngV is not true angular velocity
    A = rawAccel;

    // Allow external access to uncalibrated magnetometer values
    RawMag = mag;  

    // Apply the calibration parameters to raw mag
    if (HasMagCalibration())
    {
        mag.x += MagCalibrationMatrix.M[0][3];
        mag.y += MagCalibrationMatrix.M[1][3];
        mag.z += MagCalibrationMatrix.M[2][3];
    }

    // Provide external access to calibrated mag values
    // (if the mag is not calibrated, then the raw value is returned)
    CalMag = mag;

    float angVelLength = angVel.Length();
    float accLength    = rawAccel.Length();


    // Acceleration in the world frame (Q is current HMD orientation)
    Vector3f accWorld  = Q.Rotate(rawAccel);

    // Keep track of time
    Stage++;
    float currentTime  = Stage * DeltaT; // Assumes uniform time spacing

    // Insert current sensor data into filter history
    FRawMag.AddElement(RawMag);
    FAccW.AddElement(accWorld);
    FAngV.AddElement(angVel);

    // Update orientation Q based on gyro outputs.  This technique is
    // based on direct properties of the angular velocity vector:
    // Its direction is the current rotation axis, and its magnitude
    // is the rotation rate (rad/sec) about that axis.  Our sensor
    // sampling rate is so fast that we need not worry about integral
    // approximation error (not yet, anyway).
    if (angVelLength > 0.0f)
    {
        Vector3f     rotAxis      = angVel / angVelLength;  
        float        halfRotAngle = angVelLength * DeltaT * 0.5f;
        float        sinHRA       = sin(halfRotAngle);
        Quatf        deltaQ(rotAxis.x*sinHRA, rotAxis.y*sinHRA, rotAxis.z*sinHRA, cos(halfRotAngle));

        Q =  Q * deltaQ;
    }
    
    // The quaternion magnitude may slowly drift due to numerical error,
    // so it is periodically normalized.
    if (Stage % 5000 == 0)
        Q.Normalize();
    
	// Maintain the uncorrected orientation for later use by predictive filtering
	QUncorrected = Q;

    // Perform tilt correction using the accelerometer data. This enables 
    // drift errors in pitch and roll to be corrected. Note that yaw cannot be corrected
    // because the rotation axis is parallel to the gravity vector.
    if (EnableGravity)
    {
        // Correcting for tilt error by using accelerometer data
        const float  gravityEpsilon = 0.4f;
        const float  angVelEpsilon  = 0.1f; // Relatively slow rotation
        const int    tiltPeriod     = 50;   // Req'd time steps of stability
        const float  maxTiltError   = 0.05f;
        const float  minTiltError   = 0.01f;

        // This condition estimates whether the only measured acceleration is due to gravity 
        // (the Rift is not linearly accelerating).  It is often wrong, but tends to average
        // out well over time.
        if ((fabs(accLength - 9.81f) < gravityEpsilon) &&
            (angVelLength < angVelEpsilon))
            TiltCondCount++;
        else
            TiltCondCount = 0;
    
        // After stable measurements have been taken over a sufficiently long period,
        // estimate the amount of tilt error and calculate the tilt axis for later correction.
        if (TiltCondCount >= tiltPeriod)
        {   // Update TiltErrorEstimate
            TiltCondCount = 0;
            // Use an average value to reduce noice (could alternatively use an LPF)
            Vector3f accWMean = FAccW.Mean();
            // Project the acceleration vector into the XZ plane
            Vector3f xzAcc = Vector3f(accWMean.x, 0.0f, accWMean.z);
            // The unit normal of xzAcc will be the rotation axis for tilt correction
            Vector3f tiltAxis = Vector3f(xzAcc.z, 0.0f, -xzAcc.x).Normalized();
            Vector3f yUp = Vector3f(0.0f, 1.0f, 0.0f);
            // This is the amount of rotation
            float    tiltAngle = yUp.Angle(accWMean);
            // Record values if the tilt error is intolerable
            if (tiltAngle > maxTiltError) 
            {
                TiltErrorAngle = tiltAngle;
                TiltErrorAxis = tiltAxis;
            }
        }

        // This part performs the actual tilt correction as needed
        if (TiltErrorAngle > minTiltError) 
        {
            if ((TiltErrorAngle > 0.4f)&&(Stage < 8000))
            {   // Tilt completely to correct orientation
                Q = Quatf(TiltErrorAxis, -TiltErrorAngle) * Q;
                TiltErrorAngle = 0.0f;
            }
            else 
            {
                //LogText("Performing tilt correction  -  Angle: %f   Axis: %f %f %f\n",
                //        TiltErrorAngle,TiltErrorAxis.x,TiltErrorAxis.y,TiltErrorAxis.z);
                //float deltaTiltAngle = -Gain*TiltErrorAngle*0.005f;
                // This uses agressive correction steps while your head is moving fast
                float deltaTiltAngle = -Gain*TiltErrorAngle*0.005f*(5.0f*angVelLength+1.0f);
                // Incrementally "untilt" by a small step size
                Q = Quatf(TiltErrorAxis, deltaTiltAngle) * Q;
                TiltErrorAngle += deltaTiltAngle;
            }
        }
    }

    // Yaw drift correction based on magnetometer data.  This corrects the part of the drift
    // that the accelerometer cannot handle.
    // This will only work if the magnetometer has been enabled, calibrated, and a reference
    // point has been set.
    const float maxAngVelLength = 3.0f;
    const int   magWindow = 5;
    const float yawErrorMax = 0.1f;
    const float yawErrorMin = 0.01f;
    const int   yawErrorCountLimit = 50;
    const float yawRotationStep = 0.00002f;

    if (angVelLength < maxAngVelLength)
        MagCondCount++;
    else
        MagCondCount = 0;

	YawCorrectionInProgress = false;
    if (EnableYawCorrection && MagReady && (currentTime > 2.0f) && (MagCondCount >= magWindow) &&
        (Q.Distance(MagRefQ) < MagRefDistance))
    {
        // Use rotational invariance to bring reference mag value into global frame
        Vector3f grefmag = MagRefQ.Rotate(GetCalibratedMagValue(MagRefM));
        // Bring current (averaged) mag reading into global frame
        Vector3f gmag = Q.Rotate(GetCalibratedMagValue(FRawMag.Mean()));
        // Calculate the reference yaw in the global frame
        float gryaw = atan2(grefmag.x,grefmag.z);
        // Calculate the current yaw in the global frame
        float gyaw = atan2(gmag.x,gmag.z);
        //LogText("Yaw error estimate: %f\n",YawErrorAngle);
        // The difference between reference and current yaws is the perceived error
        YawErrorAngle = AngleDifference(gyaw,gryaw);
        // If the perceived error is large, keep count
        if ((fabs(YawErrorAngle) > yawErrorMax) && (!YawCorrectionActivated))
            YawErrorCount++;
        // After enough iterations of high perceived error, start the correction process
        if (YawErrorCount > yawErrorCountLimit)
            YawCorrectionActivated = true;
        // If the perceived error becomes small, turn off the yaw correction
        if ((fabs(YawErrorAngle) < yawErrorMin) && YawCorrectionActivated) 
        {
            YawCorrectionActivated = false;
            YawErrorCount = 0;
        }
        // Perform the actual yaw correction, due to previously detected, large yaw error
        if (YawCorrectionActivated) 
        {
			YawCorrectionInProgress = true;
            int sign = (YawErrorAngle > 0.0f) ? 1 : -1;
            // Incrementally "unyaw" by a small step size
            Q = Quatf(Vector3f(0.0f,1.0f,0.0f), -yawRotationStep * sign) * Q;
        }
    }
}
//----------------------------------------------------------------------------
void BouncingTetrahedra::Reposition (int t0, int t1, Contact& contact)
{
    RigidTetra& tetra0 = *mTetras[t0];
    RigidTetra& tetra1 = *mTetras[t1];

    // Compute the centroids of the tetrahedra.
    Vector3f vertices0[4], vertices1[4];
    tetra0.GetVertices(vertices0);
    tetra1.GetVertices(vertices1);
    Vector3f centroid0 = Vector3f::ZERO;
    Vector3f centroid1 = Vector3f::ZERO;
    int i;
    for (i = 0; i < 4; ++i)
    {
        centroid0 += vertices0[i];
        centroid1 += vertices1[i];
    }
    centroid0 *= 0.25f;
    centroid1 *= 0.25f;

    // Randomly perturb the tetrahedra vertices by a small amount.  This is
    // done to help prevent the LCP solver from getting into cycles and
    // degenerate cases.
    const float reduction = 0.95f;
    float reduceI = reduction*Mathf::IntervalRandom(0.9999f, 1.0001f);
    float reduceJ = reduction*Mathf::IntervalRandom(0.9999f, 1.0001f);
    for (i = 0; i < 4; ++i)
    {
        vertices0[i] = centroid0 + (vertices0[i] - centroid0)*reduceI;
        vertices1[i] = centroid1 + (vertices1[i] - centroid1)*reduceJ;
    }

    // Compute the distance between the tetrahedra.
    float dist = 1.0f;
    int statusCode = 0;
    Vector3f closest[2];
    LCPPolyDist3(4, vertices0, 4, mFaces, 4, vertices1, 4, mFaces,
        statusCode, dist, closest);
    ++mLCPCount;

    // In theory, LCPPolyDist<3> should always find a valid distance, but just
    // in case numerical round-off errors cause problems, let us trap it.
    assertion(dist >= 0.0f, "LCP polyhedron distance calculator failed.\n");

    // Reposition the tetrahedra to the theoretical points of contact.
    closest[0] = centroid0 + (closest[0] - centroid0)/reduceI;
    closest[1] = centroid1 + (closest[1] - centroid1)/reduceJ;
    for (i = 0; i < 4; ++i)
    {
        vertices0[i] = centroid0 + (vertices0[i] - centroid0)/reduceI;
        vertices1[i] = centroid1 + (vertices1[i] - centroid1)/reduceJ;
    }

    // Numerical round-off errors can cause interpenetration.  Move the
    // tetrahedra to back out of this situation.  The length of diff
    // estimates the depth of penetration when dist > 0 was reported.
    Vector3f diff = closest[0] - closest[1];

    // Apply the separation distance along the line containing the centroids
    // of the tetrahedra.
    Vector3f diff2 = centroid1 - centroid0;
    diff = diff2/diff2.Length()*diff.Length();

    // Move each tetrahedron by half of kDiff when the distance was large,
    // but move each by twice kDiff when the distance is really small.
    float mult = (dist >= mTolerance ? 0.5f : 1.0f);
    Vector3f delta = mult*diff;

    // Undo the interpenetration.
    if (tetra0.Moved && !tetra1.Moved)
    {
        // Tetra t0 has moved but tetra t1 has not moved.
        tetra1.SetPosition(tetra1.GetPosition() + 2.0f*delta);
        tetra1.Moved = true;
    }
    else if (!tetra0.Moved && tetra1.Moved)
    {
        // Tetra t1 has moved but tetra t0 has not moved.
        tetra0.SetPosition(tetra0.GetPosition() - 2.0f*delta);
        tetra0.Moved = true;
    }
    else
    {
        // Both tetras moved or both tetras did not move.
        tetra0.SetPosition(tetra0.GetPosition() - delta);
        tetra0.Moved = true;
        tetra1.SetPosition(tetra1.GetPosition() + delta);
        tetra1.Moved = true;
    }

    // Test whether the two tetrahedra intersect in a vertex-face
    // configuration.
    contact.IsVFContact = IsVertex(vertices0, closest[0]);
    if (contact.IsVFContact)
    {
        contact.A = mTetras[t1];
        contact.B = mTetras[t0];
        CalculateNormal(vertices1, closest[1], contact);
    }
    else
    {
        contact.IsVFContact = IsVertex(vertices1, closest[1]);
        if (contact.IsVFContact)
        {
            contact.A = mTetras[t0];
            contact.B = mTetras[t1];
            CalculateNormal(vertices0, closest[0], contact);
        }
    }

    // Test whether the two tetrahedra intersect in an edge-edge
    // configuration.
    if (!contact.IsVFContact)
    {
        contact.A = mTetras[t0];
        contact.B = mTetras[t1];
        Vector3f otherVertexA = Vector3f::UNIT_X;
        Vector3f otherVertexB = Vector3f::ZERO;
        contact.EA = ClosestEdge(vertices0, closest[0], otherVertexA);
        contact.EB = ClosestEdge(vertices1, closest[1], otherVertexB);
        Vector3f normal = contact.EA.UnitCross(contact.EB);
        if (normal.Dot(otherVertexA - closest[0]) < 0.0f)
        {
            contact.N = normal;
        }
        else
        {
            contact.N = -normal;
        }
    }

    // Reposition results to correspond to relocaton of tetra.
    contact.PA = closest[0] - delta;
    contact.PB = closest[1] + delta;
}
void Particle::Render(Camera* camera, unsigned int i, bool drawAxes)
{
    switch( this->_type )
    {
    case BillBoard:
        break;
    case VectorAligned:
        break;
    case ScreenFacing:
    default:
    {
        Vector3f particleToCamera = camera->GetPosition()-this->_position;
        this->_depth = particleToCamera.Length();

        Vector3f cameraYAxis = camera->GetEulerRotation()*Vector3f(sin(this->_rotation), cos(this->_rotation), 0.0f);
        Vector3f localX = cameraYAxis.Cross(particleToCamera);
        Vector3f localY = particleToCamera.Cross(localX);

        localX.Normalize();
        localY.Normalize();

        // Set blend mode
        switch( this->_blendMode )
        {
        case Subtractive:
            glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE);
            break;
        case Additive:
            glBlendFunc(GL_SRC_ALPHA, GL_ONE);
            break;
        case Normal:
        default:
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            break;
        }

        // Evaluate animators
        float t = 1.0f-this->_life/this->_maxLife;

        Vector2f size = this->_size->GetValue(t);

        // Bind texture
        if( this->_texture )
        {
            glBindTexture(GL_TEXTURE_2D, this->_texture->GetTextureName());
        }

        // Render
        glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
        glBegin(GL_QUADS);

        glColor4f(this->_color.r, this->_color.g, this->_color.b, this->_color.a);

        // TODO (Viet Nguyen): Get rid of texture coordinate hacks!!!!

        glTexCoord2f(0.0f, 0.0f);
        glVertex3fv((float*)
                    (this->_position+(-localX)*size.width+(-localY)*size.height));

        glTexCoord2f(1.0f/4.0f/*!!!!*/, 0.0f);
        glVertex3fv((float*)
                    (this->_position+localX*size.width+(-localY)*size.height));

        glTexCoord2f(1.0f/4.0f/*!!!!*/, 1.0f);
        glVertex3fv((float*)
                    (this->_position+localX*size.width+localY*size.height));

        glTexCoord2f(0.0f, 1.0f);
        glVertex3fv((float*)
                    (this->_position+(-localX)*size.width+localY*size.height));

        glEnd();

        // Unbind texture
        if( this->_texture)
        {
            glBindTexture(GL_TEXTURE_2D, 0);
        }

        if( drawAxes )
        {
            glBegin(GL_LINES);
            glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);

            glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
            glVertex3fv((float*)(this->_position));
            glVertex3fv((float*)(this->_position+localX*size.width));

            glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
            glVertex3fv((float*)(this->_position));
            glVertex3fv((float*)(this->_position+localY*size.height));

            glEnd();
        }
    }
    }
}
Пример #18
0
void
KickEffector::PrePhysicsUpdateInternal(float /*deltaTime*/)
{
    // this should also include the case when there is no ball
    // (because then there will be no body, neither).
    if (mAction.get() == 0 || mBallBody.get() == 0)
    {
        return;
    }

    if (mAgent.get() == 0)
    {
        GetLog()->Error()
            << "ERROR: (KickEffector) parent node is not derived from BaseNode\n";
        return;
    }

    shared_ptr<KickAction> kickAction =
        shared_dynamic_cast<KickAction>(mAction);
    mAction.reset();

    if (kickAction.get() == 0)
    {
        GetLog()->Error()
            << "ERROR: (KickEffector) cannot realize an unknown ActionObject\n";
        return;
    }

    // if the agent doesn't have a body, we're done (this should never happen)
    if (mBall.get() == 0) return;

    Vector3f force =
        mBallBody->GetWorldTransform().Pos() -
        mAgent->GetWorldTransform().Pos();

    // the ball can be kicked if the distance is
    // less then Ball-Radius + Player-Radius + KickMargin AND
    // the player is close to the ground
    if (mAgent->GetWorldTransform().Pos().z() > mPlayerRadius + 0.01 ||
        force.Length() > mPlayerRadius + mBallRadius + mKickMargin)
    {
        // ball is out of reach, or player is in the air:
        // kick has no effect
        return;
    }

    // get the kick angle in the horizontal plane
    double theta = salt::gArcTan2(force[1], force[0]);
    if (mThetaErrorRNG.get() != 0)
    {
        theta += (*(mThetaErrorRNG.get()))();
    }

    float phi = salt::gMin(salt::gMax(kickAction->GetAngle(), mMinAngle), mMaxAngle);
    if (mSigmaPhiEnd > 0.0 || mSigmaPhiMid > 0.0)
    {
        // f will be close to 0.0 if the angle is near the minimum or the maximum.
        // f will be close to 1.0 if the angle is somewhere in the middle of the range.
        float f = 1.0 - 2.0 * salt::gAbs((phi - mMinAngle) / (mMaxAngle - mMinAngle) - 0.5);
        // f is set to a number between mSigmaPhiEnd and mSigmaPhiMid
        f = salt::gMax(mSigmaPhiEnd + f * (mSigmaPhiMid-mSigmaPhiEnd), 0.0);
        phi = salt::NormalRNG<>(phi,f)();
    }
    phi = salt::gDegToRad(90.0-phi);

    // x = r * cos(theta) * sin(90 - phi), with r = 1.0
    force[0] = salt::gCos(theta) * salt::gSin(phi);
    // y = r * sin(theta) * sin(90 - phi), with r = 1.0
    force[1] = salt::gSin(theta) * salt::gSin(phi);
    // z = r * cos(90 - phi),              with r = 1.0
    force[2] = salt::gCos(phi);

    float kick_power = salt::gMin(salt::gMax(kickAction->GetPower(), 1.0f), mMaxPower);
    if (mForceErrorRNG.get() != 0)
    {
        kick_power += (*(mForceErrorRNG.get()))();
    }

    force *= (mForceFactor * kick_power);

    const Vector3f torque(-mTorqueFactor*force[1]/salt::g2PI,
                          mTorqueFactor*force[0]/salt::g2PI,
                          0.0);

    mBall->SetAcceleration(mSteps,force,torque,mAgent);

    mBallStateAspect->UpdateLastKickingAgent(mAgent);

}
Пример #19
0
void CRigidBody::DeliverCollisionMessage(CCollisionMessage* ColMsg)
{
	if (!ColMsg) return;

	if (ColMsg->GetCollisionType() == SPHERE_TO_SPHERE) {
		HandleSphereToSphereCollision(ColMsg);
		return;
	}

	/****** Deploy to HandlePushCollision() if this is the case ******/
	// Push collision not working. Commenting this out for now.
	/*	if (ColMsg->GetCollisionType() == PUSHED) {
		HandlePushCollision(ColMsg);
		return;
	}
*/ 

	CVehicle* Car = (CVehicle*)ColMsg->GetEntity();

	/************** set reflection motion ************/

	m_vPosition = m_translate + (*ColMsg->GetReverse())*RIGIDBODY_SPACING_FACTOR;

	Vector3f velocityWC;
	if (disturbed) {
		velocityWC = m_vDirectionWhenDisturbed*80.0f;
	}
	else {
		velocityWC = Car->GetVehicleVelocityWC();
		// if reversing, velocityWC will point in opposite direction as actual velocity
		if (Car->GetVehicleVelocityLC().X() < 0.0f)
			velocityWC *= -1.0f;
	}

	m_vReflection = velocityWC - 2.0f*(velocityWC.Dot(*ColMsg->GetNormal()))*(*ColMsg->GetNormal());
	m_vReflection *= RIGIDBODY_REFLECTION_FACTOR;
	m_vDirectionWhenDisturbed = m_vReflection;

	Car->SetVehicleVelocityLC(0.0f);
	Car->SetVehiclePositionLC(Vector3f(m_vPosition.X(), m_vPosition.Z(), m_vPosition.Y()));

	/*************** set angular velocity ******************/

	// Compute angle between vehicle heading and plane
	Vector3f PlaneEdge = ColMsg->GetPlane()->Edge0();
	Vector3f CarHeading = Car->GetVehicleHeadingWC();
	float angle = acos(CarHeading.Dot(PlaneEdge)/(PlaneEdge.Length()*CarHeading.Length()));

	// spin CW or CCW?
	float spin; // magnitude of spin about the y-axis
	if (angle > Math<float>::PI/2.0f) { // CCW
		spin = Math<float>::PI - angle;
	}
	else { // CW
		spin = -angle;
	}
	spin *= RIGIDBODY_SPIN_FACTOR;
	m_vRotation = Vector3f(0.0f, spin, 0.0f);

	/*************** set vectors that are actually used in renderer ************/
	/*********************** to the values computed above **********************/

	m_translate = m_vPosition;
	m_box.Center() = m_vPosition;
	m_sphere.Center() = m_vPosition;
	Car->GetRotationLC().Z() += spin;

	disturbed = true;

	/*
	CLog::GetLog().Write(LOG_MISC, "\n\n\nreflection = (%f, %f, %f)",
		m_vReflection.X(), m_vReflection.Y(), m_vReflection.Z());
	CLog::GetLog().Write(LOG_MISC, "direction = (%f, %f, %f)\n\n",
		m_vDirectionWhenDisturbed.X(), m_vDirectionWhenDisturbed.Y(), m_vDirectionWhenDisturbed.Z());
*/
}
Пример #20
0
 F32 Vector3f::Length(const Vector3f& vec) {
     return vec.Length();
 }
Пример #21
0
//----------------------------------------------------------------------------
void BouncingSpheres::DoCollisionDetection ()
{
    mBoundaryContacts.clear();

    // Collisions with boundaries.
    Contact contact;
    int i;
    for (i = 0; i < NUM_BALLS; ++i)
    {
        Vector3f position = mBalls[i]->GetPosition();
        float radius = mBalls[i]->GetRadius();
        mBalls[i]->Moved = false;
        mBlocked[i].clear();

        // These checks are done in pairs under the assumption that the ball 
        // radii are smaller than the separation of opposite boundaries, hence
        // only one of each opposite pair of boundaries may be touched at any
        // time.

        // rear[0] and front[5] boundaries
        if (position.X() < mBoundaryLocations[0].X() + radius)
        {
            SetBoundaryContact(i, 0, position, radius, contact);
        }
        else if (position.X() > mBoundaryLocations[5].X() - radius)
        {
            SetBoundaryContact(i, 5, position, radius, contact);
        }

        // left[1] and right[3] boundaries
        if (position.Y() < mBoundaryLocations[1].Y() + radius)
        {
            SetBoundaryContact(i, 1, position, radius, contact);
        }
        else if (position.Y() > mBoundaryLocations[3].Y() - radius)
        {
            SetBoundaryContact(i, 3, position, radius, contact);
        }

        // bottom[2] and top[4] boundaries
        if (position.Z() < mBoundaryLocations[2].Z() + radius)
        {
            SetBoundaryContact(i, 2, position, radius, contact);
        }
        else if (position.Z() > mBoundaryLocations[4].Z() - radius)
        {
            SetBoundaryContact(i, 4, position, radius, contact);
        }
    }

    // Collisions between balls.
    for (i = 0; i < NUM_BALLS-1; ++i)
    {
        for (int j = i + 1; j < NUM_BALLS; ++j)
        {
            Vector3f diff =
                mBalls[j]->GetPosition() - mBalls[i]->GetPosition();
            float diffLen = diff.Length();
            float radiusI = mBalls[i]->GetRadius();
            float radiusJ = mBalls[j]->GetRadius();
            float magnitude = diffLen - radiusI - radiusJ;
            if (magnitude < 0.0f)
            {
                contact.A = mBalls[i];
                contact.B = mBalls[j];
                contact.N = diff/diffLen;
                Vector3f deltaPos = magnitude*contact.N;

                if (mBalls[i]->Moved && !mBalls[j]->Moved)
                {
                    // Ball i moved but ball j did not.
                    mBalls[j]->Position() -= deltaPos;
                }
                else if (!mBalls[i]->Moved && mBalls[j]->Moved)
                {
                    // Ball j moved but ball i did not.
                    mBalls[i]->Position() += deltaPos;
                }
                else
                {
                    // Neither ball moved or both balls moved already.
                    deltaPos *= 0.5f;
                    mBalls[j]->Position() -= deltaPos;
                    mBalls[i]->Position() += deltaPos;
                }

                contact.P = mBalls[i]->Position() + radiusI*contact.N; 
                mBoundaryContacts.push_back(contact);
            }
        }
    }

    mNumContacts = (int)mBoundaryContacts.size();
}
Пример #22
0
void Player::HandleMovement(double dt, std::vector<Ptr<CollisionModel> >* collisionModels,
	                        std::vector<Ptr<CollisionModel> >* groundCollisionModels, bool shiftDown)
{
    // Handle keyboard movement.
    // This translates BasePos based on the orientation and keys pressed.
    // Note that Pitch and Roll do not affect movement (they only affect view).
    Vector3f controllerMove;
    if(MoveForward || MoveBack || MoveLeft || MoveRight)
    {
        if (MoveForward)
        {
            controllerMove += ForwardVector;
        }
        else if (MoveBack)
        {
            controllerMove -= ForwardVector;
        }

        if (MoveRight)
        {
            controllerMove += RightVector;
        }
        else if (MoveLeft)
        {
            controllerMove -= RightVector;
        }
    }
    else if (GamepadMove.LengthSq() > 0)
    {
        controllerMove = GamepadMove;
    }
    controllerMove = GetOrientation(bMotionRelativeToBody).Rotate(controllerMove);    
    controllerMove.y = 0; // Project to the horizontal plane
    if (controllerMove.LengthSq() > 0)
    {
        // Normalize vector so we don't move faster diagonally.
        controllerMove.Normalize();
        controllerMove *= OVR::Alg::Min<float>(MoveSpeed * (float)dt * (shiftDown ? 3.0f : 1.0f), 1.0f);
    }

    // Compute total move direction vector and move length
    Vector3f orientationVector = controllerMove;
    float moveLength = orientationVector.Length();
    if (moveLength > 0)
        orientationVector.Normalize();
        
    float   checkLengthForward = moveLength;
    Planef  collisionPlaneForward;
    bool    gotCollision = false;

    for(size_t i = 0; i < collisionModels->size(); ++i)
    {
        // Checks for collisions at model base level, which should prevent us from
		// slipping under walls
        if (collisionModels->at(i)->TestRay(BodyPos, orientationVector, checkLengthForward,
				                            &collisionPlaneForward))
        {
            gotCollision = true;
            break;
        }
    }

    if (gotCollision)
    {
        // Project orientationVector onto the plane
        Vector3f slideVector = orientationVector - collisionPlaneForward.N
			* (orientationVector.Dot(collisionPlaneForward.N));

        // Make sure we aren't in a corner
        for(size_t j = 0; j < collisionModels->size(); ++j)
        {
            if (collisionModels->at(j)->TestPoint(BodyPos - Vector3f(0.0f, RailHeight, 0.0f) +
					                                (slideVector * (moveLength))) )
            {
                moveLength = 0;
                break;
            }
        }
        if (moveLength != 0)
        {
            orientationVector = slideVector;
        }
    }
    // Checks for collisions at foot level, which allows us to follow terrain
    orientationVector *= moveLength;
    BodyPos += orientationVector;

    Planef collisionPlaneDown;
    float adjustedUserEyeHeight = GetFloorDistanceFromTrackingOrigin(ovrTrackingOrigin_EyeLevel);
    float finalDistanceDown = adjustedUserEyeHeight + 10.0f;

    // Only apply down if there is collision model (otherwise we get jitter).
    if (groundCollisionModels->size())
    {
        for(size_t i = 0; i < groundCollisionModels->size(); ++i)
        {
            float checkLengthDown = adjustedUserEyeHeight + 10;
            if (groundCollisionModels->at(i)->TestRay(BodyPos, Vector3f(0.0f, -1.0f, 0.0f),
                checkLengthDown, &collisionPlaneDown))
            {
                finalDistanceDown = Alg::Min(finalDistanceDown, checkLengthDown);
            }
        }

        // Maintain the minimum camera height
        if (adjustedUserEyeHeight - finalDistanceDown < 1.0f)
        {
            BodyPos.y += adjustedUserEyeHeight - finalDistanceDown;
        }
    }
    
    SetBodyPos(BodyPos, false);
}
Пример #23
0
//----------------------------------------------------------------------------
void GelatinBlob::CreateSprings ()
{
    // The icosahedron has 12 vertices and 30 edges.  Each vertex is a
    // particle in the system.  Each edge represents a spring.  To keep the
    // icosahedron from collapsing, 12 immovable particles are added, each
    // outside the icosahedron in the normal direction above a vertex.  The
    // immovable particles are connected to their corresponding vertices with
    // springs.
    int iNumParticles = 24, iNumSprings = 42;

    // Viscous forces applied.  If you set viscosity to zero, the cuboid
    // wiggles indefinitely since there is no dissipation of energy.  If
    // the viscosity is set to a positive value, the oscillations eventually
    // stop.  The length of time to steady state is inversely proportional
    // to the viscosity.
#ifdef _DEBUG
    float fStep = 0.1f;
#else
    float fStep = 0.01f;  // simulation needs to run slower in release mode
#endif
    float fViscosity = 0.01f;
    m_pkModule = new PhysicsModule(iNumParticles,iNumSprings,fStep,
        fViscosity);

    // Set positions and velocities.  The first 12 positions are the vertices
    // of the icosahedron.  The last 12 are the extra particles added to
    // stabilize the system.
    const Vector3f* akVertex = m_spkSphere->Vertices();
    int i;
    for (i = 0; i < 12; i++)
    {
        m_pkModule->SetMass(i,1.0f);
        m_pkModule->Position(i) = akVertex[i];
        m_pkModule->Velocity(i) = 0.1f*Vector3f(Mathf::SymmetricRandom(),
            Mathf::SymmetricRandom(),Mathf::SymmetricRandom());
    }
    for (i = 12; i < 24; i++)
    {
        m_pkModule->SetMass(i,Mathf::MAX_REAL);
        m_pkModule->Position(i) = 2.0f*akVertex[i-12];
        m_pkModule->Velocity(i) = Vector3f::ZERO;
    }

    // get unique set of edges for icosahedron
    set<EdgeKey> kEdge;
    int iTQuantity = m_spkSphere->GetTriangleQuantity();
    const int* piConnect = m_spkSphere->Connectivity();
    for (i = 0; i < iTQuantity; i++)
    {
        int iV0 = *piConnect++;
        int iV1 = *piConnect++;
        int iV2 = *piConnect++;
        kEdge.insert(EdgeKey(iV0,iV1));
        kEdge.insert(EdgeKey(iV1,iV2));
        kEdge.insert(EdgeKey(iV2,iV0));
    }

    // springs are at rest in the initial configuration
    const float fConstant = 10.0f;
    Vector3f kDiff;
    int iSpring = 0;
    set<EdgeKey>::iterator pkIter;
    for (pkIter = kEdge.begin(); pkIter != kEdge.end(); pkIter++)
    {
        const EdgeKey& rkKey = *pkIter;
        int iV0 = rkKey.V[0], iV1 = rkKey.V[1];
        kDiff = m_pkModule->Position(iV1) - m_pkModule->Position(iV0);
        m_pkModule->SetSpring(iSpring,iV0,iV1,fConstant,kDiff.Length());
        iSpring++;
    }
    for (i = 0; i < 12; i++)
    {
        kDiff = m_pkModule->Position(i+12) - m_pkModule->Position(i);
        m_pkModule->SetSpring(iSpring,i,i+12,fConstant,kDiff.Length());
        iSpring++;
    }
}
Пример #24
0
//----------------------------------------------------------------------------
void GelatinCube::CreateSprings ()
{
    // The inner 4-by-4-by-4 particles are used as the control points of a
    // B-spline volume.  The outer layer of particles are immovable to
    // prevent the cuboid from collapsing into itself.
    int numSlices = 6;
    int numRows = 6;
    int numCols = 6;

    // Viscous forces applied.  If you set viscosity to zero, the cuboid
    // wiggles indefinitely since there is no dissipation of energy.  If
    // the viscosity is set to a positive value, the oscillations eventually
    // stop.  The length of time to steady state is inversely proportional
    // to the viscosity.
#ifdef _DEBUG
    float step = 0.1f;
#else
    float step = 0.01f;  // simulation needs to run slower in release mode
#endif
    float viscosity = 0.01f;
    mModule = new0 PhysicsModule(numSlices, numRows, numCols, step,
        viscosity);

    // The initial cuboid is axis-aligned.  The outer shell is immovable.
    // All other masses are constant.
    float sFactor = 1.0f/(float)(numSlices - 1);
    float rFactor = 1.0f/(float)(numRows - 1);
    float cFactor = 1.0f/(float)(numCols - 1);
    int s, r, c;
    for (s = 0; s < numSlices; ++s)
    {
        for (r = 0; r < numRows; ++r)
        {
            for (c = 0; c < numCols; ++c)
            {
                mModule->Position(s, r, c) =
                    Vector3f(c*cFactor, r*rFactor, s*sFactor);

                if (1 <= s && s < numSlices - 1
                &&  1 <= r && r < numRows - 1
                &&  1 <= c && c < numCols - 1)
                {
                    mModule->SetMass(s, r, c, 1.0f);
                    mModule->Velocity(s, r, c) = 0.1f*Vector3f(
                        Mathf::SymmetricRandom(), Mathf::SymmetricRandom(),
                        Mathf::SymmetricRandom());
                }
                else
                {
                    mModule->SetMass(s, r, c, Mathf::MAX_REAL);
                    mModule->Velocity(s, r, c) = Vector3f::ZERO;
                }
            }
        }
    }

    // Springs are at rest in the initial configuration.
    const float constant = 10.0f;
    Vector3f diff;

    for (s = 0; s < numSlices - 1; ++s)
    {
        for (r = 0; r < numRows; ++r)
        {
            for (c = 0; c < numCols; ++c)
            {
                mModule->ConstantS(s, r, c) = constant;
                diff = mModule->Position(s + 1, r, c) -
                    mModule->Position(s, r, c);
                mModule->LengthS(s, r, c) = diff.Length();
            }
        }
    }

    for (s = 0; s < numSlices; ++s)
    {
        for (r = 0; r < numRows - 1; ++r)
        {
            for (c = 0; c < numCols; ++c)
            {
                mModule->ConstantR(s, r, c) = constant;
                diff = mModule->Position(s, r + 1, c) -
                    mModule->Position(s, r, c);
                mModule->LengthR(s, r, c) = diff.Length();
            }
        }
    }

    for (s = 0; s < numSlices; ++s)
    {
        for (r = 0; r < numRows; ++r)
        {
            for (c = 0; c < numCols - 1; ++c)
            {
                mModule->ConstantC(s, r, c) = constant;
                diff = mModule->Position(s, r, c + 1) -
                    mModule->Position(s, r, c);
                mModule->LengthC(s, r, c) = diff.Length();
            }
        }
    }
}
Пример #25
0
/// Returns false if the colliding entities are no longer in contact after resolution.
bool FirstPersonCR::ResolveCollision(Collision & c)
{
	Entity * dynamic;
	Entity * other;
	if (c.one->physics->type == PhysicsType::DYNAMIC)
	{
		dynamic = c.one;
		other = c.two;
	}
	else 
	{
		dynamic = c.two;
		other = c.one;
	}
	if (c.one->physics->noCollisionResolutions || c.two->physics->noCollisionResolutions)
		return false;

	// Retardation?
//	if (dynamic->physics->lastCollisionMs + dynamic->physics->minCollisionIntervalMs > physicsNowMs)
	//	return false;

	dynamic->physics->lastCollisionMs = physicsNowMs;

	Entity * dynamic2 = (other->physics->type == PhysicsType::DYNAMIC) ? other : NULL;
	Entity * staticEntity;
	Entity * kinematicEntity;
	if (dynamic == c.one)
		other = c.two;
	else
		other = c.one;
	if (!dynamic2)
	{
		staticEntity = other->physics->type == PhysicsType::STATIC? other : NULL;
		kinematicEntity = other->physics->type == PhysicsType::KINEMATIC? other : NULL;
	}
//	std::cout<<"\nCollision: "<<c.one->name<<" "<<c.two->name;
	// Collision..!
	// Static-Dynamic collision.
	if (!dynamic2)
	{
		PhysicsProperty * pp = dynamic->physics;
		// Skip? No.
//		if (kinematicEntity)
//			return true;

		/// Flip normal if dynamic is two.
		if (dynamic == c.two)
			c.collisionNormal *= -1;

		if (c.collisionNormal.y > 0.8f)
			pp->lastGroundCollisionMs = physicsNowMs;

		// Default plane? reflect velocity upward?
		// Reflect based on the normal.
		float velDotNormal = pp->velocity.DotProduct(c.collisionNormal);
		
		/// This will be used to reflect it.
		Vector3f velInNormalDir = c.collisionNormal * velDotNormal;
		Vector3f velInTangent = pp->velocity - velInNormalDir;
		
		Vector3f newVel = velInTangent * (1 - pp->friction) + velInNormalDir * (-pp->restitution);

		/// Apply resitution and stuffs.
		dynamic->physics->velocity = newVel;
		assert(dynamic->parent == 0); 
		/// Adjusting local position may not help if child entity.
		// Old code
		Vector3f moveVec = AbsoluteValue(c.distanceIntoEachOther) * c.collisionNormal;
//		if (moveVec.x || moveVec.z)
//			std::cout<<"\nMoveVec: "<<moveVec;
		dynamic->localPosition += moveVec;
		/// For double-surface collision resolution (not bouncing through walls..)

		/// For the previously backwards-collisions.
//		if (c.distanceIntoEachOther < 0)
	//		dynamic->localPosition += c.distanceIntoEachOther * c.collisionNormal;
//		else // Old code
	//		dynamic->localPosition += AbsoluteValue(c.distanceIntoEachOther) * c.collisionNormal;

		/// If below threshold, sleep it.
		if (dynamic->physics->velocity.Length() < inRestThreshold && c.collisionNormal.y > 0.8f)
		{
			// Sleep eeet.
			dynamic->physics->state |= CollisionState::IN_REST;
			// Nullify velocity.
			dynamic->physics->velocity = Vector3f();
		}
		if (debug == 7)
		{
			std::cout<<"\nCollision resolution: "<<(c.one->name+" "+c.two->name+" ")<<c.collisionNormal<<" onePos"<<c.one->worldPosition<<" twoPos"<<c.two->worldPosition;
		}
	}
	// Dynamic-dynamic collision.
	else 
	{
//		std::cout<<"\nProblem?"	;
		/// Push both apart?
		PhysicsProperty * pp = dynamic->physics, * pp2 = dynamic2->physics;

		/// Flip normal if dynamic is two.
		// See if general velocities align with one or the other? or...
		
//		if (dynamic == c.two)

		;// c.collisionNormal *= -1;

//		std::cout<<"\nNormal: "<<c.collisionNormal;

		// Default plane? reflect velocity upward?		
		/// This will be used to reflect it.
		Vector3f velInNormalDir = c.collisionNormal * pp->velocity.DotProduct(c.collisionNormal);
		Vector3f velInNormalDir2 = c.collisionNormal * pp2->velocity.DotProduct(c.collisionNormal);
		Vector3f velInTangent = pp->velocity - velInNormalDir,
			velInTangent2 = pp2->velocity - velInNormalDir2;
		Vector3f velInTangentTot = velInTangent + velInTangent2,
			velInNormalDirTot = velInNormalDir + velInNormalDir2;		
		/// Use lower value restitution of the two?
		float restitution = 0.5f; // MinimumFloat(pp->restitution, pp2->restitution);
		Vector3f normalDirPart = velInNormalDirTot * restitution * 0.5f;
		Vector3f to2 = (dynamic2->worldPosition - dynamic->worldPosition).NormalizedCopy();
		float partTo2 = normalDirPart.DotProduct(to2);
	//	std::cout<<" normalDirPart: "<<normalDirPart;

		float normalDirPartVal = normalDirPart.Length();

		Vector3f fromCollisionToDyn1 = (dynamic->worldPosition - c.collissionPoint).NormalizedCopy();
		Vector3f fromCollisionToDyn2 = (dynamic2->worldPosition - c.collissionPoint).NormalizedCopy();

		pp->velocity = velInTangent * (1 - pp->friction) + fromCollisionToDyn1 * normalDirPartVal;
		pp2->velocity = velInTangent2 * (1 - pp->friction) + fromCollisionToDyn2 * normalDirPartVal;
		/// Apply resitution and stuffs.
		assert(dynamic->parent == 0);
		/// Adjusting local position may not help if child entity.
		// Old code
		float distanceIntoAbsH = AbsoluteValue(c.distanceIntoEachOther * 0.5f);

		dynamic->localPosition += distanceIntoAbsH * fromCollisionToDyn1;
		dynamic2->localPosition += distanceIntoAbsH * fromCollisionToDyn2;

		/// For double-surface collision resolution (not bouncing through walls..)
		/// If below threshold, sleep it.
		if (dynamic->physics->velocity.Length() < inRestThreshold && c.collisionNormal.y > 0.8f)
		{
			pp->Sleep();
		}
		else
			pp->Activate();
		if (pp2->velocity.Length() < inRestThreshold && c.collisionNormal.y > 0.8f)
		{
			pp2->Sleep();
		}
		else
			pp2->Activate();
		if (debug == 7)
		{
			std::cout<<"\nCollision resolution: "<<(c.one->name+" "+c.two->name+" ")<<c.collisionNormal<<" onePos"<<c.one->worldPosition<<" twoPos"<<c.two->worldPosition;
		}
	}


	// Check collision normal.


	return true;
}
Пример #26
0
/// Query if it has reached next waypoint. Just compares distance with the proximity threshold.
bool PathableProperty::HasReachedNextWaypoint()
{
	Vector3f vecDist = nextWaypoint->position - owner->worldPosition;
	float distance = vecDist.Length();
	return distance < proximityThreshold;
}