Compare commits

...

2 Commits

Author SHA1 Message Date
ktyl 3d2c8e83a6 update todo 2023-02-20 01:21:10 +00:00
ktyl 75e9bac556 refactoring, remove rtweekend header 2023-02-20 01:19:28 +00:00
19 changed files with 274 additions and 281 deletions

View File

@ -13,9 +13,10 @@ https://www.linuxhowtos.org/C_C++/socket.htm
* [x] waits for connection
* [x] send a message to the client
* [x] move core rendering out of main.cpp
* [ ] combine 'hittable' 'hittable_list' and 'scene' into 'world'
* [x] combine 'hittable' 'hittable_list' and 'scene' in 'world'
* [x] send rendered image data to client
* [x] form image file on client
* [ ] extract netcode from main
* [ ] specify protocol format
* [ ] receive imaging command
* [x] render image

View File

@ -1,6 +1,7 @@
#pragma once
#include "rtweekend.h"
#include "error.h"
#include "vec3.h"
// for writing to stdout
#include <iostream>
@ -8,59 +9,21 @@
// for writing to socket
#include <unistd.h>
class colour : public vec3
{
using vec3::vec3;
public:
friend colour operator*(const colour& u, const colour& v);
friend colour lerp(const colour& a, const colour& b, double t);
colour correct_gamma(int samples);
friend void write_colour_to_socket(int sockfd, colour pixel_colour, int samples_per_pixel);
friend void write_colour_to_stream(std::ostream &out, colour pixel_colour, int samples_per_pixel);
friend int format_component(double component);
};
const colour pink(254.0/255.0, 226.0/255.0, 170.0/255.0);
const colour grey(0.133, 0.133, 0.133);
void correct_gamma(colour& pixel_colour, int samples)
{
double r = pixel_colour.x();
double g = pixel_colour.y();
double b = pixel_colour.z();
// divide the colour total by the number of samples and gamma-correct for gamma=2.0
auto scale = 1.0 / samples;
r = sqrt(scale * r);
g = sqrt(scale * g);
b = sqrt(scale * b);
pixel_colour = colour(r, g, b);
}
int format_component(double component)
{
return int(256 * math::clamp(component, 0.0, 0.999));
}
void write_colour_to_stream(std::ostream &out, colour pixel_colour, int samples_per_pixel)
{
correct_gamma(pixel_colour, samples_per_pixel);
auto r = pixel_colour.x();
auto g = pixel_colour.y();
auto b = pixel_colour.z();
// write the translated [0,255] value of each colour component.
out << format_component(r) << ' '
<< format_component(g) << ' '
<< format_component(b) << '\n';
}
void write_colour_to_socket(int sockfd, colour pixel_colour, int samples_per_pixel)
{
correct_gamma(pixel_colour, samples_per_pixel);
int r = format_component(pixel_colour.x());
int g = format_component(pixel_colour.y());
int b = format_component(pixel_colour.z());
// pack values
int len = 3;
char s[len];
sprintf(s, "%c%c%c", r, g, b);
int written = write(sockfd, s, len);
if (written < 0)
{
error("ERROR writing colour to socket");
}
}

View File

@ -1,7 +1,5 @@
#pragma once
#include <iostream>
void error(const char* message)
{
perror(message);
exit(1);
}
void error(const char* message);

23
include/hit_record.h Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#include <cmath>
#include <cstdlib>
#include <limits>
#include <memory>
class material;
struct hit_record
{
point3 p;
vec3 normal;
std::shared_ptr<material> mat_ptr;
double t;
bool front_face;
inline void set_face_normal(const ray& r, const vec3& outward_normal)
{
front_face = dot(r.direction(), outward_normal) < 0;
normal = front_face ? outward_normal : -outward_normal;
}
};

View File

@ -1,27 +1,10 @@
#pragma once
#include "rtweekend.h"
#include "ray.h"
class material;
struct hit_record
{
point3 p;
vec3 normal;
shared_ptr<material> mat_ptr;
double t;
bool front_face;
inline void set_face_normal(const ray& r, const vec3& outward_normal)
{
front_face = dot(r.direction(), outward_normal) < 0;
normal = front_face ? outward_normal : -outward_normal;
}
};
#include "hit_record.h"
class hittable
{
public:
virtual bool hit(const ray& r, double tMin, double tMax, hit_record& rec) const = 0;
public:
virtual bool hit(const ray& r, double tMin, double tMax, hit_record& rec) const = 0;
};

View File

