Что не так с моим кодом мягкой тени?

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

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

Когда было взято 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
  }
}

person JulianR    schedule 05.02.2009    source источник


Ответы (5)


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

person timday    schedule 05.02.2009

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

 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));
person Hath    schedule 05.02.2009

Фактически вы создаете точку на линии на линии с направлением (1, 1, 1). Действительно ли источник света линейный?

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

person jpalecek    schedule 05.02.2009

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

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

Знаете ли вы более эффективный способ уменьшить образование паттернов?

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

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

person JulianR    schedule 05.02.2009
comment
Смотрится намного красивее. Другие вещи, на которые стоит обратить внимание: качество генератора случайных чисел и выборка Монте-Карло, когда вы запускаете образцы, пока статистика не покажет, что у вас есть хорошая оценка. Имейте в виду, что такой подход с множественной выборкой никогда не будет быстрым (иначе они бы не изобрели радиосигнал). - person timday; 05.02.2009

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

person Morten Christiansen    schedule 05.02.2009