May 24, 2010

Simple CMake example

Here is a simple example of how to use CMake to automatically generate Makefile on Linux system.

Suppose $PREFIX is the top level directory of my project where all of my sources, object files and executable reside. The CMake way of maintaining a regular project is to split all the files into two distinct sets with each one represented by a directory.

Usually, we have $PREFIX/src and $PREFIX/bin, where src contains all the source files and bin contains all the binary files. Source files do not necessarily mean program source code, it could also contain other stuff, like a bump map or texture files if you are doing graphics, or audio files if you are doing multimedia. Most importantly, the CMake system configuration file, which is called CMakeLists.txt, is located under the src directory.

The bin directory is where all the automatically generated files are located during the compile and link process. On different platforms, this directory may contain quite different types of files.

In my example, my source code is just one simple file, called mpisort.cc and of course there is also the CMakeLists.txt file. So the src directory looks like this,

src/mpisort.cc
src/CMakeLists.txt

mpisort.cc is a program implementing parallel quick sort algorithm through MPI which is almost the de facto standard for parallel programming for distributed memory systems like large clusters. The exact implementation is not important here, two things are important, however. They are

(1) MPI requires special compile flags, which could be quite different on different platforms.
(2) MPI requires special link flags and corresponding libraries, which too could be very different for different platforms.

The way CMake works is that you tell CMake (through its own language) which library you use and what flags you use. One nice thing is that there are so many built-in macros in CMake that address those frequent jobs, so what I need to do here is just to write down those several lines in the CMakeLists.txt file:

1 cmake_minimum_required(VERSION 2.8)
2 find_package(MPI REQUIRED)
3 include_directories(${MPI_INCLUDE_PATH})
4 add_executable(mpisort mpisort.cc)
5 target_link_libraries(mpisort ${MPI_LIBRARIES})

The first line tells CMake the minimum possible version of CMake for this CMakeLists.txt to work properly. This is largely for backward compatibility.

The second like tells CMake to find a MPI library on the target system, this will be automatically addressed differently on different platforms accordingly. The REQUIRED flag causes CMake to blow out if it cannot find a working MPI library.

If CMake successfully locates the information for MPI, the MPI_INCLUDE_PATH and MPI_LIBRARIES macros will be defined to be the exact path where "mpi.h" is found and the necessary libraries against which the program needs to link.

The third line informs CMake to include in search path those additional paths represented by MPI_INCLUDE_PATH where "mpi.h" can be found.

The fourth line tells CMake the name for the executable and its associated source code. Please note CMake will automatically handle naming issues. For example, on Linux, the executable is named "mpisort" with proper file attribute correctly set. On Windows, this executable will be "mpisort.exe", the ".exe" is correctly resolved by CMake when I build the project on a Windows platform.

The fifth line lets CMake know which libraries to link when generating the executable.

And we are done in terms of CMake configuration. Now we need to let CMake generate a Makefile for us so that we can compile the program. Remember I said the bin directory contains all those automatically generated files during compile and link. So now let us switch to our $PREFIX/bin directory. And the way we use CMake is like this,

ccmake ../src/

ccmake is a curses interface for CMake on Linux. It takes a directory as argument, and looks for a CMakeLists.txt file under that directory to start with. It parses the file for configuration information and displays its interface then. In its interface, customized configuration is supported, since my sample program is so simple, its does not require any additional config. I then press 'C' to let cmake identify the necessary system configurations, like the C compiler's name, location, version and that of C++ compiler, etc. (I do not know why this is not done automatically on startup). I then press 'C' again to let cmake parase my user-defined configration (even if in my case there is nothing customized, I have to do this). Now cmake gathers all necessary information and is ready to generate a Makefile for us. I then press 'G' to let it output the Makefile. ccmake will automatically exits after generating the Makefile. So I come back to the command line again, now I can do make to compile and link my executable.

This might not be very straightforward for my toy program, however, it is quite nice for intermediate or large projects.

Moreover, the CMake way is portable, you can copy the src directory to Windows or Mac and basically follow the same steps to generate Visual Studio project/solution files and XCode project files respectively without any modification of the sources.

For more detailed information, please refer to http://www.cmake.org/

If you need my example, it is here.

Apr 15, 2010

photonmapper

