我正在尝试编写一个简单的光线追踪器作为一个爱好项目,现在一切正常,除了我根本无法使用软阴影。我对软阴影的想法是,光源被认为具有位置和半径。为了对这盏灯进行阴影测试,我将主光线照射到场景中的对象处,然后向光源投射 n 条光线,其中每条新光线在每个轴上都有一个随机分量,其中随机分量会发生变化在 -radius 和半径之间。
如果这样的射线击中场景中的对象,我会增加一个 hitcounter(如果射线击中多个对象,它仍然只会增加一个)。如果它在没有碰撞的情况下到达光源,我将主光线的交点到光源中心的距离添加到一个变量中。
当采集了 n 个样本时,我计算碰撞的光线的比率,并将光的颜色乘以该比率(因此颜色为 1000,1000,1000 的光将以 0.5 的比率变为 500,500,500,其中一半的光线发生了碰撞)。然后我通过将较早的距离变量除以非碰撞光线的数量来计算到光源的平均距离。我返回那个变量并且函数退出。
问题是:它不起作用。至少不完全是。在这里可以看到它的样子。你可以看到它有点像软阴影,如果你用力眯眼的话。
我不明白,我是在这里制造了某种根本性的缺陷,还是很小的东西?我相当肯定问题出在这种方法上,因为当我计算这种方法直接产生的部分点亮像素的数量时,只有大约 250 个,而应该有更多。当您仔细查看图片时,您会看到一些部分点亮的像素,这表明其余代码处理部分点亮的像素就好了。
这是软阴影类的实际光线:
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
}
}