//----------------------------------------------------------------------------
void DirectionalLight::ComputeSpecular (const Matrix3f& rkWorldRotate,
    const Vector3f&, float, const Vector3f* akVertex,
    const Vector3f* akNormal, int iQuantity, const bool* abVisible,
    const Vector3f& rkCameraModelLocation, ColorRGB* akSpecular)
{
    // transform light direction to model space of old mesh
    Vector3f kModelDir = m_kDirection*rkWorldRotate;

    // adjust specular color by light intensity
    ColorRGB kAdjSpecular = m_fIntensity*m_kSpecular;

    for (int i = 0; i < iQuantity; i++)
    {
        if ( abVisible[i] )
        {
            float fDot = kModelDir.Dot(akNormal[i]);
            Vector3f kReflect = kModelDir - (2.0f*fDot)*akNormal[i];
            Vector3f kViewDir = rkCameraModelLocation - akVertex[i];
            fDot = kViewDir.Dot(kReflect);
            if ( fDot > 0.0f )
            {
                float fCoeff = fDot*fDot/kViewDir.Dot(kViewDir);
                akSpecular[i] += fCoeff*kAdjSpecular;
            }
        }
    }
}
Beispiel #2
0
bool Camera3d::PointInFrustum(const Vector3f &point)
{
	float pcz,pcx,pcy,h;

	// compute vector from camera position to p
	Vector3f v = point - _eye;

	// compute and test the Z coordinate
	pcz = v.Dot(-_frustumZ);
	if (pcz > _far || pcz < _near)
		return false;

	// compute and test the Y coordinate
	pcy = v.Dot(_frustumY);
	h = pcz * _frustumTanFOV;
	if (pcy > h || pcy < -h)
		return false;

	// compute and test the X coordinate
	pcx = v.Dot(_frustumX);
	h = h * _ratioAspect;
	if (pcx > h || pcx < -h)
		return false;
	return true;
}
Beispiel #3
0
// intersect3D_SegmentPlane(): intersect a segment and a plane
//    Input:  a_Ray = a segment, and a_Plane = a plane = {Point V0; Vector n;}
//    Output: *I0 = the intersect point (when it exists)
//    Return: 0 = disjoint (no intersection)
//            1 = intersection in the unique point *I0
//            2 = the segment lies in the plane
int cTracer::intersect3D_SegmentPlane( const Vector3f & a_Origin, const Vector3f & a_End, const Vector3f & a_PlanePos, const Vector3f & a_PlaneNormal)
{
	Vector3f    u = a_End - a_Origin;       // a_Ray.P1 - S.P0;
	Vector3f    w = a_Origin - a_PlanePos;  // S.P0 - Pn.V0;

	float     D = a_PlaneNormal.Dot( u);      // dot(Pn.n, u);
	float     N = -(a_PlaneNormal.Dot( w));  // -dot(a_Plane.n, w);

	const float EPSILON = 0.0001f;
	if (fabs(D) < EPSILON)
	{
		// segment is parallel to plane
		if (N == 0)
		{
			// segment lies in plane
			return 2;
		}
		return 0;  // no intersection
	}
	
	// they are not parallel
	// compute intersect param
	float sI = N / D;
	if (sI < 0 || sI > 1)
	{
		return 0;  // no intersection
	}

	// Vector3f I ( a_Ray->GetOrigin() + sI * u);// S.P0 + sI * u;  // compute segment intersect point
	RealHit = a_Origin + u * sI;
	return 1;
}
Beispiel #4
0
bool Intersect::RaySphere (const Vector3f& origin, const Vector3f& dir, const Vector3f& center, float radius)
{
	Vector3f diff (origin - center);
	float a = diff.Dot(dir);
	float b = (a * a) + (radius * radius) - diff.Dot();
	return Float::IsPositive(b);
	// Distance if 'b' is positive: (-a - Float::Sqrt(b));
}
//----------------------------------------------------------------------------
// Clip C+t*V with [t0,t1] against the plane Dot(N,X-P) = 0, discarding that
// portion of the interval on the side of the plane to which N is directed.
// The return value is 'true' when a nonempty interval exists after clipping.
//----------------------------------------------------------------------------
static bool ClipAgainstPlane (const Vector3f& C, const Vector3f& V,
    const Vector3f& N, const Vector3f& P, float& t0, float& t1)
{
    // Define f(t) = Dot(N,C+t*V-P)
    //             = Dot(N,C-P) + t*Dot(N,V)
    //             = a0 + t*a1
    // Evaluate at the endpoints of the time interval.
    float a0 = N.Dot(C - P);
    float a1 = N.Dot(V);
    float f0 = a0 + t0*a1;
    float f1 = a0 + t1*a1;

    // Clip [t0,t1] against the plane.  There are nine cases to consider,
    // depending on the signs of f0 and f1.
    if (f0 > 0.0f)
    {
        if (f1 > 0.0f)
        {
            // The segment is strictly outside the plane.
            return false;
        }
        else if (f1 < 0.0f)
        {
            // The segment intersects the plane at an edge-interior point.
            // T = -a0/a1 is the time of intersection, so discard [t0,T].
            t0 = -a0/a1;
        }
        else  // f1 == 0.0f
        {
            // The segment is outside the plane but touches at the
            // t1-endpoint, so discard [t0,t1] (degenerate to a point).
            t0 = t1;
        }
    }
    else if (f0 < 0.0f)
    {
        if (f1 > 0.0f)
        {
            // The segment intersects the plane at an edge-interior point.
            // T = -a0/a1 is the time of intersection, so discard [T,t1].
            t1 = -a0/a1;
        }
    }
    else  // f0 == 0.0f
    {
        if (f1 > 0.0f)
        {
            // The segment is outside the plane but touches at the
            // t0-endpoint, so discard [t0,t1] (degenerate to a point).
            t1 = t0;
        }
    }

    return true;
}
Matrix4f Matrix4f::LookAtLH(const Vector3f& eye, const Vector3f& at, const Vector3f& up)
{
    Vector3f z = (at - eye).Normalized();  // Forward
    Vector3f x = up.Cross(z).Normalized(); // Right
    Vector3f y = z.Cross(x);

    Matrix4f m(x.x,  x.y,  x.z,  -(x.Dot(eye)),
               y.x,  y.y,  y.z,  -(y.Dot(eye)),
               z.x,  z.y,  z.z,  -(z.Dot(eye)),
               0,    0,    0,    1 ); 
    return m;
}
void CRigidBody::HandleSphereToSphereCollision(CCollisionMessage* ColMsg)
{
	CVehicle* Car = (CVehicle*)ColMsg->GetEntity();
	Vector3f CenterToCenter = *ColMsg->GetCenterToCenter();

	// set translate
	m_vReflection = CenterToCenter*0.05f;
	m_vPosition = m_translate;
	m_vDirectionWhenDisturbed = m_vReflection;

	// set rotation
	if (CenterToCenter.Length() == 0.0f) CenterToCenter = Vector3f(1.0f, 0.0f, 0.0f);
	float theta1 = (CenterToCenter.Dot(Car->GetVehicleHeadingWC()))/(CenterToCenter.Length()*Car->GetVehicleHeadingWC().Length());
	Vector3f CP = CenterToCenter.Cross(Vector3f(0.0f, 1.0f, 0.0f));
	float theta2 = (CP.Dot(Car->GetVehicleHeadingWC()))/(CP.Length()*Car->GetVehicleHeadingWC().Length());

//	CLog::GetLog().Write(LOG_DEBUGOVERLAY, 120, "theta1 = %f", theta1);
//	CLog::GetLog().Write(LOG_DEBUGOVERLAY, 121, "theta2 = %f", theta2);

	float spin;
	if (0.0f < theta1 && theta1 < 1.0f) {
		// LOWER-LEFT QUADRANT
		if (0.0f < theta2 && theta2 < 1.0f) {
			spin = theta2;
		}
		// LOWER-RIGHT QUADRANT
		else {
			spin = theta2;
		}
	}
	else {
		// UPPER-LEFT QUADRANT
		if (0.0f < theta2 && theta2 < 1.0f) {
			spin = -theta2;
		}
		// UPPER-RIGHT QUADRANT
		else {
			spin = -theta2;
		}
	}

	spin *= RIGIDBODY_SPIN_FACTOR;
	m_vRotation = Vector3f(0.0f, spin, 0.0f);

	// actually set it!
	Car->SetVehicleVelocityLC(0.0f);
	Car->SetVehiclePositionLC(Vector3f(m_vPosition.X(), m_vPosition.Z(), m_vPosition.Y()));

	disturbed = true;
}
Beispiel #8
0
bool RtIntersect::RayTriangle( const Vector3f & rayStart, const Vector3f & rayDir,
							const Vector3f & v0, const Vector3f & v1, const Vector3f & v2,
							float & t0, float & u, float & v )
{
	assert( rayDir.IsNormalized() );

	const Vector3f edge1 = v1 - v0;
	const Vector3f edge2 = v2 - v0;

	const Vector3f tv = rayStart - v0;
	const Vector3f pv = rayDir.Cross( edge2 );
	const Vector3f qv = tv.Cross( edge1 );
	const float det = edge1.Dot( pv );

	// If the determinant is negative then the triangle is backfacing.
	if ( det <= 0.0f )
	{
		return false;
	}

	// This code has been modified to only perform a floating-point
	// division if the ray actually hits the triangle. If back facing
	// triangles are not culled then the sign of 's' and 't' need to
	// be flipped. This can be accomplished by multiplying the values
	// with the determinant instead of the reciprocal determinant.

	const float s = tv.Dot( pv );
	const float t = rayDir.Dot( qv );

	if ( s >= 0.0f && s <= det )
	{
		if ( t >= 0.0f && s + t <= det )
		{
			// If the determinant is almost zero then the ray lies in the triangle plane.
			// This comparison is done last because it is usually rare for
			// the ray to lay in the triangle plane.
			if ( fabsf( det ) > Math<float>::SmallestNonDenormal )
			{
				const float rcpDet = 1.0f / det;
				t0 = edge2.Dot( qv ) * rcpDet;
				u = s * rcpDet;
				v = t * rcpDet;
				return true;
			}
		}
	}

	return false;
}
Beispiel #9
0
//--------------------------------------------------------------------------------
Plane3f::Plane3f(const Vector3f& normal, const Vector3f& v)
{
	auto d = -normal.Dot(v);
	m_fComponents[0] = normal.x;
	m_fComponents[1] = normal.y;
	m_fComponents[2] = normal.z;
	m_fComponents[3] = d;
}
Beispiel #10
0
//-----------------------------------------------------------
float LOCAL_DistToPlane(Vector3f * p, Vector3f * p0, Vector3f * p1, Vector3f * p2)
{
	Vector3f q0 = *p1 - *p0;
	Vector3f q1 = *p2 - *p0;
	Vector3f c = (q0.Cross(q1)).Normalized();
	Vector3f q = *p - *p0;
	return(c.Dot(q));
}
Beispiel #11
0
void ModelViewer::OnDraw()
{
	// Animate the model if requested
	if (mAnimate)
	{
		ulong delta = Time::GetDeltaMS();

		if (delta > 0)
		{
			const Vector3f axis (0.0f, 0.0f, 1.0f);
			Quaternion rot (axis, -Float::Sin(0.0005f * delta));
			mStage->SetRelativeRotation( rot * mStage->GetRelativeRotation() );
		}
	}

	// Fade out the status bar
	if (mSbHighlight != 0 && mTimestamp != 0.0f)
	{
		float current = Time::GetTime();
		float factor = (current - mTimestamp) / 2.0f;
		factor = Float::Clamp(factor, 0.0f, 1.0f);
		mSbHighlight->SetAlpha( (1.0f - factor) * 0.85f );
		if (factor == 1.0f) mTimestamp = 0.0f;
	}

	// If there was a request to reset the viewpoint, now should be a good time as we know what's visible
	if (mResetCamera > 0 && mResetCamera++ > 1)
	{
		mResetCamera = 0;
		const Bounds& bounds = mInst->GetAbsoluteBounds();

		if (bounds.IsValid())
		{
			const Vector3f& center (bounds.GetCenter());
			Vector3f total = bounds.GetMax() - bounds.GetMin();
			total.Normalize();

			// Default positions should always be at a downward angle
			Vector3f down	  (0.175f, -0.5f, -1.0f );
			Vector3f straight ( 0.35f, -1.0f, -0.35f);

			down.Normalize();
			straight.Normalize();

			// How much the camera will be angled downward depends on the dot product
			float dot = total.Dot( Vector3f(0.0f, 0.0f, 1.0f) );
			Vector3f dir ( Interpolation::Linear(down, straight, dot) );

			// Distance should be far enough away to view the entire model
			float distance = Float::Clamp(bounds.GetRadius() * 1.2f, 1.0f, mCam->GetDolly().z);

			// Animate the camera to the calculated position
			mCam->Stop();
			mCam->AnimateTo(center, dir, distance, 0.5f);
		}
	}
}
Beispiel #12
0
void Projectile::Update(float elapsedTime) 
{
	// Test si les conditions de fin du projectile sont vraies
	if (m_timeToLive <= 0 || !m_shot || elapsedTime == 0)
		return;

	// Test si atteint la cible
	if(	abs(m_destination.x - m_pos.x) < m_collisionRadius.x 
		&& abs(m_destination.y - m_pos.y) < m_collisionRadius.y 
		&& abs(m_destination.z - m_pos.z) < m_collisionRadius.z) {
			Hit();
			return;
	}
	Vector3f speed = m_rot * m_speed;
	speed = speed * m_speed.Lenght();
	// Met a jour la valeur de la vitesse en 
	// fonction de l'acceleration et du temps
	m_speed += m_acceleration * elapsedTime;

	m_timeToLive -= elapsedTime;

	// distance entre le projectile et sa destination
	// chemin le plus court
	Vector3f distance;
	distance.x = m_pos.x - m_destination.x;
	distance.y = m_pos.y - m_destination.y;
	distance.z = m_pos.z - m_destination.z;

	// calculer l'angle entre les 2 vecteurs
	// fix imprecision float
	float n = distance.Dot(speed) / (distance.Lenght() * speed.Lenght());
	if (n > 1)
		n = 1;
	else if (n < -1)
		n = -1;
	float angleA = acos(n);
	std::cout << angleA << std::endl;
	Vector3f axis = distance.Cross(speed);
	axis.Normalize();
	// rotation autour de laxe
	float rotation;
	if (abs(angleA) >= m_maxRot && abs(angleA) < PII - m_maxRot) {
		rotation = (angleA > 0) ? -m_maxRot : m_maxRot;
		rotation *= elapsedTime;
	}
	else
		rotation = angleA - PII;
	Quaternion q;
	q.FromAxis(rotation, axis);
	q.Normalise();

	m_rot = q * m_rot;
	m_rot.Normalise();
	
	// calcul la nouvelle position
	m_pos += speed * elapsedTime;
}
Beispiel #13
0
// -1 to 1 range on panelMatrix, returns -2,-2 if looking away from the panel
Vector2f	GazeCoordinatesOnPanel( const Matrix4f & viewMatrix, const Matrix4f panelMatrix, const bool floatingPanel )
{
	// project along -Z in the viewMatrix onto the Z = 0 plane of activityMatrix

	const Vector3f viewForward = MatrixForward( viewMatrix ).Normalized();

	Vector3f panelForward;
	float approach;
	if ( floatingPanel )
	{
		Matrix4f mat = panelMatrix;
		mat.SetTranslation( Vector3f( 0.0f ) );
		panelForward = mat.Transform( Vector3f( 0.0f, 0.0f, 1.0f ) ).Normalized();
		approach = viewForward.Dot( panelForward );
		if ( approach >= -0.1 )
		{	// looking away
			return Vector2f( -2.0f, -2.0f );
		}
	}
	else
	{
		panelForward = -MatrixForward( panelMatrix ).Normalized();
		approach = viewForward.Dot( panelForward );
		if ( approach <= 0.1 )
		{	// looking away
			return Vector2f( -2.0f, -2.0f );
		}
	}

	const Matrix4f panelInvert = panelMatrix.Inverted();
	const Matrix4f viewInvert = viewMatrix.Inverted();

	const Vector3f viewOrigin = viewInvert.Transform( Vector3f( 0.0f ) );
	const Vector3f panelOrigin = MatrixOrigin( panelMatrix );

	// Should we disallow using panels from behind?
	const float d = panelOrigin.Dot( panelForward );
	const float t = -( viewOrigin.Dot( panelForward ) + d ) / approach;

	const Vector3f impact = viewOrigin + viewForward * t;
	const Vector3f localCoordinate = panelInvert.Transform( impact );

	return Vector2f( localCoordinate.x, localCoordinate.y );
}
//----------------------------------------------------------------------------
void BouncingTetrahedra::ComputeImpulseMagnitude (float* preRelVelocities,
    float* impulseMagnitudes)
{
    // The coefficient of restitution.
    float restitution = 0.8f;
    float temp = 20.0f*NUM_TETRA;
    if (mTotalKE < temp)
    {
        restitution *= 0.5f*mTotalKE/temp;
    }
    float coeff = -(1.0f + restitution);

    for (int i = 0; i < mNumContacts; ++i)
    {
        if (preRelVelocities[i] < 0.0f)
        {
            const Contact& contact = mContacts[i];
            const RigidBodyf& bodyA = *contact.A;
            const RigidBodyf& bodyB = *contact.B;

            Vector3f velDiff = bodyA.GetLinearVelocity() -
                bodyB.GetLinearVelocity();
            Vector3f relA = contact.PA - bodyA.GetPosition();
            Vector3f relB = contact.PB - bodyB.GetPosition();
            Vector3f AxN = relA.Cross(contact.N);
            Vector3f BxN = relB.Cross(contact.N);
            Vector3f JInvAxN = bodyA.GetWorldInverseInertia()*AxN;
            Vector3f JInvBxN = bodyB.GetWorldInverseInertia()*BxN;

            float numer = coeff*(contact.N.Dot(velDiff)
                + bodyA.GetAngularVelocity().Dot(AxN)
                - bodyB.GetAngularVelocity().Dot(BxN));

            float denom = bodyA.GetInverseMass() + bodyB.GetInverseMass()
                + AxN.Dot(JInvAxN) + BxN.Dot(JInvBxN);

            impulseMagnitudes[i] = numer/denom;
        }
        else
        {
            impulseMagnitudes[i] = 0.0f;
        }
    }
}
Vector3f SlideMove(
		const Vector3f & footPos,
		const float eyeHeight,
		const Vector3f & moveDirection,
		const float moveDistance,
		const CollisionModel & collisionModel,
		const CollisionModel & groundCollisionModel
	    )
{
	// Check for collisions at eye level to prevent slipping under walls.
	Vector3f eyePos = footPos + UpVector * eyeHeight;

	// Pop out of any collision models.
	collisionModel.PopOut( eyePos );

	{
		Planef fowardCollisionPlane;
		float forwardDistance = moveDistance;
		if ( !collisionModel.TestRay( eyePos, moveDirection, forwardDistance, &fowardCollisionPlane ) )
		{
			// No collision, move the full distance.
			eyePos += moveDirection * moveDistance;
		}
		else
		{
			// Move up to the point of collision.
			eyePos += moveDirection * forwardDistance;

			// Project the remaining movement onto the collision plane.
			const float COLLISION_BOUNCE = 0.001f;	// don't creep into the plane due to floating-point rounding
			const float intoPlane = moveDirection.Dot( fowardCollisionPlane.N ) - COLLISION_BOUNCE;
			const Vector3f slideDirection = ( moveDirection - fowardCollisionPlane.N * intoPlane );

			// Try to finish the move by sliding along the collision plane.
			float slideDistance = moveDistance;
			collisionModel.TestRay( eyePos - UpVector * RailHeight, slideDirection, slideDistance, NULL );

			eyePos += slideDirection * slideDistance;
		}
	}

	if ( groundCollisionModel.Polytopes.GetSizeI() != 0 )
	{
		// Check for collisions at foot level, which allows following terrain.
		float downDistance = 10.0f;
		groundCollisionModel.TestRay( eyePos, - UpVector, downDistance, NULL );

		// Maintain the minimum camera height.
		if ( eyeHeight - downDistance < 1.0f )
		{
			eyePos += UpVector * ( eyeHeight - downDistance );
		}
	}

	return eyePos - UpVector * eyeHeight;
}
Beispiel #16
0
// Compute a rotation required to transform "estimated" into "measured"
// Returns an approximation of the goal rotation in the Simultaneous Orthogonal Rotations Angle representation
// (vector direction is the axis of rotation, norm is the angle)
Vector3f SensorFusion_ComputeCorrection(Vector3f measured, Vector3f estimated)
{
    measured.Normalize();
    estimated.Normalize();
    Vector3f correction = measured.Cross(estimated);
    float cosError = measured.Dot(estimated);
    // from the def. of cross product, correction.Length() = sin(error)
    // therefore sin(error) * sqrt(2 / (1 + cos(error))) = 2 * sin(error / 2) ~= error in [-pi, pi]
    // Mathf::Tolerance is used to avoid div by 0 if cos(error) = -1
    return correction * sqrt(2 / (1 + cosError + Mathf::Tolerance));
}
Beispiel #17
0
// -1 to 1 range on screenMatrix, returns -2,-2 if looking away from the screen
Vector2f MoviePlayerView::GazeCoordinatesOnScreen( const Matrix4f & viewMatrix, const Matrix4f screenMatrix ) const
{
	// project along -Z in the viewMatrix onto the Z = 0 plane of screenMatrix
	const Vector3f viewForward = MatrixForward( viewMatrix ).Normalized();

	Vector3f screenForward;
	if ( Cinema.SceneMgr.FreeScreenActive )
	{
		// FIXME: free screen matrix is inverted compared to bounds screen matrix.
		screenForward = -Vector3f( screenMatrix.M[0][2], screenMatrix.M[1][2], screenMatrix.M[2][2] ).Normalized();
	}
	else
	{
		screenForward = -MatrixForward( screenMatrix ).Normalized();
	}

	const float approach = viewForward.Dot( screenForward );
	if ( approach <= 0.1f )
	{
		// looking away
		return Vector2f( -2.0f, -2.0f );
	}

	const Matrix4f panelInvert = screenMatrix.Inverted();
	const Matrix4f viewInvert = viewMatrix.Inverted();

	const Vector3f viewOrigin = viewInvert.Transform( Vector3f( 0.0f ) );
	const Vector3f panelOrigin = MatrixOrigin( screenMatrix );

	// Should we disallow using panels from behind?
	const float d = panelOrigin.Dot( screenForward );
	const float t = -( viewOrigin.Dot( screenForward ) + d ) / approach;

	const Vector3f impact = viewOrigin + viewForward * t;
	const Vector3f localCoordinate = panelInvert.Transform( impact );

	return Vector2f( localCoordinate.x, localCoordinate.y );
}
Beispiel #18
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;
	}
}
Beispiel #19
0
//----------------------------------------------------------------------------------------------------
Matrix4f Matrix4f::LookAtLHMatrix( Vector3f& eye, Vector3f& at, Vector3f& up )
{
	// This method is based on the method of the same name from the D3DX library.

	Matrix4f ret;

	Vector3f zaxis = at - eye; 
	zaxis.Normalize();
	
	Vector3f xaxis = up.Cross( zaxis );
	xaxis.Normalize();

	Vector3f yaxis = zaxis.Cross( xaxis );

	ret.m_afEntry[ 0] = xaxis.x;
	ret.m_afEntry[ 1] = yaxis.x;
	ret.m_afEntry[ 2] = zaxis.x;
	ret.m_afEntry[ 3] = 0.0f;

	ret.m_afEntry[ 4] = xaxis.y;
	ret.m_afEntry[ 5] = yaxis.y;
	ret.m_afEntry[ 6] = zaxis.y;
	ret.m_afEntry[ 7] = 0.0f;

	ret.m_afEntry[ 8] = xaxis.z;
	ret.m_afEntry[ 9] = yaxis.z;
	ret.m_afEntry[10] = zaxis.z;
	ret.m_afEntry[11] = 0.0f;

	ret.m_afEntry[12] = -(xaxis.Dot(eye));
	ret.m_afEntry[13] = -(yaxis.Dot(eye));
	ret.m_afEntry[14] = -(zaxis.Dot(eye));
	ret.m_afEntry[15] = 1.0f;

	return( ret );
}
Beispiel #20
0
void ExtendedWmlCamera::DollyZoom( float fDistance )
{
	Vector3f in(GetDirection());
	in.Normalize();
	Vector3f translate( in * fDistance );

	// if new camera point is past target point, ignore this dolly request
	Vector3f newEye = GetLocation() + translate;
	Vector3f normDir = GetDirection();
	normDir.Normalize();
	if ( newEye.Dot(normDir) < m_ptTarget.Dot(normDir) ) {

		if (!m_bUsePerspective)
			OrthoDollyZoom( fDistance );

		SetTargetFrame( GetLocation() + translate, GetLeft(), GetUp(), m_ptTarget );
	}
}
//----------------------------------------------------------------------------
void DirectionalLight::ComputeDiffuse (const Matrix3f& rkWorldRotate,
    const Vector3f&, float, const Vector3f*, const Vector3f* akNormal,
    int iQuantity, const bool* abVisible, ColorRGB* akDiffuse)
{
    // transform light direction to model space of old mesh
    Vector3f kModelDir = m_kDirection*rkWorldRotate;

    // adjust diffuse color by light intensity
    ColorRGB kAdjDiffuse = m_fIntensity*m_kDiffuse;

    for (int i = 0; i < iQuantity; i++)
    {
        if ( abVisible[i] )
        {
            float fDot = kModelDir.Dot(akNormal[i]);
            if ( fDot < 0.0f )
                akDiffuse[i] -= fDot*kAdjDiffuse;
        }
    }
}
Beispiel #22
0
/* Calculates the GLOBAL rotation of the world, not relative to the world's current rotation
 * * pFrom, the first point,
 * * pDest, the next point. The two points create a line and the line's angle from the x axis is measured */
