Beispiel #1
0
int CVMergeLines::Process(CVPipeline * pipe)
{
	for (int i = 0; i < pipe->lines.Size(); ++i)
	{
		Line & line1 = pipe->lines[i];
		// Make sure it's normalized.
		Vector3f dir = line1.direction.NormalizedCopy();
		for (int j = 0; j < pipe->lines.Size(); ++j)
		{
			if (i == j)
				continue;

			Line & line2 = pipe->lines[j];	
			// Check that the directions align.
			Vector3f dir2 = line2.direction.NormalizedCopy();

			if (AbsoluteValue(dir.DotProduct(dir2)) < 0.95f)
				continue;
		
			// Check overlap distance. If not overlapping at all, skip 'em.
	//		if (line1.stop.x < line2.start.x ||
		//		line1.start.x > line2.stop.x)
		//		continue;

			// Check the distance between the lines.
			float distance = (line1.start - line2.start).Length();
			if (distance < maxDistance->GetFloat())
			{
				// Merge 'em
				line1.Merge(line2);
				pipe->lines.RemoveIndex(j);
				--j;
			}
		}
	}
	returnType = CVReturnType::LINES;
	return returnType;
}
Beispiel #2
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;
}
Beispiel #3
0
/// For NormalMapping~
void Mesh::CalculateUVTangents()
{
	bool defaultCalcUVTangents = false;
	if (!defaultCalcUVTangents)
		return; 
	// Not working anyway.. fit it.
	if (this->uvs.Size() == 0)
	{
		std::cout<<"\nNo UVs found. Skipping.";
		return;
	}
	for (int i = 0; i < faces.Size(); ++i)
	{
		MeshFace * f = &faces[i];
		if (f->numVertices < 3)
            continue;

		// Reference:
		// http://www.terathon.com/code/tangent.html

		/// 3 Points on the faces
		Vector3f v1, v2, v3;
		v1 = vertices[f->vertices[0]];
		v2 = vertices[f->vertices[1]];
		v3 = vertices[f->vertices[2]];

		Vector2f uv1, uv2, uv3;
		uv1 = uvs[f->uvs[0]];
		uv2 = uvs[f->uvs[1]];
		uv3 = uvs[f->uvs[2]];

		/// Diff-vectors.
		Vector3f v1ToV2 = v2 - v1,
			v1ToV3 = v3 - v1;
		Vector2f uv1ToUV2 = uv2 - uv1,
			uv1ToUV3 = uv3 - uv1;

		Vector2f deltaUV1 = uv1ToUV2,
			deltaUV2 = uv1ToUV3;
		Vector3f deltaPos1 = v1ToV2;
		Vector3f deltaPos2 = v1ToV3;
	  // Edges of the triangle : postion delta
 		float r = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x);
		Vector3f tangent = (deltaPos1 * deltaUV2.y   - deltaPos2 * deltaUV1.y)*r;
		Vector3f biTangent = (deltaPos2 * deltaUV1.x   - deltaPos1 * deltaUV2.x)*r;

		/// Check handed-ness.
		Vector3f crossProduct =  normals[f->normals[0]].CrossProduct(tangent);
		float dotProduct = crossProduct.DotProduct(biTangent);
//		std::cout<<"\nHandednesS: "<<dotProduct > 0;
		if (dotProduct < 0)
			tangent *= -1;

		/// Add the tanget and bitangnet
		f->uvTangent = tangent;
		f->uvBiTangent = biTangent;


		/// Help http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-13-normal-mapping/		
	}
}
Beispiel #4
0
void PhysicsManager::ApproximateIntegrate(Entity * entity, float timeSinceLastUpdate)
{
	PhysicsProperty * physics = entity->physics;
   	// Calculate velocity using the moment?
	physics->CalculateVelocity();
	float currentVelocity = physics->velocity.Length();
    float velocitySquared = currentVelocity * currentVelocity;
    if (currentVelocity > 0.0001f)
	{
		entity->localPosition += physics->velocity * timeSinceLastUpdate;
        physics->state |= CollisionState::COLLIDING;
        physics->state &= ~CollisionState::IN_REST;

		/// Only apply this if we're exceeding stuffs
        /** http://en.wikipedia.org/wiki/Drag_%28physics%29
            Drag depends on the properties of the fluid and on the size, shape,
            and speed of the object. One way to express this is by means of the drag equation:
                Fd = 0.5 * p * v^2 * Cd * A
            where
                FD is the drag force,
                p is the density of the fluid,[12]
                v is the speed of the object relative to the fluid,
                A is the cross-sectional area, and
                Cd is the drag coefficient – a dimensionless number.

            The drag coefficient depends on the shape of the object and on the Reynolds number:
                Re
        */
#define AIR_DENSITY	1.225 // kg/m^3
#define PT_VELOCITY dynamicEntity->physics->velocity
#define MASS 500
        if (currentVelocity > 10.f)
		{
            float dragCoefficient = 0.001f;
            float crossSectionalArea = physics->physicalRadius;
            float dragForce = 0.5f * airDensity * velocitySquared * dragCoefficient * crossSectionalArea;
            float dragEnergy = dragForce * timeSinceLastUpdate;
            float velocityDecrease = sqrt(dragEnergy / MASS * 2);

            // And decrement the velocity.
			float preVel = physics->velocity.Length();
			Vector3f decrease = - physics->velocity.NormalizedCopy() * velocityDecrease;
            physics->velocity += decrease;
			float postVel = physics->velocity.Length();
		    // This looks like it should always be true,
            // but it's false if x is a NaN.
            if (!(physics->velocity[0] == physics->velocity[0])){
      //          std::cout<<"\nwosh-";
            }
        }
    }
#ifdef _DEBUG
    // Make object bounce up again if at -100.0f made for testing physics only
/*		if (dynamicEntity[i]->position[1] < -100.0f && dynamicEntity[i]->physics->velocity[1] < 0){
        dynamicEntity[i]->position[1] = -100.0f;
        dynamicEntity[i]->physics->velocity[1] = dynamicEntity[i]->physics->velocity[1] * -0.4;
    }
    */
#endif

    // Add gravitation and acceleration to velocities
    if (!(physics->state & CollisionState::IN_REST))
	{
//                dynamicEntity->physics->velocity += this->gravitation * timeSinceLastUpdate;
		physics->linearMomentum += this->gravitation * physics->mass * timeSinceLastUpdate * physics->gravityMultiplier;
//                std::cout<<"Applying gravitation to velocity.";
    }
        

    // Always apply acceleration unless otherwise noted.
    if (physics->acceleration.MaxPart() > ZERO)
	{
		Vector3f velIncrease = entity->rotationMatrix.Product(physics->acceleration);
		velIncrease *= timeSinceLastUpdate;
        Vector3f momentumIncrease = velIncrease * physics->mass;
		physics->linearMomentum += momentumIncrease;
//                std::cout<<"Accelerating  velocityIncrease: "<<velocityIncrease<<" newVel: "<<dynamicEntity->physics->velocity;
        
        physics->state |= CollisionState::COLLIDING;
        physics->state &= ~CollisionState::IN_REST;
    }
	
	/// Apply angular velocities
	float angularVelocitySquared = physics->angularVelocity.LengthSquared();
	float angularVelocity = sqrt(angularVelocitySquared);
	if (angularVelocitySquared > 0.000001f)
	{
        Vector3f lookAtPreRotate = entity->rotationMatrix * Vector4d(0,0,-1,1);

		if (physics->useQuaternions)
		{
			///Calculate with quaternions.
			PhysicsProperty * physics = entity->physics;
			Quaternion & orientation = physics->orientation;
			if (physics->angularVelocity.MaxPart() > 0){

	//              std::cout<<"\nQuaternion, pre: "<<physics->orientation;

	//            std::cout<<"\nTime since last update: "<<timeSinceLastUpdate;
				physics->orientation.ApplyAngularVelocity(physics->angularVelocity, timeSinceLastUpdate);
				physics->orientation.Normalize();
	  //          std::cout<<" post: "<<physics->orientation;
	   //         std::cout<<"\nAngular Velocity: "<<physics->angularVelocity;
			}
		}
		// Euclidean.
		else {
			/// Default gimbal-locking rotations
			entity->Rotate(physics->angularVelocity * timeSinceLastUpdate);
		}
		// Recalculate the matrix?
		entity->RecalculateMatrix();

		/// Adjust velocity in the movement direction depending on our new rotation!
		Vector3f lookAtPostRotate = entity->rotationMatrix * Vector4d(0,0,-1,1);
		float velDotLookatPreRotate = lookAtPreRotate.DotProduct(physics->velocity);
		float velPreRotate = physics->velocity.Length();
		Vector3f oldVelocity = physics->velocity;
		Vector3f velocityMinusLocalZVelocity = oldVelocity - lookAtPreRotate * velDotLookatPreRotate;
		/// Change it.
		physics->velocity = velocityMinusLocalZVelocity +
			velDotLookatPreRotate * lookAtPostRotate * physics->velocityRetainedWhileRotating +
			velDotLookatPreRotate * lookAtPreRotate * (1.0f - physics->velocityRetainedWhileRotating);
		
		/// And apply some damping or it will increase.
		float dampingDueToRotation = pow(0.99754f, angularVelocity);
		// Close, 0.99854f
		physics->velocity *= dampingDueToRotation;
		physics->velocity *= pow(linearDamping, timeSinceLastUpdate);
	//	if (dampingDueToRotation < 0.9985f)
		//	std::cout<<"\nDamping due to rotation: "<<dampingDueToRotation;

		float velPostRotate = physics->velocity.Length();
	//	assert(velPostRotate <= velPreRotate);

		//              std::cout<<"\nUpdating velocity using rotations..? "<<oldVelocity<<" newVel: "<<dynamicEntity->physics->velocity;
        
        // Decrease the velocity as if we've got some air in the way too?
        physics->angularVelocity *= pow(angularDamping, timeSinceLastUpdate);
        physics->state |= CollisionState::COLLIDING;
        physics->state &= ~CollisionState::IN_REST;
    }
	// Apply angular acceleration
    if (physics->angularAcceleration.MaxPart() > ZERO){
        // Screw the quaternions and stuff for now... do it all in local space
        Vector3f angularVelocityIncrease = physics->angularAcceleration * timeSinceLastUpdate;
        physics->angularVelocity += angularVelocityIncrease;
        physics->state |= CollisionState::COLLIDING;
        physics->state &= ~CollisionState::IN_REST;
    }

	// Apply linear damping
	physics->linearMomentum *= pow(physics->linearDamping, timeSinceLastUpdate);

	// Update velocity.
	if (physics->inverseMass == 0)
		physics->inverseMass = 1 / physics->mass;
	physics->velocity = physics->linearMomentum * physics->inverseMass;
	entity->localPosition += physics->velocity * timeSinceLastUpdate;

	// Move position


    // Reposition them in the entityCollisionOctree as needed...!
    // This could maybe be done less times per loop, but that would apply to the whole loop below if so...!

}
Beispiel #5
0
/** All entities sent here should be fully dynamic! 
	Kinematic ones may or may not work (consider adding own integration function).
*/
void SRIntegrator::IntegrateDynamicEntities(List<Entity*> & dynamicEntities, float timeInSeconds)
{
	FirstPersonIntegrator::IntegrateDynamicEntities(dynamicEntities, timeInSeconds);
	for (int i = 0; i < dynamicEntities.Size(); ++i)
	{
		// check for magnetics.
		Entity * entity = dynamicEntities[i];
		if (entity->physics->state & CollisionState::IN_REST)
			continue;
		MagneticProperty * magProp = entity->GetProperty<MagneticProperty>();
		if (magProp)
		{
			// Rotate a bit.
			// Raycast to floor on location, at forward + 1 and side + 1, then rotate so that the ship is flat to the level.
			Vector3f upVec = entity->rotationMatrix.GetColumn(1),
				forwardVec = -entity->rotationMatrix.GetColumn(2),
				rightVec = entity->rotationMatrix.GetColumn(0);
			/// New rolling, check nearest points of track.
			TrackPoint * tp = track->NearestPoint(entity->worldPosition);
			if (!tp || tp->next == 0)
				continue;
			TrackPoint * next = tp->next->next;
			if (!next)
				continue;
			
			/// Desired forward, and up-right vectors of the track.
			Vector3f desForward = (next->pos - tp->pos).NormalizedCopy(),
				desUp = tp->up,
				desRight = tp->right;

			float desForwardDotCurrForward = desForward.NormalizedCopy().DotProduct(forwardVec);
			Vector3f desForwardInCurrDir = desForwardDotCurrForward * desForward; // Less than 1			
			float forwardDotDesUp = forwardVec.DotProduct(desUp);

			// Pitch down or up?
			Vector3f forwardProjected = desForwardDotCurrForward * desForward;
			Vector3f diffForwardCurrForward = forwardVec - desForward;
			/// Pitch needed?
			float pitchNeeded = diffForwardCurrForward.DotProduct(upVec);
//			if (AbsoluteValue(pitchNeeded) > 0.1f)
	//			std::cout<<"\nPitch needed: "<<pitchNeeded;
			if (desForwardDotCurrForward > 0)
				pitchNeeded *= -1;
			// Rotate slightly around side-vector.
			entity->physics->angularVelocity  -= rightVec * pitchNeeded * timeInSeconds * 0.2f;
			
			/// Barrel-roll.
			Vector3f diffUpCurrUp = upVec - desUp;
			float barrelNeeded = diffUpCurrUp.DotProduct(rightVec);
	//		if (AbsoluteValue(barrelNeeded) > 0.1f)
	//			std::cout<<"\nBarrel needed: "<<barrelNeeded;
			entity->physics->angularVelocity += forwardVec * barrelNeeded * timeInSeconds * 0.1f;

			/// Add some velocity towards the next and previous node, acting as magnetism down towards the field?
			entity->physics->velocity -= desUp * timeInSeconds * 5.f + (entity->worldPosition - tp->pos).NormalizedCopy() * 5.f * timeInSeconds;

			/// Old rolling
			/*
			Ray ray(entity->worldPosition, -upVec); // 0 - side, 1 - up, 2 - forward
			ray.collisionFilter = CC_TRACK;
			List<Intersection> iSecs = Physics.Raycast(ray);
			float distBelow = iSecs.Size()? iSecs[0].distance : 0.f;
			// Ray again.
			ray.start += forwardVec;
			iSecs = PhysicsMan.Raycast(ray);
			float distInFront = iSecs.Size()? iSecs[0].distance : 0.f;
			ray.start = entity->worldPosition + rightVec;
			iSecs = PhysicsMan.Raycast(ray);
			float distSide = iSecs.Size()? iSecs[0].distance : 0.f;

			float distPitch = distInFront - distBelow;
			float distRoll = distSide - distBelow;

			// Rotate accordingly for pitch.
			if (distInFront && distBelow && AbsoluteValue(distPitch) < 2.f && distBelow < 5.f)
			{
				// Rotate slightly around side-vector.
				entity->physics->angularVelocity  += rightVec * distPitch * timeInSeconds * 0.2f;
			}
			// Rotate accordingly for roll.
			if (distSide && distBelow && AbsoluteValue(distRoll) < 2.f  && distBelow < 5.f)
			{
				// Rotate slightly around side-vector.
				entity->physics->angularVelocity  -= forwardVec * distRoll * timeInSeconds * 0.1f;
			}


			/// If not above anything, rotate to level-plane.
			if (distBelow == 0)
			{
				magProp->timeOutsideTrack += timeInSeconds;
				if (magProp->timeOutsideTrack > 2.f)
				{
					/// If nothing detected, rotate so that the ship will be level again, by rolling?
					if (forwardVec.y > 0.2f)
					{
						entity->physics->angularVelocity += forwardVec.y * rightVec * timeInSeconds * 0.1f;
					}
					/// Right-vec not aligned with XZ plane? Roll until it is.
					if (AbsoluteValue(rightVec.y) > 0.2f)
					{
						entity->physics->angularVelocity += rightVec.y * forwardVec * timeInSeconds * 0.1f;	
					}
					if (upVec.y < 0.8f)
					{
						// Barrel-roll up.
						entity->physics->angularVelocity += (-1.f + upVec.y) * forwardVec * timeInSeconds * 0.1f;	
					}
				}
			}
			else 
			{
				magProp->timeOutsideTrack = 0;
			}
			*/

			// Same for roll.

			// If not close to a surface... rotate to.. stuff?
//			entity->physics->angularVelocity.x = 0.00f;
		}
	}
}