Now that I have classes to handle floating-point values, I need to add support for 3D vectors and find a way to implement the raytracing engine…which is far from easy!
3D Vectors
I developed some simple classes to handle 3D vectors, and added some operators to allow adding, multiplying,… them to be able to perform raytracing. The class is easy to use. If you want to use a (0.1, 1.2, 3.4) vector, simply write:
typedef Vec3D< float_<0,1>, float_<1,2>, float_<3,4> >::type vector1;
I then implemented classes to handle Rays, Sphere, etc. I recommend downloading the source code in Part 3 if you want to explore everything.
Raytracing Algorithm
I searched over the internet and found a simple raytracing algorithm that I decided to convert to my own classes. I did that instead of using code I wrote a while ago because it was far too complex for what I wanted to achieve: simple intersections, not texturing and all this stuff.
Holding pixel values in a vector
My first idea of how to implement a raytracer with meta-programming was to use a mpl::vector and fill it with the values for each pixel of the image, by using something like mpl::fold. I implemented a simple version of that solution and then added some run-time code to fill the image based on the values stored inside the vector, through the use of mpl::foreach.
I soon realized that the limitations on the size of vectors would lead to some serious problems, so I had to figure out another solution.
ImageSequence class
I thought that instead of using the existing mpl::vector class (with its limitations) and then iterate on this vector, why not developing my own sequence class and iterate directly on it AND do the raytracing computation here, during the iteration? After several tests, it turned out it was feasible so I developed my own image sequence class.
In the end, it worked well with small images (eg. 16×16), but the compiler failed to generate much larger sequences. I finally used the following process: the main ImageSequence class is actually tiling the image into 16×16 tiles, and is iterating on the tiles. In turn, each tile sequence iterates on all the pixels contained in the tile. So, in the end, to generate run-time code to save the computed image to disk, there are two mpl::for_each loops, one to iterate on the tiles, and the second one (embedded into the first) to iterate on the pixels.
View CodeCPP | |
struct imagesequence_tag; template< typename PosX, typename PosY, int start_x, int tile_size_x > struct Pixel { BOOST_STATIC_CONSTANT(int, x = PosX::value); BOOST_STATIC_CONSTANT(int, y = PosY::value); typedef Pixel< typename PosX, typename PosY, start_x, tile_size_x > type; typedef PosX X; typedef PosY Y; typedef Pixel< mpl::int_< (start_x + ((X::value-start_x+1)%tile_size_x)) >, mpl::int_< (Y::value + ((X::value-start_x+1)/tile_size_x)) >, start_x, tile_size_x > next; // actual computation of the ray is done here... typedef HitSphere< Ray< mpb::Vec3D< mpb::float_<PosX::value, 0>, mpb::float_<PosY::value, 0>, mpb::float_<-50,0> >, mpb::Vec3D< mpb::float_<0,0>, mpb::float_<0,0>, mpb::float_<1,0> > >, Sphere< mpb::Vec3D< mpb::float_<32,0>, mpb::float_<24,0>, mpb::float_<0,0> >, mpb::float_<6, 0>, Color< mpb::float_<1,0>, mpb::float_<1,0>, mpb::float_<0,0> >, mpb::float_<0, 5> >, mpb::float_<100, 0> > hit; }; template< int start_x, int start_y, int tile_size_x, int tile_size_y, int image_size_x > struct ImageSequence_tile { BOOST_STATIC_CONSTANT(int, x = start_x); BOOST_STATIC_CONSTANT(int, y = start_y); BOOST_STATIC_CONSTANT(int, tx = tile_size_x); BOOST_STATIC_CONSTANT(int, ty = tile_size_y); typedef imagesequence_tag tag; typedef ImageSequence_tile type; typedef Pixel< mpl::int_<start_x>, mpl::int_<start_y>, start_x, tile_size_x > begin; typedef Pixel< mpl::int_<start_x>, mpl::int_<start_y + tile_size_y>, start_x, tile_size_x > end; typedef ImageSequence_tile< ((start_x+tile_size_x)%image_size_x), (start_y + (tile_size_y*((start_x+tile_size_x)/image_size_x))), tile_size_x, tile_size_y, image_size_x > next; }; template< int SIZE_X, int SIZE_Y > struct ImageSequence { BOOST_STATIC_CONSTANT(int, size_x = SIZE_X); BOOST_STATIC_CONSTANT(int, size_y = SIZE_Y); typedef ImageSequence type; typedef ImageSequence_tile< 0, 0, 16, 16, SIZE_X > begin; typedef ImageSequence_tile< 0, size_y, 16, 16, SIZE_X > end; }; | |
More on next post…

