/// <summary>
/// Find a point on a prim which is the reflection point of 2 points (pointFrom and pointTo).
/// This method uses the concept of "angle of incident = angle of rreflection" then solve
/// that equation.
/// </summary>
/// <param name="pointFrom">Source</param>
/// <param name="pointTo">Target</param>
/// <param name="part">a prim which is used as a reflection surface</param>
/// <returns></returns>
public ReflectionPoint findReflectionPoint(Vector3 pointFrom, Vector3 pointTo, SceneObjectPart part)
{
float x = 0, y = 0, z = 0;
bool xIsZero = true, yIsZero = true, zIsZero = true;
//Get a vector from start to the prim absolute position. Use that vector to test intersection
//and get the normal of the prim.
Vector3 direction = part.AbsolutePosition - pointFrom;
EntityIntersection intersection = part.TestIntersectionOBB(new Ray(pointFrom, direction), part.ParentGroup.GroupRotation, true, false);
//Return false if the ray hits nothing.
if (!intersection.HitTF)
return new ReflectionPoint();
if (intersection.normal.X != 0) { xIsZero = false; }
if (intersection.normal.Y != 0) { yIsZero = false; }
if (intersection.normal.Z != 0) { zIsZero = false; }
//Note: We can get rid of the first three if(else) statement below. But for computation result,
//it is better to use them as the 'last else' statement is quite computationally intensive.
/*
if (!xIsZero && yIsZero && zIsZero) //{1, 0, 0}
{
x = intersection.ipoint.X;
y = solvePointEquation(pointFrom.Y, pointTo.Y, x, pointFrom.X, pointTo.X);
z = solvePointEquation(pointFrom.Z, pointTo.Z, x, pointFrom.X, pointTo.X);
}
else if (xIsZero && !yIsZero && zIsZero) //{0, 1, 0}
{
y = intersection.ipoint.Y;
x = solvePointEquation(pointFrom.X, pointTo.X, y, pointFrom.Y, pointTo.Y);
z = solvePointEquation(pointFrom.Z, pointTo.Z, y, pointFrom.Y, pointTo.Y);
}
else if (xIsZero && yIsZero && !zIsZero) //{0, 0, 1}
{
z = intersection.ipoint.Z;
x = solvePointEquation(pointFrom.X, pointTo.X, z, pointFrom.Z, pointTo.Z);
y = solvePointEquation(pointFrom.Y, pointTo.Y, z, pointFrom.Z, pointTo.Z);
}
else if (xIsZero && yIsZero && zIsZero)
{
throw new Exception("There is no such normal vector which has x, y, and z = 0");
}
//else create a virtual enviroment where the reflection plane has a normal to be x-axis.
//Find the reflection point on that virtual plane, then rotate it back to map the prim surface.
else
{
*/
//Initialise all the required rotation variables
Quaternion partRotation = Vector3.RotationBetween(intersection.normal, new Vector3(1, 0, 0));
Quaternion inverseRotation = Quaternion.Inverse(partRotation);
Matrix4 partRotationM = Matrix4.CreateFromQuaternion(partRotation);
Matrix4 inverseRotationM = Matrix4.CreateFromQuaternion(inverseRotation);
//Direction vectors from prim absolute position to pointFrom, pointTo, and the intersection point.
Vector3 newPointFrom = pointFrom - part.AbsolutePosition;
Vector3 newPointTo = pointTo - part.AbsolutePosition;
Vector3 newIntersection = intersection.ipoint - part.AbsolutePosition;
//Rotate those directions vectors so that they map on a plane where normal = x-axis
newPointFrom = Vector3.Transform(newPointFrom, partRotationM);
newPointTo = Vector3.Transform(newPointTo, partRotationM);
newIntersection = Vector3.Transform(newIntersection, partRotationM);
//Convert those directions vectors back into a point
newPointFrom += part.AbsolutePosition;
newPointTo += part.AbsolutePosition;
newIntersection += part.AbsolutePosition;
//Now we calculate the relfection point by solving the equation.
x = newIntersection.X;
y = solvePointEquation(newPointFrom.Y, newPointTo.Y, x, newPointFrom.X, newPointTo.X);
z = solvePointEquation(newPointFrom.Z, newPointTo.Z, x, newPointFrom.X, newPointTo.X);
//Rotate the reflection point back to map the original prim surface.
Vector3 virtualReflectionPoint = new Vector3(x, y, z) - part.AbsolutePosition;
virtualReflectionPoint = Vector3.Transform(virtualReflectionPoint, inverseRotationM);
virtualReflectionPoint += part.AbsolutePosition;
//Set result x, y and z.
x = virtualReflectionPoint.X;
y = virtualReflectionPoint.Y;
z = virtualReflectionPoint.Z;
//}
//Check if the found reflection point (x, y, and z) is actually on the prim surface.
//If yes then return that point and true. If not then return point(0, 0, 0) and false;
ReflectionPoint reflectionPoint = new ReflectionPoint(new Vector3(x, y, z), true);
if (checkPointIntersectPrim(reflectionPoint.reflectionPoint, part, 0.1f))
{
reflectionPoint.surfaceMaterial = part.Material;
return reflectionPoint;
}
else { return new ReflectionPoint(); }
}