Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ray tracing - refraction bug

I am writing a ray tracer. So far I have diffuse, Blinn lighting and reflections. Something has gone wrong with my refractions and I have no idea what. I'm hoping someone can help me out. enter image description here

I have a big red diffuse + Blinn sphere and a small refractive one with refraction index n = 1.5.

The small one is just really screwed up.

Relevant code:

ReflectiveSurface::ReflectiveSurface(const Color& _n, const Color& _k) : 
F0(Color(((_n - 1)*(_n - 1) + _k * _k) / ((_n + 1)*(_n + 1) + _k * _k))) {}

Color ReflectiveSurface::F(const Point& N, const Point& V) const {
    float cosa = fabs(N * V);
    return F0 + (F0 * (-1) + 1) * pow(1 - cosa, 5);
}

Color ReflectiveSurface::getColor(const Incidence& incidence, const Scene& scene, int traceDepth) const {
    Point reflectedDir = reflect(incidence.normal, incidence.direction);
    Ray ray = Ray(incidence.point + reflectedDir * epsilon, reflectedDir);
    return F(incidence.normal, incidence.direction) * scene.rayTrace(ray, traceDepth + 1);
}

Point ReflectiveSurface::reflect(const Point& N, const Point& V) const {
    return V - N * (2 * (N * V));
}

bool RefractiveSurface::refractionDir(Point& T, Point& N, const Point& V) const {
    float cosa = -(N * V), cn = n;
    if (cosa < 0) { cosa = -cosa; N = N * (-1); cn = 1 / n; }
    float disc = 1 - (1 - cosa * cosa) / cn / cn;
    if (disc < 0) return false;
    T = V / cn + N * (cosa / cn - sqrt(disc));
    return true;
}

RefractiveSurface::RefractiveSurface(float _n, const Color& _k) : ReflectiveSurface(Color(1, 1, 1) * _n, _k) {}

Surface* RefractiveSurface::copy() { return new RefractiveSurface(*this); }

Color RefractiveSurface::getColor(const Incidence& incidence, const Scene& scene, int traceDepth) const {
    Incidence I = Incidence(incidence);
    Color reflectedColor, refractedColor;
    Point direction = reflect(I.normal, I.direction);
    Ray reflectedRay = Ray(I.point + direction * epsilon, direction);
    if (refractionDir(direction, I.normal, I.direction)) {
        Ray refractedRay = Ray(I.point + direction * epsilon, direction);
        Color colorF = F(I.normal, I.direction);
        reflectedColor = colorF * scene.rayTrace(reflectedRay, traceDepth + 1);
        refractedColor = (Color(1, 1, 1) - colorF) * scene.rayTrace(refractedRay, traceDepth + 1);
    }
    else {
        reflectedColor = scene.rayTrace(reflectedRay, traceDepth + 1);
    }
    return reflectedColor + refractedColor;
}

The code is all over the place, since this is a homework and I'm not allowed to include additional headers and I have to send it in in one cpp file, so i had to separate every class into forward declaration, declaration and implementation in that one file. It makes me vomit but I tried to keep it as clean as possible. There is tons of code so I only included what I thought was most related. ReflectiveSurface is RefractiveSurface's parent class. N is the surface normal, V is the ray direction vector this normal, n is the refraction index. The incidence structure holds a point, a normal and a direction vector.

Formulas for the Fersnel approximation and the refraction vector respectively: enter image description here

You can see in the code that I use an epsilon * ray direction value to avoid shadow acne caused by float imprecision. Something similar seems to be happening to the small sphere, though. Another screenshot: enter image description here

enter image description here

As you can see, the sphere doesn't appear transparent, but it does inherit the diffuse sphere's color. It also usually has some white pixels.

Without refraction:

enter image description here

like image 726
PEC Avatar asked Nov 04 '14 16:11

PEC


People also ask

Is ray tracing a reflection?

Ray tracing is capable of simulating a variety of optical effects, such as reflection, refraction, soft shadows, scattering, depth of field, motion blur, caustics, ambient occlusion and dispersion phenomena (such as chromatic aberration).

What is ray tracing in simple words?

What is ray tracing? Simply put, ray tracing is a technique that makes light in videogames behave like it does in real life. It works by simulating actual light rays, using an algorithm to trace the path that a beam of light would take in the physical world.

Why is it called ray tracing?

Ray tracing is essentially the reverse process, and the name is very literal: It refers to a method of generating an image with a computer by “tracing” the path of light from an imaginary eye or camera to the objects in that image.

What is ray-tracing and how does it work?

How Does It Work? The other advantage of ray-tracing is that, by extending the idea of ray propagation, we can very easily simulate effects like reflection and refraction, both of which are handy in simulating glass materials or mirror surfaces.

What happens when you raytrace down the refracted ray?

When you do a raytrace down the refracted ray, you will have the same problem as when tracing the reflected ray, that you may hit the same surface you just hit again erroneously. To help that, you once again just move the ray slightly away from the surface.

What is the history of ray tracing?

In a 1979 paper entitled "An Improved Illumination Model for Shaded Display", Turner Whitted was the first to describe how to extend Appel's ray-tracing algorithm for more advanced rendering. Whitted's idea extended Appel's model of shooting rays to incorporate computations for both reflection and refraction.

What does ieasy have to do with ray tracing?

IEasy to do with ray tracing IRefraction ITransparent objects ILight bends at the surface IDetails get very complicated COSC342 Ray Tracing Re ections and Refractions 2 Re ection ILight re ected in surface ICast a new ray for re ection IRe ected direction is r = 2n(v n) v Ir is the re ected ray Iv the view direction In the surface normal


Video Answer


2 Answers

RefractiveSurface::refractionDir takes the normal N by (non-const) reference, and it may invert it. This seems dangerous. It's not clear the caller wants I.normal to be flipped, as it's used in color calculations further down.

Also, refracted_color is not always initialized (unless the Color constructor makes it black).

Try (temporarily) simplifying and just see if the refracted rays hit where you expect. Remove the Fresnel computation and the reflection component and just set refracted_color to the result of the trace of the refracted ray. That will help determine if the bug is in the Fresnel calculation or in the geometry of bending the ray.

A debugging tip: Color the pixels that don't hit anything with something other than black. That makes it easy to distinguish the misses from the shadows (surface acne).

like image 191
Adrian McCarthy Avatar answered Oct 20 '22 01:10

Adrian McCarthy


The answer turned out to be pretty simple, but it took me like 3 days of staring at the code to catch the bug. I have a Surface class, I derive from it two classes: RoughSurface (diffuse+blinn) and RelfectiveSurface. Then, RefractiveSurace is derived from RefleciveSurface. ReflectiveSurface's constructor takes the refractive index(n) and the extinction value (k) as parameters, but doesn't store them. (F0) is computed from them during construction, and then they are lost. RefractiveSurface, on the other hand, uses (n) in the refraction angle calculation.

Old constructor:

RefractiveSurface::RefractiveSurface(float _n, const Color& _k) :
    ReflectiveSurface(Color(1, 1, 1) * _n, _k) {}

New Constructor:

RefractiveSurface::RefractiveSurface(float _n, const Color& _k) :
    ReflectiveSurface(Color(1, 1, 1) * _n, _k), n(_n) {}

As you can see, I forgot to save the (n) value for RefractiveSurface in the constructor.

Small red sphere behind big glass sphere lit from the two sides of the camera:

enter image description here

It looks awesome in motion!D

Thank you for your time, guys. Gotta finish this homework, then I'll rewrite the whole thing and optimize the hell out of it.

like image 33
PEC Avatar answered Oct 20 '22 00:10

PEC