GLSL Sphere - solution géométrique d'intersection de rayons
J'essaie d'implémenter l'intersection des rayons sphériques dans GLSL, à la fois la solution géométrique et analytique. J'ai du mal à résoudre le geom one, cela devrait avoir quelque chose à voir avec la façon dont je retourne vrai ou faux:
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 && t0 > t_min) {
t_out = t0;
return true;
}
if(t1 < t_max && t1 > t_min) {
t_out = t1;
return true;
}
return false;
}
Je pense que le problème est de savoir comment je gère t0 et t1 pour aucun, un ou les deux cas d'intersection.
Edit: la version analytique qui fonctionne:
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 && t_out > t_min) {
return true;
}
}
return false;
Réponses
Le problème est causé par t_out. L'algorithme doit calculer t_outde cette manière, c'est-à- Xdire le point d'intersection du rayon et la surface de la sphère, pour:
X = ray.origin + ray.direction * t_out;
Dans l'algorithme de travail t_outdépend de la longueur de ray.direction. t_outdevient plus petit, si la magnitude du vecteur ray.directionest plus grande.
Dans l'algorithme, qui ne fonctionne pas, ray.directionest normalisé.
float tca = dot(L, normalize(ray.direction));
Par conséquent, il t_outest calculé pour une longueur de direction de rayon de 1. En fait, vous calculez un t_out'où t_out' = t_out * length(ray.direction).
Divisez t0respectivement t1par la longueur de 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 && t0 > t_min) {
t_out = t0 / length(ray.direction); // <---
return true;
}
if (t1 < t_max && t1 > t_min) {
t_out = t1 / length(ray.direction); // <---
return true;
}
return false;
}