2014-02-11 1 views
2

Я работаю над алгоритмом raytracing для класса и столкнулся с какой-то странной проблемой.Артефакты отражения отражения и прозрачность

img

Это основная сцена, которую я сейчас работаю. Ничего серьезного, все в порядке. Теперь мой код организован таким образом:

Image* Tracer::render() 
{ 
    int w = _scr.width(); 
    int h = _scr.height(); 
    Image* im = new Image(w, h); 
    int i, j; 
    for(i = 0; i < h; i++) 
    { 
     for(j = 0; j < w; j++) 
     { 
      im->setColour(i, j, render(i, j)); 
     } 
    } 
    return im; 
} 

Я вызываю эту функцию для генерации изображения. Для того, чтобы цвет каждого пикселя:

Vec Tracer::render(int i, int j) 
{ 
    Vec pxlcol(0,0,0); 
    Vec p(0,0,0); 
    int obj; 
    Vec dir = _scr.point(i,j); 
    dir = dir - _obs; 
    obj = intercept(_obs, dir, p); 
    if(obj != -1) 
    { 
     pxlcol = objCol(_obs, p, obj, _ref); 
    } 
    return pxlcol; 
} 

Где INT Tracer :: перехватывает (Vec о, Vec д, Vec & р) является следующей функцией

int Tracer::intercept(Vec o, Vec d, Vec& p) 
{ 
    int obj, k; 
    Vec temp = o; 
    Vec ptry = o; 
    obj = -1; 
    for(k = 0; k < _nobj; k++) 
    { 
     temp = _obj[k]->intercept(o, d); 
     if(!(temp == o) && (((temp - o).mod() < (ptry - o).mod()) || (ptry == o))) 
     { 
      ptry = temp; 
      obj = k; 
     } 
    } 
    p = ptry; 
    return obj; 
} 

, который находит индекс к объекту который перехватывает луч г начиная с ö, а также возвращает точку р, где такое происходит перехват и Vec Tracer :: objCol (Vec о, Ve ф, Int OBJ, Int г) функция

Vec Tracer::objCol(Vec o, Vec p, int obj, int r) 
{ 
    Vec colour(0,0,0); 
    Vec point(0,0,0), reflected(0,0,0); 
    unit ref = _obj[obj]->ref(p); 
    if((1 - ref) > 0) 
     point = pointCol(o, p, obj); 
    if(ref > 0 && r > 0) 
     reflected = refCol(o, p, _obj[obj]->normal(o, p), r - 1); 
    colour = (point*(1 - ref)) + (reflected*ref); 
    return colour; 
} 

, который находит цвет, который указывал р посылает в направлении о зная, что он принадлежит к объекту OBJ и что максимальное число разрешенные отражения r.

Когда я делаю назад (белый) стена отражает свет, это результат:

img

Выглядит довольно хорошо, никаких проблем там. Теперь, если я право (синий) стена отражающий результат заключается в следующем:

img

(я не могу отправить более чем 2 ссылки еще, удалите круглые скобки, чтобы увидеть изображение). И это становится еще хуже, если я решу сделать сферу отражающих:

img

Он становится прозрачным! И я не знаю, почему это произойдет, так как я искал перехват лучей, прежде чем добираться до цветов.

Вот мои коды для нахождения цвета точки и отраженный цвет:

Vec Tracer::pointCol(Vec o, Vec p, int obj) 
{ 
    Vec pcol(0,0,0); 
    Vec inten(0,0,0); 
    unit cos = 0; 
    Vec c(0,0,0); 
    Vec normal = _obj[obj]->normal(o, p); 
    Vec inter = o; 
    Vec objcol = _obj[obj]->colour(p); 
    bool block = false; 
    if(_amb == 1) 
     return objcol; 
    int l = 0; 
    int k = 0; 
    for(l = 0; l < _nlight; l++) 
    { 
     c = _li[l]->getPos() - p; 
     block = false; 
     if(c*normal > 0) 
     { 
      for(k = 0; k < _nobj; k++) 
      { 
       if(k != obj) 
       { 
        inter = _obj[k]->intercept(p, c); 
        inter = inter - p; 
        if(!(inter.null()) && (inter.mod() < c.mod())) 
        { 
         block = true; 
         k = _nobj; 
        } 
       } 
      } 

      if(!block) 
      { 
       cos = (c*normal)/(c.mod()*normal.mod()); 
       inten = inten + _li[l]->getInt()*cos; 
      } 
     } 
    } 

    inten = inten.div(_totalinten); 
    pcol = objcol*_amb + objcol.multi(inten)*(1 - _amb); 
    return pcol; 
} 

Константа _amb определяет, сколько из света окружающего света и сколько рассеивается.

Функция Vec Vec :: DIV (Vec v) возвращает точечную деление векторов (например, (а, б, в) .div ((х, у, г)) = (а/х, b/y, c/z)). Функция Vec Vec :: multi (Vec v) делает то же самое для умножения.

Vec Tracer::refCol(Vec o, Vec p, Vec n, int r) 
{ 
    Vec rcol(0,0,0); 
    Vec i = p - o; 
    Vec refl(0,0,0); 
    int obj = 0; 
    Vec point(0,0,0); 
    i.normalise(); 
    refl = reflected(i, n); 
    obj = intercept(p, refl, point); 
    if(obj != -1) 
    { 
     rcol = objCol(p, point, obj, r); 
    } 
    return rcol; 
} 

С objCol вызовы refCol с параметром R-1, число отражений ограничена сверху _ref.

Любая идея, что может вызвать эти странные эффекты отражения?

+0

Кровавый ад это сработало: O Я пробовал первое, перемещая точку пересечения немного по нормали, я попробую другую вещь. –

+0

Рад это слышать - я изменил комментарий на ответ и написал немного больше, чтобы объяснить, что происходит. – schnaader

ответ

2

Это был комментарий, я сделал ответ из него, потому что, кажется, работает:

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

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

+1

Да, скорее всего случай. Проблема, с которой сталкивается любой, кто пишет raytracer. Хорошие воспоминания. +1 – Bart

+0

Bleeergh. Итак, первое, что я подумал, когда думал о том, чтобы реализовать то, что отраженный луч не может столкнуться с исходным объектом: что, если я этого хочу? Я имею в виду, если я, например, _indide_ отражающий объект, я хочу, чтобы он смог отразить себя. Так что просто не разрешая саморефлексию, это не режет. Имея это в виду, есть ли более элегантный/общий способ сделать это, не перемещая точку пересечения? –

+1

Вы можете передать точку пересечения в следующую рекурсию и разрешить только новые точки пересечения с помощью некоторого epsilon - это предотвратит новые столкновения в этой точке, но позволит столкнуться с одним и тем же объектом дальше. – schnaader

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

  • Нет связанных вопросов^_^