Skip to content
NDT: N-Dimensional Tracer
Branch: master
Clone or download
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
aws Added a missing comma. May 24, 2019
cmake Updated build process to be compatible with EC2 clusters. May 10, 2019
objects Fixed problem with bounding point cloud locations. May 21, 2019
scenes Added a scene for visualizing Nelder-Mead. May 25, 2019
.dockerignore Can now build a docker image. Apr 30, 2019
.gitignore Can now build a docker image. Apr 30, 2019
.travis.yml Added mpich to packages to install. May 5, 2019
CMakeLists.txt Updated valgrind rule to use new command-line options. May 18, 2019
Dockerfile
LICENSE
Makefile.unix Updated valgrind rule to use new command-line options. May 18, 2019
README.md Fixed a typo. May 19, 2019
bounding.c Updated some disabled debugging code to use correct variables. May 23, 2019
bounding.h
camera.c Fixed a memory leak. Apr 15, 2019
camera.h Fixed some unused variable warnings. Apr 2, 2019
common.mk Updated build process to be compatible with EC2 clusters. May 10, 2019
image.c
image.h Added image_add function along with other changes to simplify MPI calls. May 5, 2019
kmeans.c Initial commit into git. Apr 1, 2019
kmeans.h Initial commit into git. Apr 1, 2019
map.c Initial commit into git. Apr 1, 2019
map.h Initial commit into git. Apr 1, 2019
matrix.c Initial commit into git. Apr 1, 2019
matrix.h Initial commit into git. Apr 1, 2019
ndt.c Changed buffer sizes for partial paths to be NAME_MAX lenght. May 18, 2019
ndt_config.h Updated build process to use cmake. Apr 29, 2019
ndt_config.h.in Updated build process to use cmake. Apr 29, 2019
nelder-mead.c Simplified the accept portion of the expand phase. May 25, 2019
nelder-mead.h Added nm_simplex_point function to expose contents of the simplex. May 23, 2019
object.c Added Nelder-Mead to minimize radius of bounding spheres. May 23, 2019
object.h Replaced explicit bounding spheres with point clouds that implicitly … May 20, 2019
scene.c Replaced explicit bounding spheres with point clouds that implicitly … May 20, 2019
scene.h Added scene_print to get a sense of scene structre. May 15, 2019
timing.c Initial commit into git. Apr 1, 2019
timing.h Initial commit into git. Apr 1, 2019
vectNd.c
vectNd.h Renamed vectNd_inline.c to vectNd_inline.h. Apr 29, 2019
vectNd_inline.h Renamed vectNd_inline.c to vectNd_inline.h. Apr 29, 2019

README.md

NDT: N-Dimensional Tracer

NDT is a hyper-dimensional ray-tracer. Just like any normal ray-tracer ndt produces images by tracing the path of light rays from an observer to objects and light sources. However unlike normal ray-tracers, all of the vectors used to represent light rays can have an arbitrary number of dimension. This allows for direct rendering of scenes that have more than just three spacial dimensions.

Getting Started

Dependancies

Packages for these dependancies should exist for most Linux distributions and are available via macports on macOS.

  • libjpeg and/or libpng
  • libyaml (optional)

In Debian Linux:

$ sudo apt-get install cmake libjpeg-dev libpng-dev libyaml-dev

In macOS using macports:

$ sudo port install cmake jpeg libpng libyaml

Linux or macOS

Build from source with cmake:

$ git clone https://github.com/doing-science-to-stuff/ndt.git
$ cd ndt
$ cmake .
$ make

Build from source without cmake:

$ cd ndt
$ make -f Makefile.unix

Note: If not all dependencies are met, manual editing of common.mk will be needed.

Render sample image

$ ./ndt -f 1

Defining Custom Scenes

A scene consists of a camera, a set of objects and a set of lights. There are two ways to create a scene, the C API or a YAML file.

C API

To create a custom scene using the C API, start by making a copy of empty.c in the scenes directory.

$ cd scenes
$ cp empty.c custom.c

