Okay so i did a little bit of research and implemented a recursive "Trace" function which takes a Ray and a depth counter as parameters. It looks like this:
public Color Trace(Ray ray, int depth)
{
float distance = 5000.0f;
BaseObject hitObject = null;
Vector3D HitPoint = null;
foreach (BaseObject obj in this.scene.Objects)
{
float currentDistance = obj.Intersect(ray);
if (currentDistance < distance && currentDistance > 0)
{
distance = currentDistance;
hitObject = obj;
}
HitPoint = ray.origin.add(ray.direction.multiply(distance));
}
if (distance == 5000.0f) //Kein Object wurde getroffen
return Color.Black;
if (hitObject.isEmitter) //Eine Lichtquelle wurde getroffen
return hitObject.surfaceColor;
if (depth == MAX_DEPTH)
return Color.Black;
Vector3D normal = hitObject.Normal(HitPoint);
Ray reflectionRay = null;
if (hitObject.mat == Material.Diffuse)
{
reflectionRay = new Ray(HitPoint, Vector3D.getRandomVectorInHemisphere(1.0f));
}
Color returnColor = Trace(reflectionRay, depth + 1);
float r = hitObject.surfaceColor.R * returnColor.R;
float g = hitObject.surfaceColor.G * returnColor.G;
float b = hitObject.surfaceColor.B * returnColor.B;
r /= 255.0f;
g /= 255.0f;
b /= 255.0f;
return Color.FromArgb(255, (int)r, (int)g, (int)b);
}
And i call the function like this:
float fov = 35 * (float)Math.PI / 180;
float zdir = 1.0f / (float)Math.Tan(fov);
float aspect = (float)height / (float)width;
//BWorker.RunWorkerAsync(new Tuple<int, int, Bitmap, float, float, float>(height, width, drawArea, fov, zdir, aspect));
for (int y = 0; y < pB_Result.Height; y++)
{
for (int x = 0; x < pB_Result.Width; x++)
{
float xdir = (x / (float)width) * 2.0f - 1.0f;
float ydir = ((y / (float)height) * 2.0f - 1.0f) * aspect;
Ray ray = new Ray(new Vector3D(0.0f, 0.0f, 0.0f), new Vector3D(xdir, ydir, zdir).normalize());
float r = 0, g = 0, b = 0;
for (int i = 0; i < 3; i++)
{
Color c = Trace(ray, 0);
r += c.R;
g += c.G;
b += c.B;
}
drawArea.SetPixel(x, y, Color.FromArgb(255, (int)r / 3, (int)g / 3, (int)b / 3));
}
}
pB_Result.Image = drawArea;
But i only get this (there is one sphere on the left side of the light and one sphere on the right):
I think it all depends on my "getRandomVectorInHemisphere" function.
Currently i am just generating a random Vector:
public static Vector3D getRandomVectorInHemisphere(float radius)
{
float x = (float)new Random(DateTime.Now.Millisecond).NextDouble() * radius;
float y = (float)new Random(DateTime.Now.Millisecond).NextDouble() * radius;
float z = (float)new Random(DateTime.Now.Millisecond).NextDouble() * radius;
return new Vector3D(x, y, z).multiply((float)new Random(DateTime.Now.Millisecond).NextDouble());
}
So anyone here who can give me a hint how i can compute a random direction vector for the bouncing ray in the hemisphere the normal is pointing at?
Edit: If i do something like this:
int abortCounter = 0;
while (abortCounter < 500)
{
Vector3D b = new Vector3D((float)new Random(523940).NextDouble() - 0.5f, (float)new Random(5231).NextDouble() - 0.5f, (float)new Random(25061).NextDouble() - 0.5f);
b.normalize();
if (b.Dotproduct(normal) > 0)
return b;
abortCounter++;
if (abortCounter == 499)
return b;
else
return b;
}
return null;
I get this: