【问题标题】:What's wrong with my soft-shadow code?我的软阴影代码有什么问题?
【发布时间】:2009-02-05 12:27:09
【问题描述】:

我正在尝试编写一个简单的光线追踪器作为一个爱好项目,现在一切正常,只是我根本无法使用软阴影。我对软阴影的想法是,光源被认为具有位置和半径。为了对此灯进行阴影测试,我将主光线照射到场景中的对象处,然后向光源投射 n 条光线,其中每条新光线对每个轴都有一个随机分量,其中随机分量会发生变化在 -radius 和半径之间。

如果这样的射线击中场景中的对象,我会增加一个命中计数器(如果射线击中多个对象,它仍然只会增加一个)。如果它在没有碰撞的情况下到达光源,我将主光线的交点到光源中心的距离添加到一个变量中。

当采集了 n 个样本时,我计算碰撞的光线的比率,并将光的颜色乘以这个比率(因此颜色为 1000,1000,1000 的光将以 0.5 的比率变为 500,500,500,其中一半的光线发生了碰撞)。然后我通过将较早的距离变量除以非碰撞光线的数量来计算到光源的平均距离。我返回那个变量并且函数退出。

问题是:它不起作用。至少不完全是。它的样子可以看到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
  }
}

【问题讨论】:

    标签: c# algorithm raytracing shadow


    【解决方案1】:

    小点,但这是随机类的最佳用途吗..

     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));
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

          【解决方案4】:

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

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

          你知道一种更有效的减少模式形成的方法吗?

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

          非常感谢。

          【讨论】:

          • 看起来好多了。其他要看的东西:随机数生成器质量和蒙特卡洛采样,您可以在其中触发样本,直到统计数据表明您已经得到了很好的估计。请记住,这种多重采样方法永远不会很快(否则他们就不会发明辐射度)。
          【解决方案5】:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-06-05
            • 2013-06-10
            • 2011-07-28
            • 1970-01-01
            相关资源
            最近更新 更多