Я сделал 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;
}
Может ли «GetIntersection» вернуть отрицательное число? – 1201ProgramAlarm
Добавлен код GetIntersection для сфер –