代码之家  ›  专栏  ›  技术社区  ›  JulianR

我的软阴影代码怎么了?

  •  3
  • JulianR  · 技术社区  · 15 年前

    我想写一个简单的光线跟踪器作为一个业余项目,现在一切都很好,除了我不能让柔和的阴影工作。我对软阴影的看法是光源被认为有一个位置和一个半径。要对该灯光进行阴影测试,我选取主光线击中场景中对象的点,并向光源投射n个光线量,其中每个新光线对每个轴都有随机分量,其中随机分量在半径和半径之间变化。

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

    当取了n个样本后,我计算出碰撞光线的比率,并将光线的颜色乘以该比率(因此,颜色为100010001000的光线将变为500500500,比率为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 回复  |  直到 15 年前
        1
  •  3
  •   timday    15 年前

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

        2
  •  5
  •   Hath    15 年前

    次要的一点,但这是随机类的最佳用法吗?

     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));
    
        3
  •  1
  •   jpalecek    15 年前

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

    而且,在您的示例中,我几乎看不到任何内容。你能让你的相机更靠近被阴影,而不是指向光的方向吗?

        4
  •  1
  •   JulianR    15 年前

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

    现在每个轴都有自己的随机轴,看起来好多了。看起来还是有点奇怪,不过增加样本的数量还是有帮助的。现在看起来像 this .

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

    但最大的帮助是:不为每个样本实例化随机的。它用柔和的阴影使我的渲染速度提高了三倍!我从来就不知道随机的例子是如此昂贵。真的。

    谢谢。

        5
  •  1
  •   Morten Christiansen    15 年前

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