I am trying to write a simple raytracer as a hobby project, and now everything works fine, but I can not get soft shadows to work at all. My idea of ββsoft shadows is that the light source is considered a place and a radius. To perform a shadow test in this world, I take the point at which the primary ray hit the object in the scene and threw the n-number of rays on the light source, where each new ray has a random component for each axis, where a random component changes between radius and radius.
If such a ray hits an object in the scene, I increase the hitcounter value (if a ray hits several objects, it still only increases with one). If it hits the light source without collisions, I add the distance from the point of intersection of the primary beam to the center of the light source to the variable.
When n samples were taken, I calculate the ratio of the rays that collided and multiplied the color of the light by this ratio (so the light with a color of 1000,1000,1000 becomes 500 500 500 with a ratio of 0.5, where half of the rays collided). Then I calculate the average distance to the light source by dividing the variable distance previously by the number of non-colliding rays. I return this variable and the function exits.
The problem is that it does not work. Not really. It looks like you can see it here . You can see that it looks like soft shadows if you are humming a lot.
I donβt understand, am I doing some kind of fundamental flaw here, or is it something tiny? I am sure that the problem lies in this method, because when I count the number of partially illuminated pixels created directly by this method, there are only about 250, when there should be much more. And when you look closely at the picture, you can see some partially lit pixels, assuming that the rest of the code handles the partially lit pixels.
Here's the actual light for the soft shadow class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyFirstRayTracer
{
public class AreaLight : ILight
{
private const int _radius = 5;
private const int _samples = 16;
public Color Color { get; set; }
public Vector Location { get; set; }
#region ILight Members
public float GetLightingInformation(Vector point, ISceneObject[] scene, out Color color)
{
int intersectCount = 0;
float distance = -1;
for(int i = 0; i < _samples; i++)
{
bool intersects = false;
float rand = 0;
rand = _radius - (float)(new Random().NextDouble()*(2*_radius));
foreach (ISceneObject obj in scene)
{
Vector iPoint;
Vector loc = new Vector(Location.X + rand, Location.Y + rand, Location.Z + rand);
if (!obj.Intersect(new Ray(point, loc), out iPoint))
{
distance += (Location - point).SqLength;
}
else
{
intersects = true;
distance -= (Location - point).SqLength;
}
}
if (intersects)
intersectCount++;
}
float factor = 1-((float)intersectCount/_samples);
color = new Color(factor*Color.R, factor*Color.G, factor*Color.B);
return (float)Math.Sqrt(distance / (_samples - intersectCount));
}
#endregion
}
}