Skip to content

Commit

Permalink
Tiny KABOOM first commit; the simplest possible ray marching
Browse files Browse the repository at this point in the history
  • Loading branch information
ssloy committed Jan 27, 2019
0 parents commit c45987e
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 0 deletions.
27 changes: 27 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
cmake_minimum_required (VERSION 2.8)
project (tinykaboom)

include(CheckCXXCompilerFlag)

function(enable_cxx_compiler_flag_if_supported flag)
string(FIND "${CMAKE_CXX_FLAGS}" "${flag}" flag_already_set)
if(flag_already_set EQUAL -1)
check_cxx_compiler_flag("${flag}" flag_supported)
if(flag_supported)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}" PARENT_SCOPE)
endif()
unset(flag_supported CACHE)
endif()
endfunction()

enable_cxx_compiler_flag_if_supported("-Wall")
enable_cxx_compiler_flag_if_supported("-Wextra")
enable_cxx_compiler_flag_if_supported("-pedantic")
enable_cxx_compiler_flag_if_supported("-std=c++11")
enable_cxx_compiler_flag_if_supported("-O3")
enable_cxx_compiler_flag_if_supported("-fopenmp")

file(GLOB SOURCES *.h *.cpp)

add_executable(${PROJECT_NAME} ${SOURCES})

21 changes: 21 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Tiny KABOOM in less than 200 lines of bare C++

This repository is a support code for my computer graphics lectures. It is not meant to be the ultimate rendering code or even physically realistic. It is meant to be **simple**. This project is distributed under the [DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE](https://en.wikipedia.org/wiki/WTFPL).

**Check [the article](https://github.com/ssloy/tinykaboom/wiki) that accompanies the source code.
If you are looking for a software rasterizer, check the [other part of the lectures](https://github.com/ssloy/tinyrenderer/wiki).**

In my lectures I tend to avoid third party libraries as long as it is reasonable, because it forces to understand what is happening under the hood. So, the raytracing 256 lines of plain C++ give us this result:
![](https://raw.githubusercontent.com/ssloy/tinykaboom/master/out.jpg)

## compilation
```sh
git clone https://github.com/ssloy/tinykaboom.git
cd tinykaboom
mkdir build
cd build
cmake ..
make
```


53 changes: 53 additions & 0 deletions geometry.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#ifndef __GEOMETRY_H__
#define __GEOMETRY_H__
#include <cmath>
#include <cassert>

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];
};

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) {}
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() const { return std::sqrt(x*x+y*y+z*z); }
vec<3,T> & normalize(T l=1) { *this = (*this)*(l/norm()); return *this; }
T x,y,z;
};

template<size_t DIM,typename T> T operator*(const vec<DIM,T>& lhs, const vec<DIM,T>& rhs) {
T ret = T();
for (size_t i=DIM; 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]);
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]);
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);
return ret;
}

template<size_t DIM,typename T> vec<DIM,T> operator-(const vec<DIM,T> &lhs) {
return lhs*T(-1);
}

typedef vec<3, float> Vec3f;

#endif //__GEOMETRY_H__

Binary file added out.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 58 additions & 0 deletions tinykaboom.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#define _USE_MATH_DEFINES
#include <cmath>
#include <algorithm>
#include <limits>
#include <iostream>
#include <fstream>
#include <vector>
#include "geometry.h"

const float sphere_radius = 1.5;

float signed_distance(const Vec3f &p) {
return p.norm() - sphere_radius;
}

bool sphere_trace(const Vec3f &orig, const Vec3f &dir, Vec3f &pos) {
pos = orig;
for (size_t i=0; i<128; i++) {
float d = signed_distance(pos);
if (d < 0) return true;
pos = pos + dir*std::max(d*0.1f, .01f);
}
return false;
}

int main() {
const int width = 640;
const int height = 480;
const float fov = M_PI/3.;
std::vector<Vec3f> framebuffer(width*height);

#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.));
Vec3f hit;
if (sphere_trace(Vec3f(0, 0, 3), Vec3f(dir_x, dir_y, dir_z).normalize(), hit)) { // the camera is placed to (0,0,3) and it looks along the -z axis
framebuffer[i+j*width] = Vec3f(1, 1, 1);
} else {
framebuffer[i+j*width] = Vec3f(0.2, 0.7, 0.8); // background color
}
}
}

std::ofstream ofs("./out.ppm", std::ios::binary); // save the framebuffer to file
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)(std::max(0, std::min(255, static_cast<int>(255*framebuffer[i][j]))));
}
}
ofs.close();

return 0;
}

0 comments on commit c45987e

Please sign in to comment.