double SplineTraveler::calcRotation(Vector3f axis, Vector3f pVertex, Vector3f pDest)
{
	//Vector3f firstBranch = (pFrom - pVertex).Normalize();  
	Vector3f secondBranch = (pDest - pVertex).Normalize(); 

	//TODO handle 180 degree case
	float railAngle;
	//dot product angle. magtides of the vectors are already equal to one
	railAngle = acos(axis.Dot(secondBranch));
	if(secondBranch.z > 0)
	{
		railAngle = 2.0*3.14159265 - railAngle;
	}
	rotationAngle = railAngle;
	rotateAxis = secondBranch.Cross(axis);   //axis of this rotation.
	//rotateAxis = Vector3f(0,1,0);
	/*Vector3f xaxis = Vector3f(1,0,0);
	Vector3f yaxis = Vector3f(0,1,0);
	Vector3f zaxis = Vector3f(0,0,1);
	Vector3f point = pDest - pFrom;
	point.y = 0;
	bool tr = false;
	//if(!(point.x == 0 && point.y == 0))
	{
		tr = true;
		double x = acos((point.Dot(xaxis))/(point.Magnitude()));
		if(point.z > 0)
		{
			x = 2.0*3.14159 - x;
		}

		//double y = acos((point.Dot(yaxis))/(point.Magnitude()));
		
		double y = 0;

		double z = 0;//acos((point.Dot(zaxis))/(point.Magnitude()));

		grotation = Vector3f(x,y,z);
	}*/
	return railAngle;
}
Beispiel #23
0
string SBDelanteroL::Accion()
{

    Vector3f b = soccerPerceptor.GetDriveVec(VO_BALL);
    Vector3f myPos = soccerPerceptor.getMyPos();
    int unum=soccerPerceptor.getUnum();

    Vector3f g1 = soccerPerceptor.GetDriveVec(G1R);
    Vector3f g2 = soccerPerceptor.GetDriveVec(G2R);
    Vector3f Dir = (g1 + g2) / 2;

    if (myPos.x() <-10 && b.Length() > 5) {
        return Ir(Dir);
    }

    //Buscar centrar el Balon si esta cerca de las esquinas del contrario
    if (gAbs(myPos.y()) + myPos.x() > 28) {
        Dir += (soccerPerceptor.GetDriveVec(F2L) + soccerPerceptor.GetDriveVec(F1L))*.01;
    }

    Dir -= b;
    Dir = Dir.Normalize();

    float Pesc = Dir.Dot(b) / b.Length(), fact = 0;
    // cout << " Pesc " << Pesc <<" b.Length() " << b.Length() << endl;
    if (Pesc < 0.3 && b.Length() < 2) {
        if (unum % 2 == 0) {
            Dir = soccerPerceptor.GetDriveVec(F1L);
        } else {
            Dir = soccerPerceptor.GetDriveVec(F2L);
        }
        Dir = Dir.Normalize() - b.Normalize();
    } else if (Pesc > 0.75 && b.Length() < 5) {
        Dir = Dir + b;
    } else {
        fact = -b.Length() *.2 - 1;
        Dir = Dir * fact + b;
    }
    return Ir(Dir);
}
//----------------------------------------------------------------------------
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;
}
//----------------------------------------------------------------------------
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;
}
//----------------------------------------------------------------------------
// Compute the intersection of the segment C+t*V, [0,tMax], with a finite
// cylinder.  The cylinder has center P, radius r, height h, and axis
// direction U2.  The set {U0,U1,U2} is orthonormal and right-handed.  In the
// coordinate system of the cylinder, a point A = P + x*U0 + y*U1 + z*U2.  To
// be inside the cylinder, x*x + y*y <= r*r and |z| <= h/2.  The function
// returns 'true' iff [t0,t1] is a nonempty interval.
//----------------------------------------------------------------------------
static bool IntersectLineCylinder (const SphereStruct& sph,
    const Vector3f& V, const Vector3f& P, const Vector3f& U0,
    const Vector3f& U1, const Vector3f& U2, float halfHeight,
    const float tMax, float& t0, float& t1)
{
    t0 = 0.0f;
    t1 = tMax;

    // Clip against the plane caps.
    if (!ClipAgainstPlane(sph.C, V, U2, P + halfHeight*U2, t0, t1)
    ||  !ClipAgainstPlane(sph.C, V, -U2, P - halfHeight*U2, t0, t1))
    {
        return false;
    }

    // In cylinder coordinates, C+t*V = P + x(t)*U0 + y(t)*U1 + z(t)*U2,
    // x(t) = Dot(U0,C+t*V-P) = a0 + t*b0, y(t) = Dot(U1,C+t*V-P) = a1 + t*b1
    Vector3f CmP = sph.C - P;
    float a0 = U0.Dot(CmP), b0 = U0.Dot(V);
    float a1 = U1.Dot(CmP), b1 = U1.Dot(V);

    // Clip the segment [t0,t1] against the cylinder wall.
    float x0 = a0 + t0*b0, y0 = a1 + t0*b1, r0Sqr = x0*x0 + y0*y0;
    float x1 = a0 + t1*b0, y1 = a1 + t1*b1, r1Sqr = x1*x1 + y1*y1;
    float rSqr = sph.RSqr;

    // Some case require computing intersections of the segment with the
    // circle of radius r.  This amounts to finding roots for the quadratic
    // Q(t) = x(t)*x(t) + y(t)*y(t) - r*r = q2*t^2 + 2*q1*t + q0, where
    // q0 = a0*a0+b0*b0-r*r, q1 = a0*a1+b0*b1, and q2 = a1*a1+b1*b1.  Compute
    // the coefficients only when needed.
    float q0, q1, q2, T;

    if (r0Sqr > rSqr)
    {
        if (r1Sqr > rSqr)
        {
            q2 = b0*b0 + b1*b1;
            if (q2 > 0.0f)
            {
                q0 = a0*a0 + a1*a1 - rSqr;
                q1 = a0*b0 + a1*b1;
                float discr = q1*q1 - q0*q2;
                if (discr < 0.0f)
                {
                    // The quadratic has no real-valued roots, so the
                    // segment is outside the cylinder.
                    return false;
                }

                float rootDiscr = sqrtf(discr);
                float invQ2 = 1.0f/q2;
                float root0 = (-q1 - rootDiscr)*invQ2;
                float root1 = (-q1 + rootDiscr)*invQ2;

                // We know that (x0,y0) and (x1,y1) are outside the
                // cylinder, so Q(t0) > 0 and Q(t1) > 0.  This reduces
                // the number of cases to analyze for intersection of
                // [t0,t1] and [root0,root1].
                if (t1 < root0 || t0 > root1)
                {
                    // The segment is strictly outside the cylinder.
                    return false;
                }
                else
                {
                    // [t0,t1] strictly contains [root0,root1]
                    t0 = root0;
                    t1 = root1;
                }
            }
            else  // q2 == 0.0f and q1 = 0.0f; that is, Q(t) = q0
            {
                // The segment is degenerate, a point that is outside the
                // cylinder.
                return false;
            }
        }
        else if (r1Sqr < rSqr)
        {
            // Solve nondegenerate quadratic and clip.  There must be a single
            // root T in [t0,t1].  Discard [t0,T].
            q0 = a0*a0 + a1*a1 - rSqr;
            q1 = a0*b0 + a1*b1;
            q2 = b0*b0 + b1*b1;
            t0 = (-q1 - sqrtf(fabsf(q1*q1 - q0*q2)))/q2;
        }
        else // r1Sqr == rSqr
        {
            // The segment intersects the circle at t1.  The other root is
            // necessarily T = -t1-2*q1/q2.  Use it only when T <= t1, in
            // which case discard [t0,T].
            q1 = a0*b0 +a1*b1;
            q2 = b0*b0 + b1*b1;
            T = -t1 - 2.0f*q1/q2;
            t0 = (T < t1 ? T : t1);
        }
    }
    else if (r0Sqr < rSqr)
    {
        if (r1Sqr > rSqr)
        {
            // Solve nondegenerate quadratic and clip.  There must be a single
            // root T in [t0,t1].  Discard [T,t1].
            q0 = a0*a0 + a1*a1 - rSqr;
            q1 = a0*b0 + a1*b1;
            q2 = b0*b0 + b1*b1;
            t1 = (-q1 + sqrtf(fabsf(q1*q1 - q0*q2)))/q2;
        }
        // else:  The segment is inside the cylinder.
    }
    else // r0Sqr == rSqr
    {
        if (r1Sqr > rSqr)
        {
            // The segment intersects the circle at t0.  The other root is
            // necessarily T = -t0-2*q1/q2.  Use it only when T >= t0, in
            // which case discard [T,t1].
            q1 = a0*b0 + a1*b1;
            q2 = b0*b0 + b1*b1;
            T = -t0 - 2.0f*q1/q2;
            t1 = (T > t0 ? T : t0);
        }
        // else:  The segment is inside the cylinder.
    }

    return true;
}
//----------------------------------------------------------------------------
void OpenGLRenderer::Draw (const PlanarReflection& rkPReflection)
{
    TriMeshPtr spkPlane = rkPReflection.GetPlane();
    NodePtr spkCaster = rkPReflection.GetCaster();

    if ( !m_bCapPlanarReflection )
    {
        // The effect is not supported.  Draw normally without the mirror.
        // The OnDraw calls are necessary to handle culling and camera plane
        // state.
        spkPlane->OnDraw(*this);
        spkCaster->OnDraw(*this);
        return;
    }

    if ( m_bDrawingReflected )
    {
        // Some other object is currently doing a planar reflection.  Do not
        // allow the recursion and just draw normally.
        Renderer::Draw(spkCaster);
        SetState(spkPlane->GetRenderStateArray());
        Draw(*spkPlane);
        return;
    }

    // TO DO:  Support for multiple mirrors could be added here by iterating
    // over the section delimited by START PER-MIRROR and END PER-MIRROR.
    // None of the OpenGL code needs to change, just the mirror-plane data.

    // START PER-MIRROR

    // enable depth buffering
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    glDepthMask(GL_TRUE);

    // Step 1 setup and render.
    // Render the mirror into the stencil plane (but no color).  All visible
    // mirror pixels will have the stencil value of the mirror.
    // Make sure that no pixels are written to the depth buffer or color
    // buffer, but use depth buffer testing so that the stencil will not
    // be written where the plane is behind something already in the
    // depth buffer.
    glEnable(GL_STENCIL_TEST);
    glStencilFunc(GL_ALWAYS,rkPReflection.GetStencilValue(),~0);
    glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);
    glStencilMask(~0);
    glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
    glDepthMask(GL_FALSE);
    Draw(*spkPlane);


    // Step 2 setup and render.
    // Render the mirror plane again by only processing pixels where
    // the stencil buffer contains the reference value.  This time
    // there is no changes to the stencil buffer and the depth buffer value
    // is reset to the far view clipping plane (this is done by setting the
    // range of depth values in the viewport volume to be [1,1].  Since the
    // mirror plane cannot also be semi-transparent, then there we do not
    // care what is behind the mirror plane in the depth buffer.  We need
    // to move the depth buffer values back where the mirror plane will
    // be rendered so that when the reflected caster is rendered
    // it can be depth buffered correctly (note that the rendering
    // of the reflected caster will cause depth value to be written
    // which will appear to be behind the mirror plane).  Enable writes
    // to the color buffer.  Later when we want to render the reflecting
    // plane and have it blend with the background (which should contain
    // the reflected caster), we want to use the same blending function
    // so that the pixels where the reflected caster was not rendered
    // will contain the reflecting plane and in that case, the blending
    // result will have the reflecting plane appear to be opaque when
    // in reality it was blended with blending coefficients adding to one.
    SetState(spkPlane->GetRenderStateArray());
    glDepthRange(1.0,1.0);
    glDepthFunc(GL_ALWAYS);
    glStencilFunc(GL_EQUAL,rkPReflection.GetStencilValue(),~0);
    glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP);
    glStencilMask(~0);
    glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
    glDepthMask(GL_TRUE);
    Draw(*spkPlane);


    // Step 2 cleanup.
    // Restore the depth range and depth testing function.
    glDepthFunc(GL_LESS);
    glDepthRange(0.0,1.0);


    // Step 3 setup.
    // We are about to render the reflected caster.  For that, we
    // will need to compute the reflection viewing matrix.
    Vector3f kCurrNormal = spkPlane->WorldRotate()*
        rkPReflection.GetPlaneNormal();
    Vector3f kCurrPoint = spkPlane->WorldTranslate()+spkPlane->WorldScale()*
      (spkPlane->WorldRotate()*rkPReflection.GetPointOnPlane());
    GLdouble adPlaneEq[4] = { -kCurrNormal.X(), -kCurrNormal.Y(),
        -kCurrNormal.Z(), kCurrNormal.Dot(kCurrPoint) };
    adPlaneEq[0] = -adPlaneEq[0];
    adPlaneEq[1] = -adPlaneEq[1];
    adPlaneEq[2] = -adPlaneEq[2];
    adPlaneEq[3] = -adPlaneEq[3];
    GLfloat aafReflectionMatrix[4][4];
    ComputeReflectionMatrix(aafReflectionMatrix,adPlaneEq);

    // Save the modelview transform before replacing it with
    // the viewing transform which will handle the reflection.
    glPushMatrix();
    glMultMatrixf(&aafReflectionMatrix[0][0]);

    // Setup a clip plane so that only objects above the mirror plane
    // get reflected.
    glClipPlane(GL_CLIP_PLANE0,adPlaneEq);
    glEnable(GL_CLIP_PLANE0);


    // Reverse the cull direction.  Allow for models that are not necessarily
    // set up with front or back face culling.
    m_bReverseCullState = true;

    // We do not support mirrors reflecting mirrors.  They just appear as the
    // base color in a reflection.
    m_bDrawingReflected = true;


    // Step 3 render.
    // Render the reflected caster.  Only render where the stencil buffer
    // contains the reference value.  Enable depth testing.  This time
    // allow writes to the color buffer.
    glStencilFunc(GL_EQUAL,rkPReflection.GetStencilValue(),~0);
    glStencilOp(GL_KEEP,GL_KEEP,GL_KEEP);
    glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
    Renderer::Draw(spkCaster);


    // Step 3 cleanup.
    // Restore state.
    m_bDrawingReflected = false;
    m_bReverseCullState = false;
    glDisable(GL_CLIP_PLANE0);
    glPopMatrix();


    // Step 4 setup.
    // We are about to render the reflecting plane again.  Reset to
    // the render state for the reflecting plane.  We want to blend
    // the reflecting plane with what is already in the color buffer
    // where the reflecting plane will be rendered, particularly
    // either the image of the reflected caster or the reflecting
    // plane.  All we want to change about the rendering of the
    // reflecting plane at this stage is to force the alpha channel
    // to always be the reflectance value for the reflecting plane.
    // Render the reflecting plane wherever the stencil buffer is set
    // to the reference value.  This time clear the stencil buffer
    // reference value where it is set.  Perform the normal depth
    // buffer testing and writes.  Allow the color buffer to be
    // written to, but this time blend the relecting plane with
    // the values in the color buffer based on the reflectance value.
    // Note that where the stencil buffer is set, the color buffer
    // has either color values from the reflecting plane or the
    // reflected caster.  Blending will use src=1-alpha (reflecting plane)
    // and dest=alpha background (reflecting plane or reflected caster).
    SetState(spkPlane->GetRenderStateArray());
    glEnable(GL_BLEND);
    glBlendColorEXT(0.0f,0.0f,0.0f,rkPReflection.GetReflectance());
    glBlendFunc(GL_ONE_MINUS_CONSTANT_ALPHA_EXT,GL_CONSTANT_ALPHA_EXT);
    glStencilFunc(GL_EQUAL,rkPReflection.GetStencilValue(),~0);
    glStencilOp(GL_KEEP,GL_KEEP,GL_INVERT);
    glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
    Draw(*spkPlane);


    // Step 4 cleanup.
    glDisable(GL_BLEND);
    glDisable(GL_STENCIL_TEST);

    // END PER-MIRROR

    // render the objects as usual
    Renderer::Draw(spkCaster);
}
Beispiel #28
0
bool Plane::IsFacing(const Vector3f& point)
{
	Vector3f v = point - Point;

	return v.Dot(Normal) > 0.0f;
}
Beispiel #29
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();
}
Beispiel #30
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);
}