@ -20,21 +20,3 @@ class hittable_list : public hittable
std::vector<std::shared_ptr<hittable>> objects_;
};
bool hittable_list::hit(const ray& r, double t_min, double t_max, hit_record& rec) const
{
hit_record temp_rec;
bool hit_anything = false;
auto closest_so_far = t_max;
for (const auto& object : objects_)
{
if (object->hit(r, t_min, closest_so_far, temp_rec))
{
hit_anything = true;
closest_so_far = temp_rec.t;
rec = temp_rec;
}
}
return hit_anything;
}

View File

@ -1,7 +1,7 @@
#pragma once
#include "rtweekend.h"
#include "hittable.h"
#include "hit_record.h"
class material
{
@ -13,13 +13,6 @@ class material
ray& scattered) const = 0;
};
double schlick(double cosine, double refraction_index)
{
auto r0 = (1-refraction_index) / (1+refraction_index);
r0 = r0*r0;
return r0 + (1-r0)*pow(1-cosine, 5);
}
class lambertian : public material
{
public:
@ -106,4 +99,11 @@ class dielectric : public material
private:
double refraction_index_;
double schlick(double cosine, double refraction_index) const
{
auto r0 = (1-refraction_index) / (1+refraction_index);
r0 = r0*r0;
return r0 + (1-r0)*pow(1-cosine, 5);
}
};

View File

@ -1,18 +0,0 @@
#pragma once
#include <cmath>
#include <cstdlib>
#include <limits>
#include <memory>
// usings
using std::shared_ptr;
using std::make_shared;
using std::sqrt;
// common headers
#include "error.h"
#include "ray.h"
#include "vec3.h"

View File

@ -1,100 +0,0 @@
#pragma once
#include "math.h"
#include "sphere.h"
#include "colour.h"
#include "material.h"
#include "hittable.h"
#include "hittable_list.h"
colour ray_colour(const ray& r, const hittable& world, int depth)
{
hit_record rec;
if (depth <= 0)
{
return grey;
}
if (world.hit(r, 0.001, math::infinity, rec))
{
ray scattered;
colour attenuation;
if (rec.mat_ptr->scatter(r, rec, attenuation, scattered))
{
return attenuation * ray_colour(scattered, world, depth-1);
}
return grey;
}
vec3 unit_direction = normalize(r.direction());
auto t = 0.5 * (unit_direction.y() + 1.0) + 0.5;
return lerp(grey, pink, t);
}
hittable_list random_scene()
{
hittable_list world;
//auto ground_material = make_shared<lambertian>(pink);
//world.add(make_shared<sphere>(point3(0,-1000,0), 1000, ground_material));
//for (int a = -11; a < 11; a++)
//{
// for (int b = -11; b < 11; b++)
// {
// auto choose_mat = random_double();
// point3 centre(a + 0.9*random_double(), 0.2, b + 0.9*random_double());
// if ((centre - point3(4, 0.2, 0)).length() > 0.9)
// {
// shared_ptr<material> sphere_material;
// if (choose_mat < 0.8)
// {
// // diffuse
// //auto albedo = colour::random() * colour::random();
// sphere_material = make_shared<lambertian>(pink);
// world.add(make_shared<sphere>(centre, 0.2, sphere_material));
// }
// else if (choose_mat < 0.95)
// {
// // metal
// auto fuzz = random_double(0, 0.5);
// sphere_material = make_shared<metal>(pink, fuzz);
// world.add(make_shared<sphere>(centre, 0.2, sphere_material));
// }
// else
// {
// // glass
// sphere_material = make_shared<dielectric>(1.5);
// world.add(make_shared<sphere>(centre,0.2, sphere_material));
// }
// }
// }
//}
auto material1 = make_shared<dielectric>(1.5);
world.add(make_shared<sphere>(point3(0, 0, 0), 3.0, material1));
//auto material2 = make_shared<lambertian>(pink);
//world.add(make_shared<sphere>(point3(-4, 1, 0), 1.0, material2));
auto material3 = make_shared<metal>(pink, 0.5);
int sphere_count = 10;
for (int i = 0; i < sphere_count; i++)
{
float a = 6.28 * (float)i/sphere_count - 100.0;
float r = 8.0;
float x = r*sin(a);
float y = 2.0*cos(a);
float z = r*cos(a);
point3 pos(x,y,z);
world.add(make_shared<sphere>(pos, 2.0, material3));
}
return world;
}

View File

