2015-04-10 3 views
0

Я строю трассировщик лучей в качестве задания. Я пытаюсь заставить преломление работать в сферах, и я получил его полуфабрикат. Проблема в том, что я не могу избавиться от черной точки в центре сферыТрассировка лучей, полупрозрачная сфера имеет точку в центре

enter image description here

Это код для пересечения:

double a = rayDirection.DotProduct(rayDirection); 
double b = rayOrigin.VectAdd(sphereCenter.Negative()).VectMult(2).DotProduct(rayDirection); 
double c = rayOrigin.VectAdd(sphereCenter.Negative()).DotProduct(rayOrigin.VectAdd(sphereCenter.Negative())) - (radius * radius); 
double discriminant = b * b - 4 * a * c; 

if (discriminant >= 0) 
{ 
    // the ray intersects the sphere 
    // the first root 
    double root1 = ((-1 * b - sqrt(discriminant))/2.0 * a) - 0.000001; 
    double root2 = ((-1 * b + sqrt(discriminant))/2.0 * a) - 0.000001; 

    if (root1 > 0.00001) 
    { 
     // the first root is the smallest positive root 
     return root1; 
    } 
    else 
    { 
     // the second root is the smallest positive root  
     return root2; 
    } 
} 
else 
{ 
    // the ray missed the sphere 
    return -1; 
} 

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

double n1 = refractionRay.GetRefractiveIndex(); 
double n2 = sceneObjects.at(indexOfWinningObject)->GetMaterial().GetRefractiveIndex(); 

if (n1 == n2) 
{ 
    // ray inside the same material, means that it is going to be refracted outside, 
    n2 = 1.000293; 
} 

double n = n1/n2; 

Vect I = refractionRay.GetRayDirection(); 
Vect N = sceneObjects.at(indexOfWinningObject)->GetNormalAt(intersectionPosition); 

double cosTheta1 = -N.DotProduct(I); 
// we need the normal pointing towards the side the ray is coming from 
if (cosTheta1 < 0) 
{ 
    N = N.Negative(); 
    cosTheta1 = -N.DotProduct(I); 
} 

double cosTheta2 = sqrt(1 - (n * n) * (1 - (cosTheta1 * cosTheta1))); 
Vect refractionDirection = I.VectMult(n).VectAdd(N.VectMult(n * cosTheta1 - cosTheta2)); 


Ray newRefractionRay(intersectionPosition.VectAdd(refractionDirection.VectMult(0.001)), refractionDirection, n2, refractionRay.GetRemainingIntersections()); 

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

Если добавить цвет к объекту это выглядит следующим образом:

enter image description here

А если сделать что малая константа больше (0,1) это происходит:

enter image description here

Есть особое условие, которое я должен учитывать? Спасибо!

+0

Обратите внимание, что у вас также есть отражатель в зеленой сфере. Если это актуально, я считаю, что передняя область бесцветная и прозрачная, а не рефлексивная? –

+0

Я бы предложил сначала проверить ваши рефракционные уравнения - пересечение сферы выглядит якобы действительным (и это подтверждается правильным отображением непрозрачных сфер в сцене). – Alnitak

+0

также не должно быть необходимости вычитать этот эпсилон-фактор из двух корней, если вы убедитесь, что значение найденных корней превышает epsilon. Эти факторы необходимы только для того, чтобы вновь образовавшиеся лучи, начиная с поверхности сферы, снова не пересекали сферу. – Alnitak

ответ

1

Вы должны удалить факторы эпсилон, которые вы вычесть при вычислении двух корней:

double root1 = ((-1 * b - sqrt(discriminant))/2.0 * a); 
double root2 = ((-1 * b + sqrt(discriminant))/2.0 * a); 

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

if (root1 > 0.00001) 

NB: вы можете восполнять немного больше производительности только делает вычисление квадратного корня один раз, а также только вычисление root2 если root1 <= epsilon

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