-
Notifications
You must be signed in to change notification settings - Fork 335
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
This comment has been minimized.
Sorry, something went wrong. |
||
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.
Sorry, something went wrong.
RoastMyCode
|
||
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.
Sorry, something went wrong.
schoolmeister
|
||
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)); | ||
|
||
|
Another question.
So I am currently trying to implement two-sided triangles and based my code on your tutorial.
I am facing the issue that the refraction indices get swapped when the triangle is backfacing and the refraction doesn't get calculated correctly anymore.
I basically want to get the same result no matter whether the triangles are inserted with the vertices in (counter-)clockwise order.
I think this boils down to a software architectural question but maybe you have an idea on how to easily implementing this.
I also took a look at scratchapixel.com but they are also online using one-sided triangles.