Program Features
(0) Basic ray tracing, ambient, diffuse, specular, shadow, transparency.
(1) Reflection
(2) Refraction. My program is able to do refraction for continuous changing media without air/vacuum interfering in between. For example, a big ball contains a small ball and both of them are translucent and of different index of refraction.
(3) Geometry includes sphere, general shaped polygon (even including concave polygon) and plane.
(4) Objects include fully opaque, translucent, fully translucent, fully reflective and partially reflective.
(5) Super sampling, soft shadow.
(6) Recursive ray trace controlled by arbitrary user-defined level threshold and ray-traveled distance threshold.
(7) Texture map and bump map on sphere object, checkerboard pattern on infinite plane.
(8) Program runs very faster. A 1200 * 900 resolution rendering is done in 15 mins.
(9) Program is able to output both PPM P6 raw format and 24-bit BMP format.
(10) Use yacc/lex parser to parse POV configuration file.
(11) I wrote my own numerical library for vector and matrix computation, employing template meta-programming and expression template techniques as well as latest features from the incoming new C++ standard.
(12) Photon mapping
(13) Caustic effect
(14) Color Bleeding

Sample Image


Photon Map


Caustic Effect

grab the code here here.

Apr 1, 2010

program feature

I implement all required features, including an interactive 2dtree viewer, an interactive viewer to display all phases of the algorithm, from the original data points to the final signed distance field.

Marching cubes is implemented separately. I did not use the code provided on your links, I implement it myself. I also implement a viewer to display the geometry generated by marching and that one is also fully interactive. I did not come up with GUI system, however, my programs are very easy to use and intuitive, using keyboard to interact and mouse to navigate.

The program runs very fast for the mechpart dataset, finished within only seconds. I use a trick that, in the Euclidean graph, if two nodes are not close enough, there is not need to generate a connection for them since the corresponding edge will not be in the MST anyway. This is Jon's observation but I do contribute by discussing with him. The program runs about 20s without the trick and less than 1 second with it.

assignment discription

Divide and conquer the problem into four phases as suggested:
1. Phase 1—tangent planes
Given an unorganized set of points in 3-space (point cloud), compute an estimate of a tangent plane at each point.

2. Phase 2—consistent normals
Given a set of tangent planes at each input point, Tp(xi), each consisting of:

* a neighbourhood of points defining the tangent plane's neighborhood, Nbhd(xi),
* the tangent plane origin, oi, and
* the tangent plane's orientation represented by its normal, ni,

find a consistent global orientation for each connected component of the input data.

3. Phase 3—signed distance function
Given a set of consistently oriented tangent planes at each input point, Tp(xi), each consisting of:

* a neighbourhood of points defining the tangent plane's neighborhood, Nbhd(xi),
* the tangent plane origin, oi, and
* the tangent plane's orientation represented by its normal, ni,

calculate the signed distance function f(p) at each point p situated at the vertex of a cube in a 3D cube lattice, where f(p) is defined as the signed distance between point p and its projection z onto Tp(xi): f(p) = (p - oi) ⋅ ni.

4. Phase 4—contour tracing (marching cubes)

Given the signed distance function f(p) at each point p situated at the vertex of a cube in a 3D cube lattice, where f(p) is defined as the signed distance between point p and its projection z onto Tp(xi): f(p) = (p - oi) . ni, extract the isosurface from the signed distance function (field data). This is accomplished via the marching cubes algorithm. The resulting simplical surface contains triangles oriented at the surface of the point-sampled object.

surface reconstruction


original data points


tangent plane centroids/origins


tangent plane normals (adjusted)


MST of Euclidean distance graph


Enriched Riemannian graph


MST of Riemannian graph


grid points and their associated tangent planes


signed distance field


2dtree viewer


marching cubes shading

grab the code here here.

Feb 18, 2010

A way to build gcc

The following method comes from the Linux system administrator of our department. The credit should go to him.

It took me a while to get this figured out. Things have changed a good bit since I've last
compiled gcc. I got this to work on a CentOS x86_64 system:

# set this to your desired prefix
PREFIX=/local/duckwos/foobar

# extract sources
tar jxf gmp-4.3.1.tar.bz2
tar jxf mpfr-2.4.1.tar.bz2
tar jxf gcc-4.4.2.tar.bz2

# build 32-bit gmp
cd gmp-4.3.1
./configure --prefix=$PREFIX --enable-cxx ABI=32
make -j2
make -j2 check
make install
make distclean

# build 32-bit mpfr
cd ../mpfr-2.4.1
./configure --prefix=$PREFIX --with-gmp=$PREFIX
make -j2
make -j2 check
make install
make distclean

