Вопрос

Я пытаюсь написать простой трассировщик лучей в качестве хобби-проекта, и сейчас все работает нормально, за исключением того, что я вообще не могу заставить мягкие тени работать.Моя идея мягких теней заключается в том, что считается, что источник света имеет местоположение и радиус.Чтобы выполнить тест тени для этого источника света, я беру точку, где первичный луч попадает на объект в сцене, и отбрасываю n-количество лучей в сторону источника света, где каждый новый луч имеет случайную составляющую для каждой оси, где случайная составляющая варьируется в зависимости от радиуса.

Если такой луч попадает на объект в сцене, я увеличиваю счетчик попаданий (если луч попадает на несколько объектов, он по-прежнему увеличивается только на один).Если он добирается до источника света без столкновений, я добавляю расстояние от точки пересечения основного луча до центра источника света к переменной.

Когда было взято n образцов, я вычисляю соотношение столкнувшихся лучей и умножаю цвет света на это соотношение (таким образом, свет с цветом 1000,1000,1000 станет 500,500,500 с соотношением 0,5, где столкнулась половина лучей).Затем я вычисляю среднее расстояние до источника света, деля переменную расстояния, полученную ранее, на количество не сталкивающихся лучей.Я возвращаю эту переменную, и функция завершает работу.

Проблема в том, что:это не работает.По крайней мере, не совсем.Как это выглядит, можно увидеть здесь.Вы можете увидеть, что это напоминает мягкие тени, если очень сильно прищуриться.

Я не понимаю, я допускаю здесь какой-то фундаментальный недостаток, или это что-то крошечное?Я почти уверен, что проблема в этом методе, потому что, когда я подсчитываю количество частично освещенных пикселей, полученных непосредственно этим методом, их оказывается всего около 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
  }
}
Это было полезно?

Решение

Попробуйте сгенерировать другой "rand" для каждого компонента "loc".Как есть, все ваши дрожащие точки лежат на одной линии.

Другие советы

незначительный момент, но является ли это лучшим использованием класса random?.

 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, 1, 1).Действительно ли источник света линейный?

Кроме того, я почти ничего не вижу в вашем примере.Не могли бы вы расположить камеру ближе к будущей тени, а не со стороны света?

Видите, вот почему я захожу на этот сайт :)

Теперь у каждой оси есть свой собственный random, и это выглядит намного лучше.Это все еще выглядит немного странно, хотя увеличение количества образцов помогает.Теперь это выглядит так это.

Знаете ли вы более эффективный способ уменьшить количество формирующихся шаблонов?

Однако это самая большая помощь:не создавать случайные экземпляры для каждой выборки.Это серьезно утроило мою скорость рендеринга с мягкими тенями!Я никогда не знал, что создание экземпляра Random обходится так дорого.Ух ты.

Большое спасибо.

В своем ответе вы попросили улучшить способ создания мягких теней.Улучшением могло бы быть, вместо рандомизации всех лучей из одной точки, присвоение каждому лучу различного смещения по всем осям, чтобы эффективно предоставить им отдельное небольшое окно для рандомизации.Это должно привести к более равномерному распределению.Я не знаю, было ли это понятно, но другой способ описать это - как сетку, перпендикулярную теневому лучу.Каждая плитка в сетке содержит один из n теневых лучей, но расположение в сетке является случайным. Здесь вы можете найти часть руководства, в котором описывается, как это можно использовать для создания мягких теней.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top