Next, open custom.c (or whatever you called it) in a text editor or IDE. There are three functions defined in this file.


The first function scene_frames is optional and returns the number of frames to be rendered, if the scene describes multiple frames, (e.g., an animation).

int scene_frames(int dimensions, char *config);

Parameters:

  • dimensions - The number of dimensions for the current render.
  • config - A custom configuration string passed via the -u flag.

Returns:

  • Number of frames to render. This value can be overridden using the -f command-line option.

The second function scene_setup is required, and does all of the work of configuring a scene. Near the top of scene_setup there must a call to scene_init which provides a name for the scene as well as the number of dimensions that seen will contain. Change the name in the `scene_setup call from "empty" to "custom". This will cause all images created by the custom scene to be placed in a newly created "custom" subdirectory under the "images" directory.

int scene_setup(scene *scn, int dimensions, int frame, int frames, char *config);

The required function populates a scene structure with the camera, objects and lighting.

Parameters:

  • scn - The scene structure that will contain the scene.
  • dimensions - The number of dimensions for the current render.
  • frame - Current frame to be rendered (starting from zero).
  • frames - Total number of frames to be rendered.
  • config - A custom configuration string passed via the -u flag.

Returns:

  • Reserved

A third function scene_cleanup is optional, but provides means to cleanup any memory or other persistent resources that a scene might use to maintain state between frames.

int scene_cleanup();

The scene_cleanup function should free any additional persistent memory or other resources that the scene setup function may have allocated to maintain inter-frame state. This function will only be called once, after all frames have been rendered. If the scene doesn't allocate any persistent resources, this function can be omitted.

Returns:

  • Reserved

Vectors

All positions and directions are represented using a n-dimensions vector structure vectNd. Before a vectNd can be used, it first must be initialized with vectNd_alloc or vectNd_calloc (e.g., vectNd_alloc(&v, 5) allocates a 5-dimensional vector). and when no longer needed, should always be freed with vectNd_free.

The easiest way to set a vector is the vectNd_setStr method. vectNd_setStr takes a pointer to the vector and a string representation of the vector (e.g., vectNd_setStr(&v, "1,2,3,4"), sets v to <1,2,3,4>). Additionally vectNd_set can be used to modify individual elements of the vector, (e.g., vectNd_set(&v, 0, 7) sets the first element of v to 7).

Camera

Each scene must have a camera that defines perspective from which the scene will be viewed.

A camera must first be allocated and initialized:

camera_alloc(&scn->cam, dimensions);
camera_reset(&scn->cam);

Once the camera is initialized, it can be places into the scene using the camera_set_aim function. The camera_set_aim function is passed five parameters. This first is a pointer to the camera to be aimed. The second is a pointer to a vector from the origin to the point the scene will be viewed from. The third is a pointer to a vector from the origin to the point that will be centered in the rendered image. The fourth is an optional pointer to a vector (NULL if omitted), that gives a vector that should point toward the top of the rendered image. The fifth is a double that indicates a rotation (in radians) parallel to the image plane to be applied before the camera is aimed. In most cases, this should be zero.

vectNd_setStr(&viewPoint,"60,0,0,0");
vectNd_setStr(&viewTarget,"0,0,0,0");
vectNd_set(&up_vect,1,10);  /* 0,10,0,0... */
camera_set_aim(&scn->cam, &viewPoint, &viewTarget, &up_vect, 0);

Lights

In order for anything to be visible in a scene, light sources are needed to illuminate the objects. Each scene contains a set of light structures that provide illumination.

Make a call to scene_alloc_light to add a light to a scene. This function takes as parameters a pointer to the scene as well as a pointer to a light pointer (e.g., scene_alloc_light(scn,&lgt), where lgt is of type light\*).

Once a light has been added to the scene it needs to be configured. There are secveral types of lights that each have different configuration requirements.

The simplest type of light is ambient light. To configure an ambient light, set the type to LIGHT_AMBIENT, (e.g., lgt->type = LIGHT_AMBIENT). Then to configure the color/intensity of the ambient light, set the red, green, and blue fields to a value between 0.0 and 1.0.

light *lgt=NULL;
scene_alloc_light(scn,&lgt);
lgt->type = LIGHT_AMBIENT;
lgt->red = 0.5;
lgt->green = 0.5;
lgt->blue = 0.5;

Another, more complex light is a point light. To configure a point light, set the type to LIGHT_POINT, (e.g., lgt->type = LIGHT_POINT). Unlike ambient light, a point light has a position which is set by allocating and setting the pos field of the light structure. Then the red, green, and blue fields give the intensity of the light in each color channel. Due to how light intensity falls off with distance, it is often necessary to set the intensity of position based lighting to values in the hundreds, thousands, or more, depending on the distance.

light *lgt=NULL;
scene_alloc_light(scn,&lgt);
lgt->type = LIGHT_POINT;
vectNd_calloc(&lgt->pos,dimensions);
vectNd_setStr(&lgt->pos,"0,40,0,-40");
lgt->red = 300;
lgt->green = 300;
lgt->blue = 300;

Additional types of lighting are available, but these two should be enough to get started.

Objects

Many types of object primitives are available in ndt and are identified by a type string. A new object is added to the scene by calling scene_alloc_object. The parameters for scene_alloc_object are a pointer to the scene,cw the number of dimensions, a pointer to a pointer to an object, and a string indicating the type of object being created.

Objects in ndt are defined as sets of positions, directions, sizes (doubles), flags (integers), and other objects.

Once an object is allocated, elements are added to the appropriate sets using a set of functions. Each such function takes as its first parameter a pointer to the object, and the value being added as a second parameter. Positions are added with the object_add_pos function, directions with object_add_dir, sizes with object_add_size, flags (integers) with object_add_flag, and objects with object_add_obj. When adding vectors or objects, a pointer is used, not the actual value.

For example, to add sphere to a 4-dimensional custom scene:

object *obj = NULL;
scene_alloc_object(scn, 4, &obj, "sphere");
vectNd center;
vectNd_calloc(&center, 4);
vectNd_setStr(&center, "0,5,0,0");  /* centered at <0,5,0,0> */
object_add_pos(obj, &center);
object_add_size(obj, 5.0);  /* radius of 5 */
/* set color */
obj->red = 0.8;
obj->green = 0.1;
obj->blue = 0.1;
/* set reflectivity */
obj->red_r = 0.2;
obj->green_r = 0.2;
obj->blue_r = 0.2;

Note: In general, the dimensions variable should be used whenever the number of dimensions is needed.

Not all types of objects require elements in each set. The number of elements required in each set can depend on the number of dimensions. Each object type provides a functions (params) that provides the number of each type of element needed to fully describe an object.

Rendering Custom Scene

Once custom.c has been modified, it needs to be compiled into a shared object which can be loaded by ndt at runtime. The make file in the scenes directory should do this automatically when make is run in either the scenes directory or the top level ndt directory.

$ cd ..
$ cmake .
$ make

To actually render a scene, ndt needs to be told, using the -s options, to load the shared object that contains the scene description. The -d option indicates that the scene should be rendered using 4-dimensions.

$ ./ndt -s scenes/custom.so -d 4

If the custom scene needs any additional configuration information passed into it, the -u option can be used.

$ ./ndt -s scenes/custom.so -u 'configuration string'

YAML

To create a custom scene using a YAML file, start by making a copy of empty.yaml in the scenes directory.

$ cd scenes
$ cp empty.yaml custom.yaml

Next, open custom.yaml (or whatever you called it) in a text editor.

It should look like this:

---
scene: empty
dimensions: 4
camera:
  viewPoint: [60, 0, 0, 0]
  viewTarget: [0, 0, 0, 0]
  up: [0, 10, 0, 0]
lights:
- type: LIGHT_AMBIENT
  color: {red: 0.5, green: 0.5, blue: 0.5}
- type: LIGHT_POINT
  color: {red: 300, green: 300, blue: 300}
  pos: [0, 40, 0, -40]
objects:
- type: hplane
  dimensions: 4
  material:
    color: {red: 0.8, green: 0.8, blue: 0.8}
    reflectivity: {red: 0.5, green: 0.5, blue: 0.5}
  positions:
  - [0, -20, 0, 0]
  directions:
  - [0, 1, 0, 0]

The second and third line specify the name of the scene as well as the number of dimensions in the scene. Change the scene name on the second line from "empty" to "custom". This will cause all images created by the custom scene to be placed in a newly created "custom" subdirectory under the "images" directory.

Vectors

All positions and directions are represented using a n-dimensions vectors. In YAML an n-dimensional vector is a sequence of double values, (e.g., [60, 0, 0, 0] is the 4-dimensional vector <60,0,0,0>).

Camera

Each scene must have a camera that defines perspective from which the scene will be viewed.

A camera is described in a map named camera.

camera:
  viewPoint: [60, 0, 0, 0]
  viewTarget: [0, 0, 0, 0]
  up: [0, 10, 0, 0]

Fields:

  • viewPoint - The point from which the scene will be viewed.
  • viewTarget - The point which should appear at at the center of the screen.
  • up - An optional vector which would point up in the final image.
  • rotation - An optional double which specified a rotation (in radians) applied to the camera.

Lights

In order for anything to be visible in a scene, light sources are needed to illuminate the objects. Each scene contains a set of light structures that provide illumination.

Lights are described in a sequence named lights where each entry is a map with multiple fields which depends on the type of the light.

lights:
- type: LIGHT_AMBIENT
  color: {red: 0.5, green: 0.5, blue: 0.5}
- type: LIGHT_POINT
  color: {red: 300, green: 300, blue: 300}
  pos: [0, 40, 0, -40]

This describes two lights. The first is ambient light that is applied evently to all objects. The color/intensity of the ambient light, set the red, green, and blue fields to a value between 0.0 and 1.0. The second is a point light source, which has a position and can cast shadows. Due to how light intensity falls off with distance, it is often necessary to set the intensity of position based lighting to values in the hundreds, thousands, or more, depending on the distance.

Objects

Many types of object primitives are available in ndt and are identified by a type string.

Objects are described in a sequence named objects, where each entry is a map with multiple fields which depends on the type of the object.

In the "empty" scene there is actually one object.

- type: hplane
  dimensions: 4
  material:
    color: {red: 0.8, green: 0.8, blue: 0.8}
    reflectivity: {red: 0.5, green: 0.5, blue: 0.5}
  positions:
  - [0, -20, 0, 0]
  directions:
  - [0, 1, 0, 0]

Fields:

  • type - Specifies the type of object.
  • dimensions - Number of dimensions for objects (should always match the dimensions in the scene).
  • materal - A map that provides color and other visual properties of the object.
  • positions - A sequence of vectors that give the location of the object (e.g. center of a sphere).
  • directions - A sequence of vectors that give non-location base directions (e.g., normal vectors for a surface).
  • sizes - A sequence of doubles that give magnitudes the objects might need (e.g., the radius of a sphere).
  • flags - A sequence of integers that provide any discrete values the objects needs.

To add a sphere to the custom scene, insert the following snippet into the objects section:

- type: sphere
  dimensions: 4
  material:
    color: {red: 0.8, green: 0.1, blue: 0.1}
    reflectivity: {red: 0.2, green: 0.2, blue: 0.2}
  positions:
  - [0, 5, 0, 0]
  sizes:
  - 5.0

Rendering Custom Scene

To render the custom scene, a special yaml scene, specified with -s options, is used and the yaml file is passed as a custom parameter, passed with the -u option. The -d option indicates that the scene should be rendered using 4-dimensions.

$ ./ndt -s scenes/yaml.so -u scenes/custom.yaml -d 4

Additional Documentation

You can’t perform that action at this time.