static void RB_CreateProjectedProjectionMatrix( const idRenderLightLocal* light, float* m )
{
	auto parms = light->parms;

	if (parms.start.LengthSqr() < 0.0001f)
		parms.start = parms.target.Normalized() * 8.0f;

	if (parms.end.LengthSqr() < 0.0001f)
		parms.end = parms.target;

	idPlane planes[4];
	R_SetLightProject( planes, idVec3( 0, 0, 0 ), parms.target, parms.right, parms.up, parms.start, parms.end );

	idPlane frustrum[6];
	R_SetLightFrustum( planes, frustrum );

	idVec3 start[4];
	idVec3 dir[4];
	frustrum[0].PlaneIntersection( frustrum[1], start[0], dir[0] ); //ok
	frustrum[1].PlaneIntersection( frustrum[2], start[1], dir[1] );
	frustrum[2].PlaneIntersection( frustrum[3], start[2], dir[2] );
	frustrum[3].PlaneIntersection( frustrum[0], start[3], dir[3] );

	float scale[8];
	frustrum[4].RayIntersection( start[0], dir[0], scale[0] );
	frustrum[4].RayIntersection( start[1], dir[1], scale[1] );
	frustrum[4].RayIntersection( start[2], dir[2], scale[2] );
	frustrum[4].RayIntersection( start[3], dir[3], scale[3] );

	frustrum[5].RayIntersection( start[0], dir[0], scale[4] );
	frustrum[5].RayIntersection( start[1], dir[1], scale[5] );
	frustrum[5].RayIntersection( start[2], dir[2], scale[6] );
	frustrum[5].RayIntersection( start[3], dir[3], scale[7] );

	float n = parms.start.Length();
	float f = parms.end.Length();

	idVec3 nearPoint[4];
	nearPoint[0] = dir[0] * scale[0];
	nearPoint[1] = dir[1] * scale[1];
	nearPoint[2] = dir[2] * scale[2];
	nearPoint[3] = dir[3] * scale[3];

	float l = -((dir[0] * scale[0]) - parms.start).y;
	float r = -l;
	float b = -((dir[0] * scale[0]) - parms.start).x;
	float t = -b;

	memset( m, 0, sizeof(m[0]) * 16 );
	m[0] = (2.0f * n) / (r - l);
	m[5] = (2.0f * n) / (t - b);
	m[8] = (r + l) / (r - l);
	m[9] = (t + b) / (t - b);
	m[10] = -((f + n) / (f - n));
	m[11] = -1.0f;
	m[14] = -(2 * f  * n) / (f - n);
}
Exemple #2
0
EIntersection IntersectLineCone(const idVec3 rkLine[LSG_COUNT],
								 idVec3 rkCone[ELC_COUNT],
								 idVec3 Intersect[2], bool Stump)
{
	EIntersection rc = INTERSECT_COUNT;
	int i, n, l, x;
	float t, angle;
	idPlane lightProject[4];
	idPlane frustum[6];
	int Start[6];
	int End[6];
	bool bStart, bEnd;
	bool bCalcIntersection;
	idStr txt;
	idStr format("Frustum[%u]");
	idVec3 EndPoint(rkLine[LSG_ORIGIN]+rkLine[LSG_DIRECTION]);
	DM_LOG(LC_LIGHT, LT_DEBUG)LOGSTRING("  rkLine[LSG_ORIGIN] = [%s]\r", rkLine[LSG_ORIGIN].ToString());
	DM_LOG(LC_LIGHT, LT_DEBUG)LOGSTRING("  rkLine[LSG_DIRECTION] = [%s]\r", rkLine[LSG_DIRECTION].ToString());
	DM_LOG(LC_LIGHT, LT_DEBUG)LOGSTRING("  EndPoint = [%s]\r", EndPoint.ToString());

	R_SetLightProject(lightProject,
					   rkCone[ELC_ORIGIN],
					   rkCone[ELA_TARGET],
					   rkCone[ELA_RIGHT],
					   rkCone[ELA_UP],
					   rkCone[ELA_START],
					   rkCone[ELA_END]);
	R_SetLightFrustum(lightProject, frustum);

/*
	DM_LOGPLANE(LC_MATH, LT_DEBUG, "Light[0]", lightProject[0]);
	DM_LOGPLANE(LC_MATH, LT_DEBUG, "Light[1]", lightProject[1]);
	DM_LOGPLANE(LC_MATH, LT_DEBUG, "Light[2]", lightProject[2]);
	DM_LOGPLANE(LC_MATH, LT_DEBUG, "Light[3]", lightProject[3]);
*/
	n = format.Length();

	// Calculate the angle between the target and the lightvector.
	angle = rkCone[ELA_TARGET].Length() * rkLine[LSG_DIRECTION].Length();
	DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Denominator: %f\r", angle);
	if ( angle >= idMath::FLT_EPSILON )
	{
		angle = idMath::ACos((rkCone[ELA_TARGET] * rkLine[LSG_DIRECTION])/angle);
//		if(t > (idMath::PI/2))
//			angle = idMath::PI  - angle;

		DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Angle: %f\r", angle);
	}
	else
	{
		DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Impossible line!\r");
	}

	bCalcIntersection = false;
	l = 0;
	for ( i = 0 ; i < 6 ; i++ )
	{
		sprintf(txt, format, i);

		DM_LOGPLANE(LC_MATH, LT_DEBUG, txt, frustum[i]);

		Start[i] = frustum[i].Side(rkLine[LSG_ORIGIN], idMath::FLT_EPSILON);
		End[i] = frustum[i].Side(EndPoint, idMath::FLT_EPSILON);

		DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Frustum[%u]: Start %u   End: %u\r", i, Start[i], End[i]);

		// If the points are all on the outside there will be no intersections
		if ( ( Start[i] == PLANESIDE_BACK ) || ( End[i] == PLANESIDE_BACK ) )
		{
			bCalcIntersection = true;
		}
	}

	DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("CalcIntersection: %u\r", bCalcIntersection);
	if (bCalcIntersection == true)
	{
		DM_LOGVECTOR3(LC_MATH, LT_DEBUG, "TargetOrigin", rkLine[LSG_ORIGIN]);
		DM_LOGVECTOR3(LC_MATH, LT_DEBUG, "TargetDirection", rkLine[LSG_DIRECTION]);
		DM_LOGVECTOR3(LC_MATH, LT_DEBUG, "Endpoint", EndPoint);

		for(i = 0; i < 6; i++)
		{
			if (frustum[i].LineIntersection(rkLine[LSG_ORIGIN], rkLine[LSG_DIRECTION], &t) == true)
			{
				DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Frustum[%u] intersects\r", i);
				Intersect[l] = rkLine[LSG_ORIGIN] + t*rkLine[LSG_DIRECTION];
				l++;

				if (l > 1)
				{
					break;
				}
			}
		}
	}

	if (l < 2)
	{
		rc = INTERSECT_OUTSIDE;
	}
	else
	{
		rc = INTERSECT_FULL;
		bStart = bEnd = true;
		for (i = 0; i < 6; i++)
		{
			x = frustum[i].Side(Intersect[0], idMath::FLT_EPSILON);
			DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Frustum[%u/0] intersection test returns %u\r", i, x);
			if (x != PLANESIDE_BACK)
			{
				bStart = false;
			}

			x = frustum[i].Side(Intersect[1], idMath::FLT_EPSILON);
			DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Frustum[%u/1] intersection test returns %u\r", i, x);
			if (x != PLANESIDE_BACK)
			{
				bEnd = false;
			}
		}

		if (bStart == false && bEnd == false)
		{
			rc = INTERSECT_OUTSIDE;
		}
	}

	DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Intersection count = %u\r", l);
	DM_LOGVECTOR3(LC_MATH, LT_DEBUG, "akPoint[0]", Intersect[0]);
	DM_LOGVECTOR3(LC_MATH, LT_DEBUG, "akPoint[1]", Intersect[1]);

	return rc;
}
Exemple #3
0
// grayman #3584 - rewritten for light cones
EIntersection IntersectLineLightCone(const idVec3 rkLine[LSG_COUNT],
								 idVec3 rkCone[ELC_COUNT],
								 idVec3 Intersect[2],
								 bool inside[2])
{
	EIntersection rc = INTERSECT_COUNT;
	int i, n, intersectionCount, x;
	float t;
	idPlane lightProject[4];
	idPlane frustum[6];
	int sides[6][2] = { {0,0},
						{0,0},
						{0,0},
						{0,0},
						{0,0},
						{0,0} };
	int sidesBack = 0;
	idStr txt;
	idStr format("Frustum[%u]");
	idVec3 EndPoint(rkLine[LSG_ORIGIN]+rkLine[LSG_DIRECTION]);
	DM_LOG(LC_LIGHT, LT_DEBUG)LOGSTRING("  rkLine[LSG_ORIGIN] = [%s]\r", rkLine[LSG_ORIGIN].ToString());
	DM_LOG(LC_LIGHT, LT_DEBUG)LOGSTRING("  rkLine[LSG_DIRECTION] = [%s]\r", rkLine[LSG_DIRECTION].ToString());
	DM_LOG(LC_LIGHT, LT_DEBUG)LOGSTRING("  EndPoint = [%s]\r", EndPoint.ToString());

	R_SetLightProject(lightProject,
					   rkCone[ELC_ORIGIN],
					   rkCone[ELA_TARGET],
					   rkCone[ELA_RIGHT],
					   rkCone[ELA_UP],
					   rkCone[ELA_START],
					   rkCone[ELA_END]);
	R_SetLightFrustum(lightProject, frustum);

/*
	DM_LOGPLANE(LC_MATH, LT_DEBUG, "Light[0]", lightProject[0]);
	DM_LOGPLANE(LC_MATH, LT_DEBUG, "Light[1]", lightProject[1]);
	DM_LOGPLANE(LC_MATH, LT_DEBUG, "Light[2]", lightProject[2]);
	DM_LOGPLANE(LC_MATH, LT_DEBUG, "Light[3]", lightProject[3]);
 */
	n = format.Length();

	// grayman #3584 - determine whether the start and end points of the line segment
	// lie on the back (inside) or front (outside) of each of the 6 planes of the light cone

	intersectionCount = 0;
	for ( i = 0 ; i < 6 ; i++ )
	{
		sprintf(txt, format, i);

		DM_LOGPLANE(LC_MATH, LT_DEBUG, txt, frustum[i]);

		sides[i][0] = frustum[i].Side(rkLine[LSG_ORIGIN], idMath::FLT_EPSILON);
		sides[i][1] = frustum[i].Side(EndPoint, idMath::FLT_EPSILON);
		DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Frustum[%d]: sides[%d][0]: %d sides[%d][1]: %d\r", i, i,sides[i][0], i,sides[i][1]);
		if ( ( sides[i][0] == PLANESIDE_FRONT ) && ( sides[i][1] == PLANESIDE_FRONT ) )
		{
			// both ends of the line are outside the frustum, no need to calculate an intersection
			inside[0] = false;
			inside[1] = false;
			return INTERSECT_OUTSIDE;
		}

		if ( sides[i][0] == PLANESIDE_BACK )
		{
			sidesBack++;
		}

		if ( sides[i][1] == PLANESIDE_BACK )
		{
			sidesBack++;
		}
	}

	if ( sidesBack == 12 )
	{
		// both ends of the line are inside the frustum, no need to calculate an intersection
		rc = INTERSECT_NONE;
		Intersect[0] = rkLine[LSG_ORIGIN];
		Intersect[1] = EndPoint;
		inside[0] = true;
		inside[1] = true;
	}
	else // calculate an intersection
	{
		// We've determined that at least one of the endpoints is possibly inside
		// the frustum (light volume).

		for ( i = 0 ; i < 6 ; i++ )
		{
			if ( sides[i][0] != sides[i][1] )
			{
				// the line crosses the plane, so calculate an intersection

				if ( frustum[i].RayIntersection(rkLine[LSG_ORIGIN], rkLine[LSG_DIRECTION], t) ) // grayman #3584
				//if (frustum[i].LineIntersection(rkLine[LSG_ORIGIN], rkLine[LSG_DIRECTION], &t) == true) // grayman #3584 - this call gives wrong answers
				{
					idVec3 candidate = rkLine[LSG_ORIGIN] + t*rkLine[LSG_DIRECTION];

					// This intersection is valid iff it lies on the backside of all planes.
					// So check that, except for the plane you just intersected, because
					// you know that will return INTERSECT_ON, which is okay.

					bool inside = true;
					for ( int j = 0 ; j < 6 ; j++ )
					{
						if ( j == i )
						{
							continue; // skip the plane you just intersected
						}
						x = frustum[j].Side(candidate, idMath::FLT_EPSILON);
						if (x == PLANESIDE_FRONT)
						{
							inside = false;
							break; // no need to continue, since the point is outside
						}
					}

					if ( inside )
					{
						// This is a valid intersection point.

						Intersect[intersectionCount] = candidate;

						DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Frustum[%u] intersects\r", i);

						if (++intersectionCount > 1)
						{
							break;
						}
					}
				}
			}
		}

		if ( intersectionCount == 0 )
		{
			// both ends of the line are outside the frustum, no need to calculate an intersection
			rc = INTERSECT_OUTSIDE;
			inside[0] = false;
			inside[1] = false;
		}
		else if ( intersectionCount == 1 )
		{
			// One end of the line segment is inside the cone, and the other outside.

			rc = INTERSECT_PARTIAL;

			// Need to determine which end of the line is inside. It will be
			// the second of the two points returned. The first point will be
			// the intersection, and it has already been filled in (Intersect[0]).

			// Check the results of the side checks. If sides[0..6][0] are all
			// PLANESIDE_BACK, then the line origin is inside.
			// Otherwise, the line end is inside

			Intersect[1] = rkLine[LSG_ORIGIN]; // assume it's the line origin
			inside[0] = true;
			inside[1] = false;

			for ( i = 0 ; i < 6 ; i++ )
			{
				if (sides[i][0] == PLANESIDE_FRONT )
				{
					Intersect[1] = EndPoint; // nope, it must be the line end
					inside[0] = false;
					inside[1] = true;
					break;
				}
			}
		}
		else // intersectionCount == 2
		{
			rc = INTERSECT_FULL;
			inside[0] = false;
			inside[1] = false;

/*			// old code
			bool bStart = true;
			bool bEnd = true;
			for ( i = 0 ; i < 6 ; i++ )
			{
				x = frustum[i].Side(Intersect[0], idMath::FLT_EPSILON);
				DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Frustum[%u/0] intersection test returns %u\r", i, x);
				if (x != PLANESIDE_BACK)
				{
					bStart = false;
				}

				x = frustum[i].Side(Intersect[1], idMath::FLT_EPSILON);
				DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Frustum[%u/1] intersection test returns %u\r", i, x);
				if (x != PLANESIDE_BACK)
				{
					bEnd = false;
				}
			}

			if (bStart == false && bEnd == false)
			{
				rc = INTERSECT_OUTSIDE;
			}*/
		}
	}

	DM_LOG(LC_MATH, LT_DEBUG)LOGSTRING("Intersection count = %u\r", intersectionCount);
	DM_LOGVECTOR3(LC_MATH, LT_DEBUG, "Intersect[0]", Intersect[0]);
	DM_LOGVECTOR3(LC_MATH, LT_DEBUG, "Intersect[1]", Intersect[1]);

	return rc;
}