#c #opengl #glsl #shader #raytracing
#c #opengl #glsl #шейдер #трассировка лучей
Вопрос:
Я пытаюсь реализовать пересечение сферических лучей в GLSL, как геометрическое, так и аналитическое решение. У меня возникли проблемы с решением geom one, это должно иметь какое-то отношение к тому, как я возвращаю true или false:
bool hitSphere(Ray ray, Sphere sphere, float t_min, float t_max, out float t_out) {
// Geometric solution
float R2 = sphere.radius * sphere.radius;
vec3 L = sphere.position - ray.origin;
float tca = dot(L, normalize(ray.direction));
// if(tca < 0) return false;
float D2 = dot(L, L) - tca * tca;
if(D2 > R2) return false;
float thc = sqrt(R2 - D2);
float t0 = tca - thc;
float t1 = tca thc;
if(t0 < t_max amp;amp; t0 > t_min) {
t_out = t0;
return true;
}
if(t1 < t_max amp;amp; t1 > t_min) {
t_out = t1;
return true;
}
return false;
}
Я думаю, что проблема заключается в том, как я справляюсь с t0 и t1 ни для одного, ни для одного или обоих случаев пересечения.
Редактировать: аналитическая версия, которая работает:
vec3 oc = ray.origin - sphere.position;
float a = dot(ray.direction, ray.direction);
float b = dot(oc, ray.direction);
float c = dot(oc, oc) - sphere.radius * sphere.radius;
float discriminant = b * b - a * c;
if (discriminant > 0.0f) {
if(b > 0)
t_out = (-b sqrt(discriminant)) / a;
else
t_out = (-b - sqrt(discriminant)) / a;
if(t_out < t_max amp;amp; t_out > t_min) {
return true;
}
}
return false;
Комментарии:
1.1) Удалите строку
if(tca < 0) return false;
, в которой знак точки-p здесь не используется. 2)ray.direction
должно быть нормализовано. 3) Как вы предварительно вычисляетеt_min
иt_max
?2. @Ripi2 1) это создает странный оттенок на моих сферах, не уверен почему. 2) это почти исправляет проблему, кажется, не хватает тени между двумя сферами. 3) они жестко закодированы в ‘0.001’ и ‘9999.99’. Я обновлю сообщение некоторыми фотографиями.
Ответ №1:
Проблема вызвана t_out
. Алгоритм должен вычислять t_out
таким образом, что X
является точкой пересечения луча и поверхностью сферы, для:
X = ray.origin ray.direction * t_out;
В рабочем алгоритме t_out
зависит от длины ray.direction
. t_out
становится меньше, если величина вектора ray.direction
больше.
В алгоритме, который не работает, ray.direction
нормализуется.
float tca = dot(L, normalize(ray.direction));
Следовательно t_out
вычисляется для длины направления луча, равной 1. На самом деле вы вычисляете t_out'
где t_out' = t_out * length(ray.direction)
.
Разделите t0
соответственно t1
на длину ray.direction
:
bool hitSphere_2(Ray ray, Sphere sphere, float t_min, float t_max, out float t_out)
{
float R2 = sphere.radius * sphere.radius;
vec3 L = sphere.position - ray.origin;
float tca = dot(L, normalize(ray.direction));
// if(tca < 0) return false;
float D2 = dot(L, L) - tca * tca;
if(D2 > R2) return false;
float thc = sqrt(R2 - D2);
float t0 = tca - thc;
float t1 = tca thc;
if (t0 < t_max amp;amp; t0 > t_min) {
t_out = t0 / length(ray.direction); // <---
return true;
}
if (t1 < t_max amp;amp; t1 > t_min) {
t_out = t1 / length(ray.direction); // <---
return true;
}
return false;
}