# build 64-bit gmp
cd ../gmp-4.3.1
mv $PREFIX/include/gmp.h $PREFIX/include/gmp-i386.h
./configure --prefix=$PREFIX --libdir=$PREFIX/lib64 --enable-cxx ABI=64
make -j2
make -j2 check
make install

# build 64-bit mpfr
cd ../mpfr-2.4.1
./configure --prefix=$PREFIX --libdir=$PREFIX/lib64 --with-gmp-include=$PREFIX/include --with-gmp-lib=$PREFIX/lib64
make -j2
make -j2 check
make install

# fix up gmp header files
mv $PREFIX/include/gmp.h $PREFIX/include/gmp-x86_64.h
cp /usr/include/gmp.h $PREFIX/include/gmp.h

# build gcc
cd ../gcc-4.4.2
mkdir build
cd build
export LDFLAGS="-L$PREFIX/lib64 -Xlinker -R$PREFIX/lib64"
export LD_OPTIONS="$LDFLAGS"
export LD_RUN_PATH=$PREFIX/lib64
../configure --prefix=$PREFIX --with-gmp-include=$PREFIX/include --with-gmp-lib=$PREFIX/lib64 --with-mpfr-include=$PREFIX/include --with-mpfr-lib=$PREFIX/lib64 --enable-shared --enable-threads=posix --enable-languages=c,c++
make -j2
make install

# tell linker to specify rpath
$PREFIX/bin/gcc -dumpspecs > $PREFIX/lib/gcc/x86_64-unknown-linux-gnu/4.4.2/specs
vi $PREFIX/lib/gcc/x86_64-unknown-linux-gnu/4.4.2/specs

Find the line that contains only "*link:".
On the next line, append the text:
%{!m32:-L/local/duckwos/foobar/lib64 -R/local/duckwos/foobar/lib64} %{m32:-L/local/duckwos/foobar/lib -R/local/duckwos/foobar/lib}
Save the file.

Then you should have a working compiler.

Feb 17, 2010

Sample Images


Scene 1 Render Time 13,358,183 ms


Scene 2 Render time 129,024,982 ms


Scene 3 Render time 131,736,748 ms


Scene 4 Render time 106,477,129 ms


Scene 5 Render time 53,098,855 ms


Scene 7 Render time 22,924,387 ms
Texture map size 4096 * 2048
Bump map size 1024 * 1024


Scene 6 Render time counter overflows and offers negative values


Another Scene 6 with different object attributes.


Scene 6 with nice looking soft shadow

You can find the program tarball here.

Program Features

(0) Basic ray tracing, ambient, diffuse, specular, shadow, transparency.
(1) Reflection
(2) Refraction. My program is able to do refraction for continuous changing media without air/vacuum interfering in between. For example, a big ball contains a small ball and both of them are translucent and of different index of refraction.
(3) Geometry includes sphere, general shaped polygon (even including concave polygon) and plane.
(4) Objects include fully opaque, translucent, fully translucent, fully reflective and partially reflective.
(5) Super sampling, soft shadow.
(6) Recursive ray trace controlled by arbitrary user-defined level threshold and ray-traveled distance threshold.
(7) Texture map and bump map on sphere object, checkerboard pattern on infinite plane.
(8) Program runs faster than POV-Ray for the test scenes.
(9) Program is able to output both PPM P6 raw format and 24-bit BMP format.
(10) Use yacc/lex parser to parse POV configuration file.
(11) I wrote my own numerical library for vector and matrix computation, employing template meta-programming and expression template techniques as well as latest features from the incoming new C++ standard.

Assignment Description

Copied from Dr. Duchowski's webpage
Write a program to implement a ray tracer:
* Use either an interactive method of setting up the scene or create a simple scene "manually".
* Objects in the scene should include both spheres (and/or other quadrics), and polygonal objects (e.g., planes, cubes, the teapot).
* Images should include:
o fully opaque objects
o transluscent objects
o fully transparent objects (e.g., panes of glass)
o fully reflective objects (e.g., mirrors)
o partially reflective objects
* Shadow/Reflection/Transmission: demonstrate reflection, refraction, and shadows.
* Sampling: minimally, sample the scene at screen resolution, or optionally implement supersampling, adaptive supersampling, or distributed (stochastic) supersampling, and/or progressive sampling.
* Recursion: terminate recursion at an arbitrary (e.g., user-defined) level, or adaptively based on diminishing intensity contribution.
* Texture/bump maps: texture/bump maps should be demonstrated on planar surfaces (e.g., "walls" in the image) and spheres.