3

我正在尝试编写一个简单的光线追踪器作为一个爱好项目,现在一切正常,除了我根本无法使用软阴影。我对软阴影的想法是,光源被认为具有位置和半径。为了对这盏灯进行阴影测试,我将主光线照射到场景中的对象处,然后向光源投射 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
  }
}
4

5 回答 5

5

次要问题,但这是随机类的最佳用途吗?

 for(int i = 0; i < _samples; i++)
      {
        bool intersects = false;
        float rand = 0;
        rand = _radius - (float)(new Random().NextDouble()*(2*_radius));

这不应该是..

    var rnd = new Random()    
    for(int i = 0; i < _samples; i++)
              {
                bool intersects = false;
                float rand = 0;
                rand = _radius - (float)(rnd.NextDouble()*(2*_radius));
于 2009-02-05T12:32:49.980 回答
3

尝试为“loc”的每个组件生成不同的“rand”。照原样,您的抖动点都在一条线上。

于 2009-02-05T12:35:16.213 回答
1

您实际上在具有方向 (1, 1, 1) 的线上生成点。光源真的是线性的吗?

另外,在你的例子中我几乎看不到任何东西。你能让你的相机更接近未来的阴影而不是从光的方向指向吗?

于 2009-02-05T12:36:46.680 回答
1

看,这就是我来这个网站的原因:)

现在每个轴都有自己的随机数,而且看起来好多了。它看起来仍然有点奇怪,但增加样本数量会有所帮助。现在看起来像这样

您知道减少打版的更有效方法吗?

但最大的帮助是:不为每个样本实例化 Random 。它用柔和的阴影严重地提高了我的渲染速度三倍!我从来不知道 Random 实例化的成本如此之高。哇。

非常感谢。

于 2009-02-05T12:45:41.887 回答
1

在您的回复中,您要求改进制作柔和阴影的方法。一个改进可能是,而不是将来自同一点的所有光线随机化,而是在所有轴上给每条光线一个不同的偏移量,以有效地给它们一个单独的小窗口来随机化。这应该会导致更均匀的分布。我不知道这是否清楚,但另一种描述它的方式是垂直于阴影射线的网格。网格中的每个图块都包含 n 条阴影射线之一,但网格中的位置是随机的。在这里您可以找到教程的一部分,该教程描述了如何将其用于软阴影。

于 2009-02-05T13:27:34.940 回答