2009-02-05 7 views
3

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

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

Когда n образцов взято, я вычисляю соотношение лучей, которые столкнулись и умножили цвет света на это отношение (поэтому свет с цветом 1000,1000,1000 станет 500 500 500 с отношением 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 
    } 
} 

ответ

3

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

5

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

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

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

1

Престола, поэтому я пришел на этот сайт :)

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

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

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

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

+0

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

1

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

Смежные вопросы