I'm making a simple ray tracer and right now I'm trying to make a simple orthogonal view showing a sphere but instead of a red circle on a black background I get a red rectangle...
In my sphere class I have a method for checking if a ray hits a sphere:
public bool IntersectsRay(Ray ray) //c -> origin, R -> radius, o - origin ray,
//d - direction ray
{
Vector3 d = ray.direction;
Vector3 o = ray.origin;
Vector3 c = origin;
double R = radius;
double A = d.DotVector(d); //d^2
double B = 2 * d.DotVector(o.MinusVector(c)); //2d(o - c)
double C = (o.MinusVector(c)).DotVector(o.MinusVector(c)) - radius * radius; //(o - c)(o - c) - R^2
double delta = B * B - 4 * A * C;
if (delta < 0)
{
Console.WriteLine("There are no intersection points");
return false;
}
else
{
Console.WriteLine("delta is equal to: {0}", delta);
double t1 = (-B + Math.Sqrt(delta)) / 2 * A;
double t2 = (-B - Math.Sqrt(delta)) / 2 * A;
if (t1.Equals(t2))
{
Vector3 P1 = o.PlusVector(d.MultiplyByScalar((float)t1));
Console.WriteLine("P0: ({0}, {1}, {2})", P1.x, P1.y, P1.z);
return true;
}
else
{
Vector3 P1 = o.PlusVector(d.MultiplyByScalar((float)t1));
Vector3 P2 = o.PlusVector(d.MultiplyByScalar((float)t2));
Console.WriteLine("P1: ({0}, {1}, {2}), P2: ({3}, {4}, {5})", P1.x, P1.y, P1.z, P2.x, P2.y, P2.z);
return true;
}
}
}
Orthogonal camera class:
public class CamOrthogonal
{
public Bitmap BM;
private float pixelWidth;
private float pixelHeight;
private float centerPixelX;
private float centerPixelY;
private bool intersection;
public CamOrthogonal()
{
this.BM = new Bitmap(240, 240, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
}
public CamOrthogonal(Img IMG)
{
this.BM = IMG.BM;
}
public void render(Sphere S)
{
pixelWidth = 2.0f / BM.Width;
pixelHeight = 2.0f / BM.Height;
for (int i = 0; i < BM.Width; i++)
{
for (int j = 0; j < BM.Height; j++)
{
centerPixelX = -1.0f + (i + 0.5f) * pixelWidth;
centerPixelY = 1.0f - (j + 0.5f) * pixelHeight;
//Ray ray = new Ray(new Vector3(0, 0, 1), new Vector3(centerPixelX, centerPixelX, 0));
Ray ray = new Ray(new Vector3(centerPixelX, centerPixelX, 0), new Vector3(0, 0, 1));
/* if (Plane_or_Sphere is Plane)
{
intersection = ((Plane)Plane_or_Sphere).IntersectsRay(ray);
}
else if (Plane_or_Sphere is Sphere)
{
intersection = ((Sphere)Plane_or_Sphere).IntersectsRay(ray);
} */
intersection = S.IntersectsRay(ray);
if (intersection == true)
{
this.BM.SetPixel(i, j, Color.Red);
}
else
{
this.BM.SetPixel(i, j, Color.Black);
}
}
}
this.BM.Save("/Users/Aleksy/Desktop/RT_IMG.jpg");
}
}
An then, in my main class I have:
CamOrthogonal CAM = new CamOrthogonal();
Sphere S = new Sphere(0, 0, -10, (float)0.1); //origin - x,y,z & radius
CAM.render(S);
And what I get is that red rectangle. Where did I make the mistake?
In your code, you have:
double t1 = (-B + Math.Sqrt(delta)) / 2 * A;
In C#, this is evaluated according to the operator precedence rules, which state that *
and /
are multiplicative operators. It also says:
The operators within each section share the same precedence level.
Therefore, *
and /
have equal precedence; they are evaluated left to right. Therefore, your statement is getting evaluated like so:
double t1 = (((-B + Math.Sqrt(delta)) / 2) * A);
However, what you actually want to solve the quadratic equation is this:
double t1 = (-B + Math.Sqrt(delta)) / (2 * A);
...and the same for t2
.
EDIT
Also, your hit conditions are incorrect:
if (t1.Equals(t2))
{
Vector3 P1 = o.PlusVector(d.MultiplyByScalar((float)t1));
Console.WriteLine("P0: ({0}, {1}, {2})", P1.x, P1.y, P1.z);
return true;
}
else
{
Vector3 P1 = o.PlusVector(d.MultiplyByScalar((float)t1));
Vector3 P2 = o.PlusVector(d.MultiplyByScalar((float)t2));
Console.WriteLine("P1: ({0}, {1}, {2}), P2: ({3}, {4}, {5})", P1.x, P1.y, P1.z, P2.x, P2.y, P2.z);
return true;
}
The ray actually hits if t1 >= 0
or t2 >= 0
. In that case, the intersection point is given by whichever t
is smallest (but still >= 0
).