@ -7,7 +7,7 @@ class sphere : public hittable
{
public:
sphere() {}
sphere(point3 centre, double r, shared_ptr<material> m) :
sphere(point3 centre, double r, std::shared_ptr<material> m) :
centre_(centre),
radius_(r),
mat_ptr_(m)
@ -16,49 +16,8 @@ class sphere : public hittable
virtual bool hit(const ray& r, double t_min, double t_max, hit_record& rec) const;
private:
point3 centre_;
double radius_;
shared_ptr<material> mat_ptr_;
point3 centre_;
double radius_;
std::shared_ptr<material> mat_ptr_;
};
bool sphere::hit(const ray& r, double t_min, double t_max, hit_record& rec) const
{
vec3 oc = r.origin() - centre_;
auto a = r.direction().length_squared();
auto half_b = dot(oc, r.direction());
auto c = oc.length_squared() - radius_*radius_;
auto discriminant = half_b*half_b - a*c;
if (discriminant > 0)
{
auto root = sqrt(discriminant);
auto temp = (-half_b - root)/a;
if (temp < t_max && temp > t_min)
{
rec.t = temp;
rec.p = r.at(rec.t);
vec3 outward_normal = (rec.p - centre_) / radius_;
rec.set_face_normal(r, outward_normal);
rec.mat_ptr = mat_ptr_;
return true;
}
temp = (-half_b + root) / a;
if (temp < t_max && temp > t_min)
{
rec.t = temp;
rec.p = r.at(rec.t);
vec3 outward_normal = (rec.p - centre_) / radius_;
rec.set_face_normal(r, outward_normal);
rec.mat_ptr = mat_ptr_;
return true;
}
}
return false;
}

View File

@ -52,5 +52,4 @@ private:
// type aliases for vec3
using point3 = vec3; // 3D point
using colour = vec3; // RGB colour

17
include/world.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include "math.h"
#include "sphere.h"
#include "colour.h"
#include "material.h"
#include "hittable_list.h"
class world : public hittable_list
{
public:
static world* close_glass_sphere();
static world* orb_field();
friend colour trace(const world& world, const ray& ray, int depth);
};

67
src/colour.cpp Normal file
View File

@ -0,0 +1,67 @@
#include "colour.h"
colour colour::correct_gamma(int samples)
{
double r = x();
double g = y();
double b = z();
// divide the colour total by the number of samples and gamma-correct for gamma=2.0
auto scale = 1.0 / samples;
r = sqrt(scale * r);
g = sqrt(scale * g);
b = sqrt(scale * b);
return colour(r, g, b);
}
int format_component(double component)
{
return int(256 * math::clamp(component, 0.0, 0.999));
}
void write_colour_to_socket(int sockfd, colour pixel_colour, int samples_per_pixel)
{
pixel_colour = pixel_colour.correct_gamma(samples_per_pixel);
int r = format_component(pixel_colour.x());
int g = format_component(pixel_colour.y());
int b = format_component(pixel_colour.z());
// pack values
int len = 3;
char s[len];
sprintf(s, "%c%c%c", r, g, b);
int written = write(sockfd, s, len);
if (written < 0)
{
error("ERROR writing colour to socket");
}
}
void write_colour_to_stream(std::ostream &out, colour pixel_colour, int samples_per_pixel)
{
pixel_colour = pixel_colour.correct_gamma(samples_per_pixel);
auto r = pixel_colour.x();
auto g = pixel_colour.y();
auto b = pixel_colour.z();
// write the translated [0,255] value of each colour component.
out << format_component(r) << ' '
<< format_component(g) << ' '
<< format_component(b) << '\n';
}
colour operator*(const colour& u, const colour& v)
{
vec3 value = (vec3)u * (vec3)v;
return colour(value.x(), value.y(), value.z());
}
colour lerp(const colour& a, const colour& b, double t)
{
vec3 value = lerp((vec3)a, (vec3)b, t);
return colour(value.x(), value.y(), value.z());
}

7
src/error.cpp Normal file
View File

@ -0,0 +1,7 @@
#include "error.h"
void error(const char* message)
{
perror(message);
exit(1);
}

View File

@ -1 +0,0 @@
#include "foo.h"

20
src/hittable_list.cpp Normal file
View File

@ -0,0 +1,20 @@
#include "hittable_list.h"
bool hittable_list::hit(const ray& r, double t_min, double t_max, hit_record& rec) const
{
hit_record temp_rec;
bool hit_anything = false;
auto closest_so_far = t_max;
for (const auto& object : objects_)
{
if (object->hit(r, t_min, closest_so_far, temp_rec))
{
hit_anything = true;
closest_so_far = temp_rec.t;
rec = temp_rec;
}
}
return hit_anything;
}

