2016-12-19 6 views
1

Я сделал ray tracer:Проблемы с Lambertian затенения и теней (трассировка лучей)

И я реализующей алгоритм Blinn-Фонг, но я пришел к некоторым проблемам при рендеринге в конкретных ситуациях (otherwise it works quite well)

  • Когда шар парит в воздухе, Lambertian затенение не работает правильно (кажется, только происходит, если сфера находится выше положения источника света) - Screenshot

  • источник света находится ниже сферы - Screenshot

  • Когда тень будучи отливают на сфере (также можно увидеть в 1-ом примере) - Screenshot

  • При наличии более чем 1 плоскость в сцене (только если тень на) - Screenshot

Я предполагаю, что есть что-то не так с моей тенью и алгоритмами Ламберта затенения, но я не уверен, что, может кто-нибудь помочь?

Код (нет внешних библиотек, просто скомпилировать):

Color finalColor; 
Color ambient; 
Color diffuse; 
FPType lambertian; 
FPType phong; 
Color specular; 
bool shadowed = false; 

// Ambient 
if(AMBIENT_ON) 
{ 
    ambient = closestObjectMaterial.GetColor() * AMBIENT_LIGHT * closestObjectMaterial.GetAmbient(); 
    finalColor += ambient; 
} 

// Shadows, Diffuse, Specular 
for(const auto &lightSource : lightSources) 
{ 
    Vector lightDir = (lightSource->GetPosition() - point); // Calculate the directional vector towards the lightSource 
    FPType distance = lightDir.Magnitude(); 
    lightDir = lightDir.Normalize(); 
    lambertian = closestObjectNormal.Dot(lightDir); 

    // Shadows 
    if(SHADOWS_ON && lambertian > 0) 
    { 
     Ray shadowRay(point, lightDir); // Cast a ray from the first intersection to the light 

     std::vector<FPType> secondaryIntersections; 
     for(const auto &sceneObject : sceneObjects) 
     { 
      secondaryIntersections.push_back(sceneObject->GetIntersection(shadowRay)); 
     } 

     for(const auto &secondaryIntersection : secondaryIntersections) 
     { 
      if(secondaryIntersection > TOLERANCE) // If shadow ray intersects with some object along the way 
      { 
       shadowed = true; 
       finalColor *= closestObjectMaterial.GetDiffuse() * AMBIENT_LIGHT; 
       break; 
      } 
     } 
    } 

    // Diffuse 
    if(DIFFUSE_ON && shadowed == false) 
    { 
     diffuse = closestObjectMaterial.GetColor().Average(lightSource->GetColor()) * closestObjectMaterial.GetDiffuse() * lightSource->GetIntensity() * std::fmax(lambertian, 0)/distance; 
     finalColor += diffuse; 
    } 
    if(shadowed == false && SPECULAR_ON) 
    { 
     // Specular 
     if(closestObjectMaterial.GetSpecular() > 0 && closestObjectMaterial.GetSpecular() <= 1) 
     { 
      Vector V = -sceneDirection; 
      // Blinn-Phong 
      Vector H = (lightDir + V).Normalize(); 
      FPType NdotH = closestObjectNormal.Dot(H); 

      phong = pow(NdotH, 300); 
      specular = lightSource->GetColor() * std::fmax(0, phong) * lightSource->GetIntensity()/distance; // closestObjectMaterial.GetSpecular(); add or no? 
      finalColor += specular; 
     } 
    } 
} 

FPType Sphere::GetIntersection(Ray ray) 
{ 
    Vector length = center - ray.GetOrigin(); // Length of the vector between the center and the ray origin (hypotenuse) 
    FPType tca = length.Dot(ray.GetDirection()); // opposide side 

    if(tca < 0) // No intersection registered 
     return -1; 

if(tca > 0) // Intersection registered 
{ 
    FPType a = sqrt(length.Dot(length) - tca*tca); // Adjacent side (a = sqrt(c²-b²)) 

    if(a > radius || a < 0) 
     return -1; 

    FPType thc = sqrt(radius*radius - a*a); // the line between 2 intersection points/2 

    FPType primaryIntersection; 
    primaryIntersection = tca - thc; 
    if(primaryIntersection > 0) 
     return primaryIntersection; 
    else 
    { 
     FPType secondaryIntersection = thc + tca; 
     return secondaryIntersection; 
    } 
} 
return -1; 

}

+0

Может ли «GetIntersection» вернуть отрицательное число? – 1201ProgramAlarm

+0

Добавлен код GetIntersection для сфер –

ответ

0

Я был не уверен, почему у вашего пересечения Sphere-Ray было два квадратных корня. Хотели бы вы протестировать мою реализацию на основе this?

FPType Sphere::GetIntersection(Ray ray) 
{ 
    Vector delta = ray.GetOrigin() - center; 
    Vector dir = ray.GetDirection(); 

    //Quadratic equation describing the distance along ray to intersection 
    FPType a = dir.Dot(dir); 
    FPType b = dir.Dot(delta); //removed factor of 2 later divide by a, NOT 2a 
    FPType c = delta.Dot(delta) - radius*radius; 

    FPType descrim = b*b - a*c; 
    if (descrim < FPType(0)) { 
    return -1; 
    } 
    //Find solutions to quadratic equation 
    descrim = sqrt(descrim)/a; 
    b = -b/a; 

    FPType intersection0 = b - descrim 
    if(intersection0 >= FPType(0)) { 
    return intersection0; 
    } 

    FPType intersection1 = b + descrim 
    if(intersection1 >= FPType(0)) { 
    return intersection1; 
    } 

    //Both solutions were negative 
    return -1; 
} 
+0

Просто протестирован, результаты были полностью идентичны. –

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