我的软阴影代码出了什么问题?

时间:2009-02-05 12:27:09

标签: c# algorithm raytracing shadow

我正在尝试编写一个简单的光线跟踪器作为一个爱好项目,它现在一切正常,除了我无法使软阴影工作。我对软阴影的想法是,光源被认为具有位置和半径。为了对这个光进行阴影测试,我得到主光线撞击场景中物体的点,并向光源投射n个光线,每个新光线对每个轴都有一个随机分量,随机分量变化介于-radius和radius之间。

如果这样的光线撞击场景中的物体,我会增加一个接收器(如果一条光线击中多个物体,它仍然只增加一个)。如果它在没有碰撞的情况下进入光源,我将主光线交叉点与光源中心的距离加到变量上。

当拍摄n个样本时,我计算出碰撞的光线的比率并将光的颜色乘以该比率(因此,颜色为1000,1000,1000的光将变为500,500,500,比率为0.5,其中一半的光线相撞了)。然后我通过将先前的距离变量除以非碰撞射线的数量来计算到光源的平均距离。我返回该变量,函数退出。

问题是:它不起作用。至少不是这样。可以看到它看起来像here。你可以看到它有点像软阴影,如果你真的很难眯眼。

我不明白,我在这里犯了一些根本性的缺陷,还是它有点小?我很确定问题出在这种方法中,因为当我计算这种方法直接产生的部分点亮像素的数量时,只有大约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
  }
}

5 个答案:

答案 0 :(得分: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));

答案 1 :(得分:3)

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

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

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

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

您是否知道减少图案形成的更有效方法?

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

非常感谢。

答案 4 :(得分:1)

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