Что не так с моим кодом мягкой тени? - PullRequest
3 голосов
/ 05 февраля 2009

Я пытаюсь написать простой raytracer как хобби-проект, и теперь все работает нормально, за исключением того, что я не могу заставить работать мягкие тени. Моя идея мягких теней состоит в том, что источник света имеет местоположение и радиус. Чтобы провести тест тени на этом источнике света, я беру точку, в которой первичный луч попадает на объект в сцене, и отбрасываю 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
  }
}

Ответы [ 5 ]

5 голосов
/ 05 февраля 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));
3 голосов
/ 05 февраля 2009

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

1 голос
/ 05 февраля 2009

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

1 голос
/ 05 февраля 2009

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

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

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

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

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

1 голос
/ 05 февраля 2009

Вы фактически генерируете точку на линии на линии с направлением (1, 1, 1). Источник света действительно линейный?

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

...