Which header files are required by a NuGraf program
How to initialize the library
How to define a new object
How to create instances of an object
How to hierarchically attach an instance to the 'world'
How to set the rendering options
How to create a light source
How to create a camera
How to select the output driver
How to begin the rendering process
To begin with, any application program which makes calls to the
NuGraf library must include the file 'ni.h'. In addition, the library function
must be called to initialize the system before any other library call is made.
#include <ni.h> /* The main NuGraf include file */
#include <stdio.h> /* Some standard includes */
#include <stdlib.h>
#include <string.h>
#include <math.h>
main()
{
char *home_directory = NULL;
char *current_working_directory = NULL;
/* Initialize the library and the directory locations */
Ni_Initialize(home_directory, current_working_directory);
}
The arguments to the command are usually NULL pointers.
Next, lets add a sphere object to the scene centered at the origin.
An object is always defined with the whose argument is the name for the object (its
'handle' name). The geometry data for the object is then specified with the command; in
this case we are defining the object as a sphere of radius 5 with the number of
subdivisions for the sphere in the U and V directions being 12. The definition of the
object is ended by giving the mandatory :
{
/* Sphere primitive parameters */
Nd_Float sph_radius = 0.5;
Nd_Int sph_u_subdiv = 12; /* Parametric u & v subdivisions */
Nd_Int sph_v_subdiv = 12;
Ni_Object_Define("sphere object", Nt_CMDEND); /* Begin a new object */
Ni_Primitive(Nt_SPHERE, /* Add a sphere primitive */
Nt_RADIUS, (Nd_Float *) &sph_radius, Nt_CMDSEP,
Nt_USUBDIV, (Nd_Int *) &sph_u_subdiv, Nt_CMDSEP,
Nt_VSUBDIV, (Nd_Int *) &sph_v_subdiv, Nt_CMDSEP,
Nt_CMDEND);
Ni_Object_End(Nt_CMDEND); /* Close the current object */
}
Only one primitive is allowed per object, although some primitives
accept unlimited numbers of elements, such as the polygon primitives.
As described in the tutorial of , objects cannot be rendered
directly. Rather, one or more instances of the object must be created and placed
into the scene. Instances are virtual copies of the object data that can be moved about
and transformed in the scene. Instances created from the same object share one single copy
of the primitive data, which greatly minimizes memory usage.
An instance is created from an object definition by using the
command. One or more instances of the object can be created. The name of the instance can
be the same as the object name but in general this may lead to confusion.
{
/* These statements create instances of the geometry and */
/* hierarchically attach the instances together. */
Ni_Add_Instance(Nt_INSTANCE, "sphere inst", Nt_OBJECT, "sphere object", Nt_CMDEND);
}
Next, the instance(s) must be hierarchically attached together - in
other words, the instances must be linked or 'glued' to other instances or to the 'world'
itself. For now we will just link the instance to the 'world'. The 'world' instance holds
all instances (directly or indirectly) which will be visible in the final rendering:
We now have the geometry of the scene defined and placed into the
'world'. Next, we turn to the specification of the rendering parameters.
The first thing we should do is specify some basic rendering
parameters. All runtime rendering options are specified with the command. In this example
we will use smooth (Phong) shading which will perform one shading calculation per pixel,
and use the high-quality Z-scanline renderer:
{
/* Set up the runtime options */
Ni_Option(
Nt_SHADING, Nt_SMOOTH, Nt_CMDSEP,
Nt_RENDERLEVEL, Nt_ZSCANLINE, Nt_CMDSEP,
Nt_CMDEND);
}
If we were to render the scene right now it work look very dark
since we have not yet defined any light sources. Point, directional or spot light sources
can be added to a scene with the command. In this example we will add a point
(omnidirectional) light source located at location (10, 10, 10) in world-space
coordinates:
{
/* Location of the 'point' line source */
Nd_Vector light1_shinefrom = { 10.0, 10.0, 10.0 };
/* Add one point light source to the scene */
Ni_Light("light1",
Nt_MODEL, Nt_POINT, Nt_CMDSEP,
Nt_SHINEFROM, light1_shinefrom, Nt_CMDSEP,
Nt_CMDEND);
}
Since 3D rendering is akin to taking a picture of a scene with a
real camera, we have to define and orient a virtual camera in order to view our scene. We
could use the "default'' camera defined by the renderer by in our case we will define
a new camera called "camera#1'' using the command. The camera will be situated at
location (0, 0, 2) in world-space (along the Z axis) and it will be oriented towards the
origin. Note that we have also specified the Nt_ACTIVE option to make this new
camera active (the "default'' camera is active at start-up).
{
/* Camera variables */
Nd_Vector lookat = { 0.0, 0.0, 0.0 };
Nd_Vector lookfrom = { 0.0, 0.0, 2.0 };
/* Create a custom camera looking from the positive Z axis */
/* towards the origin. */
Ni_Camera("camera#1",
Nt_ACTIVE, Nt_CMDSEP, /* Make it the active camera */
Nt_LOOKFROM, lookfrom, Nt_CMDSEP,
Nt_LOOKAT, lookat, Nt_CMDSEP,
Nt_CMDEND);
}
Before we render the final image we have to specify an output driver
for the renderer. The output driver accepts the raw scanline data computed by the renderer
and sends it to an appropriate device. In this case we will use the internal TIFF file
output driver which will be referenced by the handle name "driver#1''. The final
rendered image will be saved to the TIFF file "example.tif'' which can subsequently
be read into other application programs.