Exemple #1
0
bool MFCollision_RaySphereTest(const MFVector& rayPos, const MFVector& rayDir, const MFVector& spherePos, float radius, MFRayIntersectionResult *pResult)
{
	MFVector diff = rayPos - spherePos;

	// calcuate the coefficients
	float a = rayDir.MagSquared3();
	float b = (2.0f*rayDir).Dot3(diff);
	float c = diff.MagSquared3() - radius*radius;

	// calculate the stuff under the root sign, if it's negative no (real) solutions exist
	float d = b*b - 4.0f*a*c;
	if(d < 0.0f) // this means ray misses cylinder
		return false;

	float root = MFSqrt(d);
	float rcp2a = MFRcp(2.0f*a);
	float t1 = (-b - root)*rcp2a;
	float t2 = (-b + root)*rcp2a;

	if(t2 < 0.0f || t1 > 1.0f)
		return false;

	if(pResult)
	{
		pResult->time = MFMax(t1, 0.0f);
		pResult->surfaceNormal.Mad3(rayDir, pResult->time, diff);
		pResult->surfaceNormal.Normalise3();
	}

	return true;
}
Exemple #2
0
bool MFCollision_SphereSphereTest(const MFVector &pos1, float radius1, const MFVector &pos2, float radius2, MFCollisionResult *pResult)
{
	MFVector diff = pos2 - pos1;

	if(!pResult)
	{
		return diff.MagSquared3() < radius1*radius1 + radius2*radius2;
	}
	else
	{
		float length = diff.Magnitude3();
		float totalRadius = radius1 + radius2;

		pResult->bCollide = length < totalRadius;

		if(pResult->bCollide)
		{
			pResult->depth = totalRadius - length;
			pResult->normal = -diff.Normalise3();
			pResult->intersectionPoint = diff * ((length / totalRadius) * (radius1 / radius2));
		}

		return pResult->bCollide;
	}
}
Exemple #3
0
void MFCollision_CalculateDynamicBoundingVolume(MFCollisionItem *pItem)
{
	switch(pItem->pTemplate->type)
	{
		case MFCT_Mesh:
		{
			MFCollisionMesh *pMesh = (MFCollisionMesh*)pItem->pTemplate->pCollisionTemplateData;
			MFBoundingVolume &vol = pItem->pTemplate->boundingVolume;

			vol.min = vol.max = vol.boundingSphere = MakeVector(pMesh->pTriangles[0].verts[0], 0.0f);

			for(int a=0; a<pMesh->numTris; a++)
			{
				MFCollisionTriangle &tri = pMesh->pTriangles[a];

				for(int b=0; b<3; b++)
				{
					vol.min = MFMin(vol.min, tri.verts[b]);
					vol.max = MFMin(vol.max, tri.verts[b]);
					vol.min.w = vol.max.w = 0.0f;

					// if point is outside bounding sphere
					MFVector diff = tri.verts[b] - vol.boundingSphere;
					float mag = diff.MagSquared3();

					if(mag > vol.boundingSphere.w*vol.boundingSphere.w)
					{
						// fit sphere to include point
						mag = MFSqrt(mag) - vol.boundingSphere.w;
						mag *= 0.5f;
						diff.Normalise3();
						vol.boundingSphere.Mad3(diff, mag, vol.boundingSphere);
						vol.boundingSphere.w += mag;
					}
				}
			}
			break;
		}

		default:
			MFDebug_Assert(false, "Invalid item type");
	}
}
Exemple #4
0
bool MFCollision_RayCylinderTest(const MFVector& rayPos, const MFVector& rayDir, const MFVector& cylinderPos, const MFVector& cylinderDir, float cylinderRadius, bool capped, MFRayIntersectionResult *pResult, float *pCylinderTime)
{
	MFVector local = rayPos - cylinderPos;

	float rayD = rayDir.Dot3(cylinderDir);
	float T0 = local.Dot3(cylinderDir);

	// bring T0 into 0.0-1.0 range
	float invMagSq = MFRcp(cylinderDir.MagSquared3());
	rayD *= invMagSq;
	T0 *= invMagSq;

	// calculate some intermediate vectors
	MFVector v1 = rayDir - rayD*cylinderDir;
	MFVector v2 = local - T0*cylinderDir;

	// calculate coeff in quadratic formula
	float a = v1.MagSquared3();
	float b = (2.0f*v1).Dot3(v2);
	float c = v2.MagSquared3() - cylinderRadius*cylinderRadius;

	// calculate the stuff under the root sign, if it's negative no (real) solutions exist
	float d = b*b - 4.0f*a*c;
	if(d < 0.0f) // this means ray misses cylinder
		return false;

	float root = MFSqrt(d);
	float rcp2a = MFRcp(2.0f*a);
	float t1 = (-b - root)*rcp2a;
	float t2 = (-b + root)*rcp2a;

	if(t1 > 1.0f || t2 < 0.0f)
		return false; // the cylinder is beyond the ray..

	if(capped || pCylinderTime || pResult)
	{
		float t = MFMax(t1, 0.0f);

		// get the t for the cylinders ray
		MFVector intersectedRay;
		intersectedRay.Mad3(rayDir, t, local);

		float ct = intersectedRay.Dot3(cylinderDir) * invMagSq;

		if(capped && (ct < 0.0f || ct > 1.0f))
		{
			// we need to test the caps

			// TODO: this is REALLY slow!! can be majorly improved!!

			// generate a plane for the cap
			MFVector point, plane;

			if(rayD > 0.0f)
			{
				// the near one
				point = cylinderPos;
				plane = MFCollision_MakePlaneFromPointAndNormal(point, -cylinderDir);
			}
			else
			{
				// the far one
				point = cylinderPos + cylinderDir;
				plane = MFCollision_MakePlaneFromPointAndNormal(point, cylinderDir);
			}

			// test the ray against the plane
			bool collide = MFCollision_RayPlaneTest(rayPos, rayDir, plane, pResult);

			if(collide)
			{
				// calculate the intersection point
				intersectedRay.Mad3(rayDir, pResult->time, rayPos);
				intersectedRay.Sub3(intersectedRay, point);

				// and see if its within the cylinders radius
				if(intersectedRay.MagSquared3() <= cylinderRadius * cylinderRadius)
				{
					return true;
				}
			}

			return false;
		}

		if(pResult)
		{
			pResult->time = t;
			pResult->surfaceNormal.Mad3(cylinderDir, -ct, intersectedRay);
			pResult->surfaceNormal.Normalise3();
		}

		if(pCylinderTime)
		{
			*pCylinderTime = ct;
		}
	}

	return true;
}
MF_API void MFParticleSystem_AddParticle(MFParticleEmitter *pEmitter)
{
	MFParticleEmitterParameters *pE = &pEmitter->params;
	MFParticleSystem *pParticleSystem = pE->pParticleSystem;

	MFParticle *pNew = NULL;
	if(pParticleSystem->particles.GetLength() < pParticleSystem->params.maxActiveParticles)
		pNew = pParticleSystem->particles.Create();

	if(pNew)
	{
		MFParticleParameters *pP = &pParticleSystem->params;

		pNew->colour = pP->colour;
		pNew->life = pP->life;
		pNew->rot = 0.0f;
		pNew->size = pP->size;

		switch(pE->type)
		{
			case MFET_Point:
				pNew->pos = pE->position.GetTrans();
				break;

			case MFET_Sphere:
			case MFET_Disc:
			{
				MFVector offset;

				do
				{
					offset = MakeVector(MFRand_Range(-pE->radius, pE->radius), MFRand_Range(-pE->radius, pE->radius), MFRand_Range(-pE->radius, pE->radius));
				}
				while(offset.MagSquared3() > pE->radius*pE->radius);

				if(pE->type == MFET_Disc)
				{
					// flatten it on to the disc
					float dist = offset.Dot3(pE->position.GetYAxis());
					offset -= pE->position.GetYAxis()*dist;
				}

				pNew->pos = pE->position.GetTrans() + offset;

				break;
			}
		}

		switch(pE->behaviour)
		{
			case MFEB_Direction:
				pNew->velocity.Normalise3(pE->startVector);
				break;
			case MFEB_TargetAttract:
				pNew->velocity.Normalise3(pE->startVector - pE->position.GetTrans());
				break;
			case MFEB_TargetRepel:
				pNew->velocity.Normalise3(pE->position.GetTrans() - pE->startVector);
				break;
		}

		pNew->velocity *= pE->velocity + MFRand_Range(-pE->velocityScatter, pE->velocityScatter);

		if(pE->directionScatter)
		{
			MFVector scatter;

			do
			{
				scatter = MakeVector(MFRand_Range(-1, 1), MFRand_Range(-1, 1), MFRand_Range(-1, 1));

				float dist = scatter.Dot3(pE->position.GetYAxis());
				scatter -= pE->position.GetYAxis()*dist;
			}
			while(scatter.MagSquared3() < 0.000001f);

			scatter.Normalise3();

			MFMatrix scatterMat;
			scatterMat.SetRotation(scatter, MFRand_Unit()*pE->directionScatter);

			pNew->velocity = ApplyMatrixH(pNew->velocity, scatterMat);
		}
	}
}