1
0
mirror of https://github.com/ssloy/tinyraytracer.git synced 2025-08-31 09:41:46 +02:00

depth map raytracing

This commit is contained in:
Dmitry V. Sokolov
2019-02-03 15:05:01 +01:00
parent c19c430151
commit 09bf2208e5
6 changed files with 95 additions and 125 deletions

12
.gitpod.yml Normal file
View File

@@ -0,0 +1,12 @@
image:
file: Dockerfile
tasks:
- command: >
mkdir --parents build &&
cd build &&
cmake .. &&
make &&
./tinyraycaster &&
pnmtopng out.ppm > out.png &&
open out.png &&
cd ..

6
Dockerfile Normal file
View File

@@ -0,0 +1,6 @@
FROM gitpod/workspace-full
USER root
# add your tools here
RUN apt-get update && apt-get install -y \
netpbm

BIN
doc/depthmap.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -3,83 +3,41 @@
#include <cmath>
#include <vector>
#include <cassert>
#include <iostream>
template <size_t DIM, typename T> struct vec {
vec() { for (size_t i=DIM; i--; data_[i] = T()); }
T& operator[](const size_t i) { assert(i<DIM); return data_[i]; }
const T& operator[](const size_t i) const { assert(i<DIM); return data_[i]; }
private:
T data_[DIM];
};
typedef vec<2, float> Vec2f;
typedef vec<3, float> Vec3f;
typedef vec<3, int > Vec3i;
typedef vec<4, float> Vec4f;
template <typename T> struct vec<2,T> {
vec() : x(T()), y(T()) {}
vec(T X, T Y) : x(X), y(Y) {}
template <class U> vec<2,T>(const vec<2,U> &v);
T& operator[](const size_t i) { assert(i<2); return i<=0 ? x : y; }
const T& operator[](const size_t i) const { assert(i<2); return i<=0 ? x : y; }
T x,y;
};
template <typename T> struct vec<3,T> {
vec() : x(T()), y(T()), z(T()) {}
vec(T X, T Y, T Z) : x(X), y(Y), z(Z) {}
template <typename T> struct vec3 {
T& operator[](const size_t i) { assert(i<3); return i<=0 ? x : (1==i ? y : z); }
const T& operator[](const size_t i) const { assert(i<3); return i<=0 ? x : (1==i ? y : z); }
float norm() { return std::sqrt(x*x+y*y+z*z); }
vec<3,T> & normalize(T l=1) { *this = (*this)*(l/norm()); return *this; }
vec3<T> & normalize(T l=1) { *this = (*this)*(l/std::sqrt((*this)*(*this))); return *this; }
T x,y,z;
};
template <typename T> struct vec<4,T> {
vec() : x(T()), y(T()), z(T()), w(T()) {}
vec(T X, T Y, T Z, T W) : x(X), y(Y), z(Z), w(W) {}
T& operator[](const size_t i) { assert(i<4); return i<=0 ? x : (1==i ? y : (2==i ? z : w)); }
const T& operator[](const size_t i) const { assert(i<4); return i<=0 ? x : (1==i ? y : (2==i ? z : w)); }
T x,y,z,w;
};
template<size_t DIM,typename T> T operator*(const vec<DIM,T>& lhs, const vec<DIM,T>& rhs) {
template<typename T> T operator*(const vec3<T>& lhs, const vec3<T>& rhs) {
T ret = T();
for (size_t i=DIM; i--; ret+=lhs[i]*rhs[i]);
for (size_t i=3; i--; ret+=lhs[i]*rhs[i]);
return ret;
}
template<size_t DIM,typename T>vec<DIM,T> operator+(vec<DIM,T> lhs, const vec<DIM,T>& rhs) {
for (size_t i=DIM; i--; lhs[i]+=rhs[i]);
template<typename T> vec3<T> operator+(vec3<T> lhs, const vec3<T>& rhs) {
for (size_t i=3; i--; lhs[i]+=rhs[i]);
return lhs;
}
template<size_t DIM,typename T>vec<DIM,T> operator-(vec<DIM,T> lhs, const vec<DIM,T>& rhs) {
for (size_t i=DIM; i--; lhs[i]-=rhs[i]);
template<typename T> vec3<T> operator-(vec3<T> lhs, const vec3<T>& rhs) {
for (size_t i=3; i--; lhs[i]-=rhs[i]);
return lhs;
}
template<size_t DIM,typename T,typename U> vec<DIM,T> operator*(const vec<DIM,T> &lhs, const U& rhs) {
vec<DIM,T> ret;
for (size_t i=DIM; i--; ret[i]=lhs[i]*rhs);
template<typename T,typename U> vec3<T> operator*(const vec3<T> &lhs, const U& rhs) {
vec3<T> ret;
for (size_t i=3; i--; ret[i]=lhs[i]*rhs);
return ret;
}
template<size_t DIM,typename T> vec<DIM,T> operator-(const vec<DIM,T> &lhs) {
template<typename T> vec3<T> operator-(const vec3<T> &lhs) {
return lhs*T(-1);
}
template <typename T> vec<3,T> cross(vec<3,T> v1, vec<3,T> v2) {
return vec<3,T>(v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x);
}
typedef vec3<float> Vec3f;
template <size_t DIM, typename T> std::ostream& operator<<(std::ostream& out, const vec<DIM,T>& v) {
for(unsigned int i=0; i<DIM; i++) {
out << v[i] << " " ;
}
return out ;
}
#endif //__GEOMETRY_H__

BIN
out.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -1,100 +1,94 @@
#include <limits>
#define _USE_MATH_DEFINES
#include <cmath>
#include <limits>
#include <iostream>
#include <fstream>
#include <vector>
#include <numeric>
#include "geometry.h"
struct Material {
Material(const Vec3f &color) : diffuse_color(color) {}
Material() : diffuse_color() {}
Vec3f diffuse_color;
};
struct Sphere {
Vec3f center;
float radius;
Material material;
};
Sphere(const Vec3f &c, const float &r, const Material &m) : center(c), radius(r), material(m) {}
bool ray_intersect(const Vec3f &orig, const Vec3f &dir, float &t0) const {
Vec3f L = center - orig;
bool sphere_ray_intersect(const Sphere &sphere, const Vec3f &orig, const Vec3f &dir, float &t0) {
Vec3f L = sphere.center - orig;
float tca = L*dir;
float d2 = L*L - tca*tca;
if (d2 > radius*radius) return false;
float thc = sqrtf(radius*radius - d2);
if (d2 > pow(sphere.radius, 2)) return false;
float thc = sqrtf(pow(sphere.radius, 2) - d2);
t0 = tca - thc;
float t1 = tca + thc;
if (t0 < 0) t0 = t1;
if (t0 < 0) return false;
return true;
}
};
}
bool scene_intersect(const Vec3f &orig, const Vec3f &dir, const std::vector<Sphere> &spheres, Vec3f &hit, Vec3f &N, Material &material) {
float scene_intersect(const Vec3f &orig, const Vec3f &dir, const std::vector<Sphere> &spheres) {
float spheres_dist = std::numeric_limits<float>::max();
for (size_t i=0; i < spheres.size(); i++) {
for (size_t i=0; i<spheres.size(); i++) {
float dist_i;
if (spheres[i].ray_intersect(orig, dir, dist_i) && dist_i < spheres_dist) {
if (sphere_ray_intersect(spheres[i], orig, dir, dist_i) && dist_i < spheres_dist) {
spheres_dist = dist_i;
hit = orig + dir*dist_i;
N = (hit - spheres[i].center).normalize();
material = spheres[i].material;
}
}
return spheres_dist<1000;
float checkerboard_dist = std::numeric_limits<float>::max();
if (fabs(dir.y)>1e-3) {
float d = -(orig.y+4)/dir.y; // the checkerboard plane has equation y = -4
Vec3f pt = orig + dir*d;
if (d>0 && fabs(pt.x)<10 && pt.z<-10 && pt.z>-30) {
checkerboard_dist = d;
}
}
return std::min(spheres_dist, checkerboard_dist);
}
Vec3f cast_ray(const Vec3f &orig, const Vec3f &dir, const std::vector<Sphere> &spheres) {
Vec3f point, N;
Material material;
if (!scene_intersect(orig, dir, spheres, point, N, material)) {
return Vec3f(0.2, 0.7, 0.8); // background color
}
return material.diffuse_color;
}
void render(const std::vector<Sphere> &spheres) {
const int width = 1024;
const int height = 768;
const int fov = M_PI/2.;
std::vector<Vec3f> framebuffer(width*height);
#pragma omp parallel for
for (size_t j = 0; j<height; j++) {
for (size_t i = 0; i<width; i++) {
float x = (2*(i + 0.5)/(float)width - 1)*tan(fov/2.)*width/(float)height;
float y = -(2*(j + 0.5)/(float)height - 1)*tan(fov/2.);
Vec3f dir = Vec3f(x, y, -1).normalize();
framebuffer[i+j*width] = cast_ray(Vec3f(0,0,0), dir, spheres);
void compute_depthmap(const size_t width, const size_t height, const float fov, const float far, const std::vector<Sphere> &spheres, std::vector<float> &zbuffer) {
#pragma omp parallel for
for (size_t j=0; j<height; j++) {
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.)));
Vec3f dir = Vec3f{dir_x, dir_y, dir_z}.normalize();
zbuffer[i+j*width] = scene_intersect(Vec3f{0,0,0}, dir, spheres);
}
}
std::ofstream ofs; // save the framebuffer to file
ofs.open("./out.ppm");
ofs << "P6\n" << width << " " << height << "\n255\n";
for (size_t i = 0; i < height*width; ++i) {
for (size_t j = 0; j<3; j++) {
ofs << (char)(255 * std::max(0.f, std::min(1.f, framebuffer[i][j])));
float minval = std::numeric_limits<float>::max(); // clamp the zbuffer by the far plane and normalize it between 0 and 1
float maxval = -std::numeric_limits<float>::max();
for (size_t i=0; i<height*width; ++i) {
minval = std::min(minval, zbuffer[i]);
maxval = std::max(maxval, std::min(zbuffer[i], far));
}
}
ofs.close();
for (size_t i=0; i<height*width; ++i)
zbuffer[i] = 1-(std::min(zbuffer[i],far)-minval)/(maxval-minval);
}
int main() {
Material ivory(Vec3f(0.4, 0.4, 0.3));
Material red_rubber(Vec3f(0.3, 0.1, 0.1));
std::vector<Sphere> spheres = { {{-3,0,-16}, 2}, {{-1,-1.5,-12}, 2}, {{1.5,-.5,-18}, 3}, {{7,5,-18}, 4} };
const size_t width = 1024;
const size_t height = 768;
const float fov = M_PI/3.;
std::vector<float> zbuffer(width*height);
compute_depthmap(width, height, fov, 23.f, spheres, zbuffer);
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, red_rubber));
spheres.push_back(Sphere(Vec3f( 1.5, -0.5, -18), 3, red_rubber));
spheres.push_back(Sphere(Vec3f( 7, 5, -18), 4, ivory));
std::vector<unsigned char> framebuffer(width*height*3);
for (size_t j=0; j<height; j++) {
for (size_t i=0; i<width; i++) {
for (size_t d=0; d<3; d++) {
framebuffer[(i+j*width)*3 + d] = 255*zbuffer[i+j*width];
}
}
}
render(spheres);
std::ofstream ofs("./out.ppm"); // save the framebuffer to file
ofs << "P6\n" << width << " " << height << "\n255\n";
ofs.write(reinterpret_cast<char *>(framebuffer.data()), 3*height*width);
ofs.close();
return 0;
}