Skip to content

Instantly share code, notes, and snippets.

@gauravssnl
Forked from zserge/ray.cc
Created September 28, 2022 07:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gauravssnl/6dd188732569e6f4e3cd4283d213fe07 to your computer and use it in GitHub Desktop.
Save gauravssnl/6dd188732569e6f4e3cd4283d213fe07 to your computer and use it in GitHub Desktop.
Minimal ray tracer for leaning purposes
#include <array>
#include <cmath>
#include <fstream>
#include <iostream>
#include <vector>
struct Vec {
float x, y, z;
Vec(float vx, float vy, float vz) : x(vx), y(vy), z(vz) {}
Vec operator+(Vec vec) { return {x + vec.x, y + vec.y, z + vec.z}; }
Vec operator-(Vec vec) { return {x - vec.x, y - vec.y, z - vec.z}; }
Vec operator*(float n) { return {x * n, y * n, z * n}; }
Vec unit() { return Vec(x, y, z) * (1 / this->length()); }
// dot product
float operator%(Vec vec) { return x * vec.x + y * vec.y + z * vec.z; }
float length() { return sqrtf(*this % *this); }
};
struct Sphere {
Vec center;
float color;
float radius;
float intersect(Vec origin, Vec direction) {
Vec p = origin - this->center;
float a = direction % direction;
float b = (p % direction) * 2;
float c = (p % p) - (this->radius * this->radius);
float d = b * b - 4 * a * c;
if (d < 0) {
return NAN;
}
float sqd = sqrtf(d);
float distance = (-b - sqd) / (2.f * a);
if (distance > .1f) {
return distance;
}
distance = (-b + sqd) / (2.f * a);
if (distance > .1f) {
return distance;
}
return NAN;
}
};
struct World {
std::vector<Sphere> spheres;
std::vector<Sphere> lights;
};
float trace(World world, Vec origin, Vec direction) {
int index = -1;
float distance = NAN;
for (int i = 0; i < world.spheres.size(); ++i) {
float d = world.spheres[i].intersect(origin, direction);
if (!std::isnan(d) && (index < 0 || d < distance)) {
distance = d;
index = i;
}
}
if (index < 0) {
return 1.f - direction.y;
}
Vec p = origin + direction * distance;
Vec n = (p - world.spheres[index].center).unit();
float c = world.spheres[index].color * .1f;
for (auto light : world.lights) {
Vec l = (light.center - p).unit();
int shadow = 0;
for (auto sphere : world.spheres) {
if (!std::isnan(sphere.intersect(p, l))) {
shadow = 1;
}
}
if (!shadow) {
float df = std::max(0.f, (l % n) * 0.7f);
float sp = powf(fmax(0.f, (l % n)), 70.f) * 0.4f;
c = c + world.spheres[index].color * light.color * df + sp;
}
}
return c;
}
void render_pgm_stereo(World world, std::string filename, int width,
int height) {
std::ofstream f(filename);
f << "P2" << std::endl << (width * 2) << " " << height << " 255" << std::endl;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
float c = trace(world, {0, 1, 5},
Vec(x - width / 2, height / 2 - y, -height).unit());
f << ((int)(c * 255)) << " ";
}
for (int x = 0; x < width; x++) {
float c = trace(world, {0.5, 1, 5},
Vec(x - width / 2, height / 2 - y, -height).unit());
f << ((int)(c * 255)) << " ";
}
}
}
void render_pgm(World world, std::string filename, int width, int height) {
std::ofstream f(filename);
f << "P2" << std::endl << width << " " << height << " 255" << std::endl;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
float c = trace(world, {0, 1, 5},
Vec(x - width / 2, height / 2 - y, -height).unit());
f << ((int)(c * 255)) << " ";
}
}
}
void render_tty(World world, int width, int height) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
float c = trace(world, {0, 1, 5},
Vec(x - width / 2, height / 2 - y, -height).unit());
char pixel = " .:-=+*#%@$"[std::max(std::min((int)(c * 10), 10), 0)];
std::cout << pixel << pixel;
}
std::cout << std::endl;
}
}
int main() {
World world = {
// spheres
{
{{0, -1000, 0}, 0.001, 1000},
{{-2, 1, -2}, 1, 1},
{{0, 1, 0}, 0.5, 1},
{{2, 1, -1}, 0.1, 1},
},
// lights
{
{{0, 100, 0}, .4, 0},
{{100, 100, 200}, .5, 0},
{{-100, 300, 100}, .1, 0},
},
};
render_pgm(world, "ray_mono.pgm", 600, 600);
render_pgm_stereo(world, "ray.pgm", 300, 200);
render_tty(world, 40, 25);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment