Skip to content
Permalink
Browse files

refractions

  • Loading branch information
ssloy committed Jan 20, 2019
1 parent c80479d commit b69793bf6e8be54973cad1b18185a67dbf11bad1
Showing with 26 additions and 8 deletions.
  1. BIN out.jpg
  2. +26 −8 tinyraytracer.cpp
BIN +5.76 KB (110%) out.jpg
Binary file not shown.
@@ -12,9 +12,10 @@ struct Light {
};

struct Material {
Material(const Vec3f &a, const Vec3f &color, const float &spec) : albedo(a), diffuse_color(color), specular_exponent(spec) {}
Material() : albedo(1,0,0), diffuse_color(), specular_exponent() {}
Vec3f albedo;
Material(const float &r, const Vec4f &a, const Vec3f &color, const float &spec) : refractive_index(r), albedo(a), diffuse_color(color), specular_exponent(spec) {}
Material() : refractive_index(1), albedo(1,0,0,0), diffuse_color(), specular_exponent() {}
float refractive_index;
Vec4f albedo;
Vec3f diffuse_color;
float specular_exponent;
};
@@ -44,6 +45,19 @@ Vec3f reflect(const Vec3f &I, const Vec3f &N) {
return I - N*2.f*(I*N);
}

Vec3f refract(const Vec3f &I, const Vec3f &N, const float &refractive_index) { // Snell's law
float cosi = - std::max(-1.f, std::min(1.f, I*N));
float etai = 1, etat = refractive_index;
Vec3f n = N;
if (cosi < 0) { // if the ray is inside the object, swap the indices and invert the normal to get the correct result
cosi = -cosi;
std::swap(etai, etat); n = -N;
}
float eta = etai / etat;
float k = 1 - eta*eta*(1 - cosi*cosi);

This comment has been minimized.

Copy link
@RoastMyCode

RoastMyCode Dec 6, 2019

Hey, great Tutorial. I think I figured almost everything of the Ray Tracer out but I cant get behind the float k = 1 - eta*eta*(1 - cosi*cosi);
How does this calculation work?
So k is obviously related to the angle of the refraction. If the refraction is greater than 90°, k becomes negative and then we only have reflection but I still dont understand how it works exactly
Edit. I just realized that the 1 - cosi * cosi calculates the sine

This comment has been minimized.

Copy link
@ssloy

ssloy Dec 7, 2019

Author Owner

Check the "vector form" section from the Snell's law wiki article:
https://en.wikipedia.org/wiki/Snell%27s_law

in particular, this formula:

return k < 0 ? Vec3f(0,0,0) : I*eta + n*(eta * cosi - sqrtf(k));
}

bool scene_intersect(const Vec3f &orig, const Vec3f &dir, const std::vector<Sphere> &spheres, Vec3f &hit, Vec3f &N, Material &material) {
float spheres_dist = std::numeric_limits<float>::max();
for (size_t i=0; i < spheres.size(); i++) {
@@ -67,8 +81,11 @@ Vec3f cast_ray(const Vec3f &orig, const Vec3f &dir, const std::vector<Sphere> &s
}

Vec3f reflect_dir = reflect(dir, N).normalize();
Vec3f refract_dir = refract(dir, N, material.refractive_index).normalize();

This comment has been minimized.

Copy link
@schoolmeister

schoolmeister Jan 28, 2019

There's a possible bug here. If k < 0 in the refract() function, then a (0, 0, 0) vector will be returned. When normalizing this vector a division by zero happens.

This comment has been minimized.

Copy link
@ssloy

ssloy Jan 28, 2019

Author Owner

yup, already fixed by this commit

Vec3f reflect_orig = reflect_dir*N < 0 ? point - N*1e-3 : point + N*1e-3; // offset the original point to avoid occlusion by the object itself
Vec3f refract_orig = refract_dir*N < 0 ? point - N*1e-3 : point + N*1e-3;
Vec3f reflect_color = cast_ray(reflect_orig, reflect_dir, spheres, lights, depth + 1);
Vec3f refract_color = cast_ray(refract_orig, refract_dir, spheres, lights, depth + 1);

float diffuse_light_intensity = 0, specular_light_intensity = 0;
for (size_t i=0; i<lights.size(); i++) {
@@ -84,7 +101,7 @@ Vec3f cast_ray(const Vec3f &orig, const Vec3f &dir, const std::vector<Sphere> &s
diffuse_light_intensity += lights[i].intensity * std::max(0.f, light_dir*N);
specular_light_intensity += powf(std::max(0.f, -reflect(-light_dir, N)*dir), material.specular_exponent)*lights[i].intensity;
}
return material.diffuse_color * diffuse_light_intensity * material.albedo[0] + Vec3f(1., 1., 1.)*specular_light_intensity * material.albedo[1] + reflect_color*material.albedo[2];
return material.diffuse_color * diffuse_light_intensity * material.albedo[0] + Vec3f(1., 1., 1.)*specular_light_intensity * material.albedo[1] + reflect_color*material.albedo[2] + refract_color*material.albedo[3];
}

void render(const std::vector<Sphere> &spheres, const std::vector<Light> &lights) {
@@ -118,13 +135,14 @@ void render(const std::vector<Sphere> &spheres, const std::vector<Light> &lights
}

int main() {
Material ivory(Vec3f(0.6, 0.3, 0.1), Vec3f(0.4, 0.4, 0.3), 50.);
Material red_rubber(Vec3f(0.9, 0.1, 0.0), Vec3f(0.3, 0.1, 0.1), 10.);
Material mirror(Vec3f(0.0, 10.0, 0.8), Vec3f(1.0, 1.0, 1.0), 1425.);
Material ivory(1.0, Vec4f(0.6, 0.3, 0.1, 0.0), Vec3f(0.4, 0.4, 0.3), 50.);
Material glass(1.5, Vec4f(0.0, 0.5, 0.1, 0.8), Vec3f(0.6, 0.7, 0.8), 125.);
Material red_rubber(1.0, Vec4f(0.9, 0.1, 0.0, 0.0), Vec3f(0.3, 0.1, 0.1), 10.);
Material mirror(1.0, Vec4f(0.0, 10.0, 0.8, 0.0), Vec3f(1.0, 1.0, 1.0), 1425.);

std::vector<Sphere> spheres;
spheres.push_back(Sphere(Vec3f(-3, 0, -16), 2, ivory));
spheres.push_back(Sphere(Vec3f(-1.0, -1.5, -12), 2, mirror));
spheres.push_back(Sphere(Vec3f(-1.0, -1.5, -12), 2, glass));
spheres.push_back(Sphere(Vec3f( 1.5, -0.5, -18), 3, red_rubber));
spheres.push_back(Sphere(Vec3f( 7, 5, -18), 4, mirror));

0 comments on commit b69793b

Please sign in to comment.
You can’t perform that action at this time.