View File

@ -1,14 +1,10 @@
#include "rtweekend.h"
#include "scene.h"
#include "colour.h"
#include "camera.h"
#include "material.h"
#include "image.h"
#include "world.h"
#include <iostream>
#include <string.h>
#include <unistd.h>
@ -106,7 +102,7 @@ void send_image_dimensions(int sock, unsigned int width, unsigned int height)
}
}
void render(camera& cam, hittable_list& world, int client_sock)
void render(camera& cam, const world& world, int client_sock)
{
for (int j = HEIGHT - 1; j >= 0; --j)
{
@ -120,7 +116,7 @@ void render(camera& cam, hittable_list& world, int client_sock)
auto u = (i + math::random_double()) / (WIDTH-1);
auto v = (j + math::random_double()) / (HEIGHT-1);
ray r = cam.get_ray(u, v);
pixel_colour += ray_colour(r, world, MAX_DEPTH);
pixel_colour += trace(world, r, MAX_DEPTH);
}
// TODO: we should instead write our output to some buffer in memory
@ -142,8 +138,6 @@ int main()
//std::cout << "P3\n" << WIDTH << ' ' << HEIGHT << "\n255\n";
hittable_list world = random_scene();
auto dist_to_target = 10.0;
auto dist_to_focus = dist_to_target + 1.0;
auto cam_y = 1.0;
@ -154,7 +148,9 @@ int main()
camera cam(lookfrom, lookat, vup, 47, ASPECT_RATIO, aperture, dist_to_focus);
render(cam, world, newsockfd);
const world* world = world::close_glass_sphere();
render(cam, *world, newsockfd);
// close client socket
close(newsockfd);

43
src/sphere.cpp Normal file
View File

@ -0,0 +1,43 @@
#include "sphere.h"
bool sphere::hit(const ray& r, double t_min, double t_max, hit_record& rec) const
{
vec3 oc = r.origin() - centre_;
auto a = r.direction().length_squared();
auto half_b = dot(oc, r.direction());
auto c = oc.length_squared() - radius_*radius_;
auto discriminant = half_b*half_b - a*c;
if (discriminant > 0)
{
auto root = sqrt(discriminant);
auto temp = (-half_b - root)/a;
if (temp < t_max && temp > t_min)
{
rec.t = temp;
rec.p = r.at(rec.t);
vec3 outward_normal = (rec.p - centre_) / radius_;
rec.set_face_normal(r, outward_normal);
rec.mat_ptr = mat_ptr_;
return true;
}
temp = (-half_b + root) / a;
if (temp < t_max && temp > t_min)
{
rec.t = temp;
rec.p = r.at(rec.t);
vec3 outward_normal = (rec.p - centre_) / radius_;
rec.set_face_normal(r, outward_normal);
rec.mat_ptr = mat_ptr_;
return true;
}
}
return false;
}

54
src/world.cpp Normal file
View File

@ -0,0 +1,54 @@
#include "world.h"
colour trace(const world& world, const ray& r, int depth)
{
hit_record rec;
if (depth <= 0)
{
return grey;
}
if (world.hit(r, 0.001, math::infinity, rec))
{
ray scattered;
colour attenuation;
if (rec.mat_ptr->scatter(r, rec, attenuation, scattered))
{
return attenuation * trace(world, scattered, depth-1);
}
return grey;
}
vec3 unit_direction = normalize(r.direction());
auto t = 0.5 * (unit_direction.y() + 1.0) + 0.5;
return lerp(grey, pink, t);
}
world* world::close_glass_sphere()
{
world* w = new world();
auto material1 = std::make_shared<dielectric>(1.5);
w->add(std::make_shared<sphere>(point3(0, 0, 0), 3.0, material1));
//auto material2 = make_shared<lambertian>(pink);
//world.add(make_shared<sphere>(point3(-4, 1, 0), 1.0, material2));
auto material3 = std::make_shared<metal>(pink, 0.5);
int sphere_count = 10;
for (int i = 0; i < sphere_count; i++)
{
float a = 6.28 * (float)i/sphere_count - 100.0;
float r = 8.0;
float x = r*sin(a);
float y = 2.0*cos(a);
float z = r*cos(a);
point3 pos(x,y,z);
w->add(std::make_shared<sphere>(pos, 2.0, material3));
}
return w;
}