예제 #1
0
파일: MFView.cpp 프로젝트: FujiGameJam/fuji
MF_API void MFView_TransformPoint3DTo2D(const MFVector& point, MFVector *pResult)
{
	MFMatrix proj, viewProj, view;

	// get the perspective projection matrix
	proj.SetPerspective(pCurrentView->fov, pCurrentView->nearPlane, pCurrentView->farPlane, pCurrentView->aspectRatio);

	// in this special case, we'll make the projection matrix produce a 0-1 value in z across all platforms (some platforms project into different 'z' spaces)
	float zn = pCurrentView->nearPlane;
	float zf = pCurrentView->farPlane;
	float zd = zf-zn;
	float zs = zf/zd;
	proj.m[10] = zs;
	proj.m[14] = -zn*zs;

	// get the view matrix (which we will need to calculate if we are in ortho mode)
	if(!MFView_IsOrtho())
		view = MFView_GetWorldToViewMatrix();
	else
		view.Inverse(MFView_GetCameraMatrix());

	viewProj.Multiply4x4(view, proj);

	// apply the projection and perform the perspective divide
	MFVector transformed;
	transformed = ApplyMatrix(point, viewProj);
	transformed *= MFRcp(transformed.w);

	// and shift the result into the ortho rect
	transformed.x += 1.0f;
	transformed.y = -transformed.y + 1.0f;

	*pResult = transformed * MakeVector(pCurrentView->orthoRect.width*0.5f, pCurrentView->orthoRect.height*0.5f) + MakeVector(pCurrentView->orthoRect.x, pCurrentView->orthoRect.y);
}
예제 #2
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;
}
예제 #3
0
파일: MFView.cpp 프로젝트: FujiGameJam/fuji
MF_API void MFView_TransformPoint2DTo3D(const MFVector& point, MFVector *pResult, MFVector *pResultRayDir)
{
	MFMatrix proj, viewProj, view;

	// get the perspective projection matrix
	proj.SetPerspective(pCurrentView->fov, pCurrentView->nearPlane, pCurrentView->farPlane, pCurrentView->aspectRatio);

	// in this special case, we'll make the projection matrix produce a 0-1 value in z across all platforms (some platforms project into different 'z' spaces)
	float zn = pCurrentView->nearPlane;
	float zf = pCurrentView->farPlane;
	float zd = zf-zn;
	float zs = zf/zd;
	proj.m[10] = zs;
	proj.m[14] = -zn*zs;

	// get the view matrix (which we will need to calculate if we are in ortho mode)
	if(!MFView_IsOrtho())
		view = MFView_GetWorldToViewMatrix();
	else
		view.Inverse(MFView_GetCameraMatrix());

	viewProj.Multiply4x4(view, proj);

	// inverse projection
	viewProj.Inverse();

	// which the point from ortho space back into homogeneous space
	*pResult = point;
	*pResult -= MakeVector(pCurrentView->orthoRect.x, pCurrentView->orthoRect.y);
	*pResult *= MakeVector(MFRcp(pCurrentView->orthoRect.width*0.5f), MFRcp(pCurrentView->orthoRect.height*0.5f));
	pResult->x -= 1.0f;
	pResult->y = -pResult->y + 1.0f;

	// and un-project
	// TODO: undo the perspective divide (f**k)
	*pResult = ApplyMatrix(*pResult, viewProj);

	if(pResultRayDir)
	{
		// calculate the pixels rays direction..

	}
}
예제 #4
0
bool MFCollision_RaySlabTest(const MFVector& rayPos, const MFVector& rayDir, const MFVector& plane, float slabHalfWidth, MFRayIntersectionResult *pResult)
{
	float a = plane.Dot3(rayDir);

	// if ray is parallel to plane
	if(a > -MFALMOST_ZERO && a < MFALMOST_ZERO)
	{
		// TODO: this is intentionally BROKEN
		// this is a near impossible case, and it adds a lot of junk to the function
/*
		if(MFAbs(rayPos.DotH(plane)) <= slabHalfWidth)
		{
			if(pResult)
			{
				pResult->time = 0.0f;
			}

			return true;
		}
*/
		return false;
	}

	// otherwise we can do the conventional test
	float inva = MFRcp(a);
	float t = -rayPos.DotH(plane);
	float t1 = (t + slabHalfWidth) * inva;
	float t2 = (t - slabHalfWidth) * inva;

	t = MFMin(t1, t2);
	t2 = MFMax(t1, t2);

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

	if(pResult)
	{
		pResult->time = MFMax(t, 0.0f);
		pResult->surfaceNormal = a > 0.0f ? -plane : plane;
	}

	return true;
}
예제 #5
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;
}