polishing

master
Dmitry V. Sokolov 2022-02-21 21:21:26 +01:00
parent a9a1d11af2
commit 5a8b6d57ef
1 changed files with 33 additions and 39 deletions

View File

@ -1,9 +1,8 @@
#include "geometry.h"
#include <limits>
#include <fstream>
#include <vector>
#include <algorithm>
#include "geometry.h"
struct Light {
vec3 position;
@ -23,12 +22,30 @@ struct Sphere {
Material material;
};
static const Material ivory = {1.0, {0.6, 0.3, 0.1, 0.0}, {0.4, 0.4, 0.3}, 50.};
static const Material glass = {1.5, {0.0, 0.5, 0.1, 0.8}, {0.6, 0.7, 0.8}, 125.};
static const Material red_rubber = {1.0, {0.9, 0.1, 0.0, 0.0}, {0.3, 0.1, 0.1}, 10.};
static const Material mirror = {1.0, {0.0, 10.0, 0.8, 0.0}, {1.0, 1.0, 1.0}, 1425.};
static const std::vector<Sphere> spheres = {
Sphere{vec3{-3, 0, -16}, 2, ivory},
Sphere{vec3{-1.0, -1.5, -12}, 2, glass},
Sphere{vec3{ 1.5, -0.5, -18}, 3, red_rubber},
Sphere{vec3{ 7, 5, -18}, 4, mirror}
};
static const std::vector<Light> lights = {
{{-20, 20, 20}, 1.5},
{{ 30, 50, -25}, 1.8},
{{ 30, 20, 30}, 1.7}
};
bool ray_sphere_intersect(const vec3 &orig, const vec3 &dir, const Sphere &s, float &t0) {
vec3 L = s.center - orig;
float tca = L*dir;
float d2 = L*L - tca*tca;
if (d2 > s.radius*s.radius) return false;
float thc = sqrtf(s.radius*s.radius - d2);
float thc = std::sqrt(s.radius*s.radius - d2);
t0 = tca - thc;
float t1 = tca + thc;
if (t0 < 1e-3) t0 = t1; // offset the original point to avoid occlusion by the object itself
@ -48,7 +65,7 @@ vec3 refract(const vec3 &I, const vec3 &N, const float eta_t, const float eta_i=
return k<0 ? vec3{1,0,0} : I*eta + N*(eta*cosi - std::sqrt(k)); // k<0 = total reflection, no ray to refract. I refract it anyways, this has no physical meaning
}
bool scene_intersect(const vec3 &orig, const vec3 &dir, const std::vector<Sphere> &spheres, vec3 &hit, vec3 &N, Material &material) {
bool scene_intersect(const vec3 &orig, const vec3 &dir, vec3 &hit, vec3 &N, Material &material) {
float spheres_dist = std::numeric_limits<float>::max();
for (const Sphere &s : spheres) {
float dist_i;
@ -74,25 +91,25 @@ bool scene_intersect(const vec3 &orig, const vec3 &dir, const std::vector<Sphere
return std::min(spheres_dist, checkerboard_dist)<1000;
}
vec3 cast_ray(const vec3 &orig, const vec3 &dir, const std::vector<Sphere> &spheres, const std::vector<Light> &lights, size_t depth=0) {
vec3 cast_ray(const vec3 &orig, const vec3 &dir, size_t depth=0) {
vec3 point, N;
Material material;
if (depth>4 || !scene_intersect(orig, dir, spheres, point, N, material))
if (depth>4 || !scene_intersect(orig, dir, point, N, material))
return vec3{0.2, 0.7, 0.8}; // background color
vec3 reflect_dir = reflect(dir, N).normalize();
vec3 refract_dir = refract(dir, N, material.refractive_index).normalize();
vec3 reflect_color = cast_ray(point, reflect_dir, spheres, lights, depth + 1);
vec3 refract_color = cast_ray(point, refract_dir, spheres, lights, depth + 1);
vec3 reflect_color = cast_ray(point, reflect_dir, depth + 1);
vec3 refract_color = cast_ray(point, refract_dir, depth + 1);
float diffuse_light_intensity = 0, specular_light_intensity = 0;
for (const Light light : lights) {
vec3 light_dir = (light.position - point).normalize();
vec3 light_dir = (light.position - point).normalize();
vec3 shadow_pt, trashnrm;
Material trashmat;
if (scene_intersect(point, light_dir, spheres, shadow_pt, trashnrm, trashmat) &&
if (scene_intersect(point, light_dir, shadow_pt, trashnrm, trashmat) &&
(shadow_pt-point).norm() < (light.position-point).norm()) // checking if the point lies in the shadow of the light
continue;
@ -102,19 +119,18 @@ vec3 cast_ray(const vec3 &orig, const vec3 &dir, const std::vector<Sphere> &sphe
return material.diffuse_color * diffuse_light_intensity * material.albedo[0] + vec3{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) {
const int width = 1024;
const int height = 768;
const float fov = M_PI/3.;
int main() {
const int width = 1024;
const int height = 768;
const float fov = M_PI/3.;
std::vector<vec3> framebuffer(width*height);
#pragma omp parallel for
#pragma omp parallel for
for (size_t j = 0; j<height; j++) { // actual rendering loop
for (size_t i = 0; i<width; i++) {
float dir_x = (i + 0.5) - width/2.;
float dir_y = -(j + 0.5) + height/2.; // this flips the image at the same time
float dir_z = -height/(2.*tan(fov/2.));
framebuffer[i+j*width] = cast_ray(vec3{0,0,0}, vec3{dir_x, dir_y, dir_z}.normalize(), spheres, lights);
framebuffer[i+j*width] = cast_ray(vec3{0,0,0}, vec3{dir_x, dir_y, dir_z}.normalize());
}
}
@ -127,28 +143,6 @@ void render(const std::vector<Sphere> &spheres, const std::vector<Light> &lights
ofs << (char)(255 * c[0]) << (char)(255 * c[1]) << (char)(255 * c[2]);
}
ofs.close();
}
int main() {
const Material ivory = {1.0, {0.6, 0.3, 0.1, 0.0}, {0.4, 0.4, 0.3}, 50.};
const Material glass = {1.5, {0.0, 0.5, 0.1, 0.8}, {0.6, 0.7, 0.8}, 125.};
const Material red_rubber = {1.0, {0.9, 0.1, 0.0, 0.0}, {0.3, 0.1, 0.1}, 10.};
const Material mirror = {1.0, {0.0, 10.0, 0.8, 0.0}, {1.0, 1.0, 1.0}, 1425.};
std::vector<Sphere> spheres = {
Sphere{vec3{-3, 0, -16}, 2, ivory},
Sphere{vec3{-1.0, -1.5, -12}, 2, glass},
Sphere{vec3{ 1.5, -0.5, -18}, 3, red_rubber},
Sphere{vec3{ 7, 5, -18}, 4, mirror}
};
std::vector<Light> lights = {
{{-20, 20, 20}, 1.5},
{{ 30, 50, -25}, 1.8},
{{ 30, 20, 30}, 1.7}
};
render(spheres, lights);
return 0;
}