Skip to documentation
DocumentationAll documentsEnglish

LIBRT(3)

NAME

librt - library for raytracing a BRL-CAD geometry database

On this page

SYNOPSIS

#include "vmath.h"
#include "raytrace.h"

extern struct rt_functab OBJ[];
extern struct rt_g rt_g;

struct rt_i *rt_dirbuild(char * mged_file_name, char * buf, int len);
int rt_gettree(struct rt_i * rtip, char * object_name);
void rt_prep(struct rt_i * rtip);
int rt_shootray(struct application * ap);
void rt_prep_timer(void);
doublert_read_timer(char *buf, int len);
void rt_pr_partitions(struct rt_i *rtip struct partition *phead, char *title);
void rt_pr_seg(struct seg *segp);

segp;

struct soltab *rt_find_solid(void);

DESCRIPTION

rt_dirbuild opens mged_file_name and builds a directory for quick lookup of objects. rt_dirbuild returns a pointer to a struct rt_i on success (often called ``rtip’'), or RTI_NULL on failure (such as being unable to open the named database). This pointer must be saved, as it is a required parameter to `rt_gettree(). The user-supplied buffer buf is filled with up to len characters of information from the first title record in the database. If it is desired for "air" objects to be reported as "hits" during ray-tracing, then the useair member of the struct rt_i must be set before the first call to rt_gettree().

All objects (groups and regions) which are to be included in the description to be raytraced must be preprocessed with rt_gettree(), which returns -1 for failure and 0 for success. This function can be called as many times as required. Be certain to pass the struct rt_i pointer from rt_dirbuild each time.

After the last rt_gettree() call, rt_prep() can be called to complete the preparation of internal data structures. If rt_prep() is not explicitly called, it will be indirectly invoked by the first use of rt_shootray().

To fire a ray at the model, an application structure must be prepared and its address passed to rt_shootray(). Note that it is mandatory that you provide values for a_ray.r_pt (the starting point of the ray to be fired), a_ray.r_dir (a unit-length direction vector), a_hit (address of user-supplied hit routine), a_miss (address of user-supplied miss routine), a_overlap (address of user-supplied overlap routine; may be null), a_rt_i (struct rt_i pointer, from rt_dirbuild), a_onehit (flag controlling stop after first hit), a_level (recursion level, just for diagnostic printing), and a_resource (address of resource structure; may be null).

To obtain a report of CPU usage for a portion or portions of your program, frame the statements with calls to rt_prep_timer() and rt_read_timer(). Each call to rt_prep_timer() resets the timing process, after which rt_read_timer() can be called to get a double which is the elapsed CPU time in seconds since rt_prep_timer() was last called. In addition, up to len bytes of system-specific detailing of resource consumption is placed in the user-supplied buffer buf.

bu_bomb can be used to exit your program with msg printed on the standard error output.

This page describes the core ray-tracing entry points at an overview level. The authoritative and complete API — including all data structures and function signatures — is defined in raytrace.h and the headers in the rt/ subdirectory, and is documented in the Doxygen-generated reference for the LIBRT module.

WARNING

Librt is designed to run in parallel on some multiprocessor machines. On some such machines system calls must be semaphore protected.

Dynamic memory handling in applications using librt should use the functions provided by libbu instead of the usual system runtime library routines. The libbu versions do not return to the caller unless they succeed. If they fail, they call bu_bomb with their last argument (str) as the parameter. The string parameter usually indicates the purpose of the memory being allocated.

EXIT CODE

All truly fatal errors detected by the library use bu_bomb to exit with a status of 12.

DEFINITION

RPP - Rectangular ParallelePiped. A region of space defined by minimum and maximum values in X, Y, and Z. RPPs are used by librt as bounding volumes for solids.

DISCUSSION

You should study the structures in raytrace.h, in particular, the application structure, the partition structure and its component structures to get an idea of what information is handed to/from rt_shootray(). rt_shootray() may be called recursively from your a_hit routine (good for doing bounced rays). If you only care about the first object hit along the path of the ray, set the a_onehit flag in the application structure before calling rt_shootray(). rt_shootray() returns the return value of the user-supplied hit or miss function that it called.

If the ray intersects the model, the a_hit routine is called with a pointer to the application structure and a pointer to a linked list of ray partitions (struct partition). Within each partition are seg (solid segment) and hit (intersection with evaluated region) structure pointers for the places where the ray enters and leaves this partition of space. pt_inhit.hit_dist is the parametric distance at which the ray enters the partition, and pt_outhit.hit_dist is the parametric distance at which the ray leaves. Note that while the hit structure contains hit_point and hit_norm elements, they are not computed by rt_shootray(). If these are needed, they can be filled in by using the RT_HIT_NORMAL macro; if surface curvature information is needed, it can be obtained by using the RT_CURVE macro after RT_HIT_NORMAL; if only the hit_point is needed, it can be filled in by using the VJOIN1 macro (see the following example).

If the ray contains any overlaps (partitions claimed by two or more regions) the a_overlap routine is called for each such partition with pointers to the application structure, the overlap partition, two regions, and the remaining partitions along the ray. If the a_overlap member is null, librt uses a default overlap handler. Additionally, librt provides the routine

If the ray does not intersect the model, the a_miss routine is called with a pointer to the application structure.

Helpful in generating a grid of ray origins, the bounding RPP of the model is computed by rt_gettree() and is stored in rtip→mdl_min and rtip→mdl_max.

EXAMPLE

A program can be loaded as follows:

$ cc -I/usr/brlcad/include main.c /usr/brlcad/lib/librt.a -l<system-specific> -lm

where <system-specific> indicates libraries required on a particular architecture. The table below indicates which system specific libraries are necessary on a particular architecture.

Architecture Librarie(s) Alliant FX/8 -lcvec -lcommon Alliant FX/2800 -lcommon SGI 4D -lmpc Cray(X/Y) -L/lib/multi -lu -lio Cray2 -lmt Encore Multi-Max -lpp

Here is a portion of a hypothetical program which uses the library:

#include <vmath.h>
#include <raytrace.h>
int
main(int argc, char argv[])
{
  static int do_if_hit(), do_if_miss(); /* Application routines */
  register int h, v;
  int grid_sz;
  struct application ap; /* Set up for rt_shootray() */
  struct rt_i *rtip;
  /* ... */

  /* Build the directory.	*/
  rtip = rt_dirbuild( argv[bu_optind++] );

  /* Load the desired portion of the model. */
  while (argv[bu_optind] != NULL)
    rt_gettree(rtip, argv[bu_optind++]);

  ap.a_hit = do_if_hit;     /* Routine for hit */
  ap.a_miss = do_if_missed; /* Routine for miss */
  ap.a_overlap = 0;
  ap.a_rt_i = rtip;
  ap.a_level = 0;
  ap.a_onehit = 0;          /* Return all objects along ray */
  ap.a_resource = 0;

  for (v = 0; v < grid_sz; ++v) /* For each scanline */
    for (h = 0; h < grid_sz; ++h) {
      /* Set up ray origin. */
      VMOVE( ap.a_ray.r_pt, get_grid(h, v));
      /* Compute ray direction. */
      VMOVE( ap.a_ray.r_dir, get_dir(h, v));
      /* Must be unit vector. */
      VUNITIZE(ap.a_ray.r_dir);
      (void)rt_shootray(&ap);
    }
   /* ... */
}

static int
do_if_hit(register struct application *ap,
          struct partition *PartHeadp)
{
  extern void put_component();
  struct curvature incurv;
  register struct partition *pp;

  for (pp = PartHeadp->pt_forw; pp != PartHeadp;
       pp = pp->pt_forw)  {

  /* Fill in all inhit info, but just the exit location for outhit. */
  RT_HIT_NORMAL(pp->pt_inhit->hit_normal, pp->pt_inhit,
                pp->pt_inseg->seg_stp, &ap->a_ray,
                pp->pt_inflip);
  RT_CURVE(&incurv, pp->pt_inhit, pp->pt_inseg->seg_stp);
  VJOIN1(pp->pt_outhit->hit_point, ap->a_ray.r_pt,
         pp->pt_outhit->hit_dist, ap->a_ray.r_dir);

  /* Do something based on information in partition structure
   *	such as output a shotline component data record.
   */
  put_component( pp->pt_inhit, &incurv, pp->pt_outhit );
  /* ... */
  }
  return 1; /* Report hit to main routine */
}

static int
do_if_missed(register struct application *ap)
{
  return 0; /* Report miss to main routine */
}

SEE ALSO

brlcad(1), mged(1), rt(1), libbu(3), libbn(3), libbg(3), libnmg(3), libbrep(3), libwdb(3).

DIAGNOSTICS

"rt_malloc: malloc failure", if librt is unable to allocate memory with malloc. `rt_ ???: read error'', if an error or EOF occurs while reading from the model database. "unexpected SIGFPE!" when a floating point error occurs. (The rootfinder traps SIGFPE, but SIGFPE elsewhere is unexpected.) "rt_shootray: zero length dir vector" when the a_ray.r_dir vector is not unit length. "rt_gettree called again after rt_prep!" when an attempt is made to add more sub-trees to the active model after calling `rt_prep() (or after firing the first ray). "rt_prep: re-invocation" when rt_prep() is called more than once. "rt_prep: no solids to prep" when there are no valid solids in the model.

The LIBRT_DEBUG environment variable may be set to the hexadecimal bit vector as described by the DEBUG_* flags listed in the raytrace.h header. Similarly, many LIBRT applications provide a "-x #" command-line option which will take precedence over the environment variable.

The RT_DEBUG_RTCMP flag (0x10000000) (set with LIBRT_DEBUG=10000000) sets up rtcmp capture, but recording starts disabled. Set LIBRT_RTCMP_FILE before enabling the flag, then call rt_rtcmp_capture_set_enabled(1) from the application or a debugger to record selected rays. Call rt_rtcmp_capture_set_enabled(0) to stop recording. Enabling returns -1 if the debug flag is unset or the output writer failed to initialize; disabling returns 0 even before setup. A ray must begin while recording is enabled, and leaving recording disabled when it finishes suppresses its record. The debug flag must be set before concurrent ray shooting; use the setter to change recording state while rays are running.

Captured hits append one high-precision rtcmp JSON record per ray with final partitions. Misses produce no record. librt never clears the output file; the caller must clear or rotate it before a new comparison as needed. Separate processes must not write to the same file concurrently. Pending records are flushed within two seconds under normal operation and during normal process shutdown; call rt_rtcmp_capture_flush() to wait for pending records when using a debugger. Disabling recording does not discard records already queued. A process terminated abnormally may lose pending records. rtcmp comparison files should use the same hit-only capture mode on both sides; its generation mode also includes misses. The output can be expanded to also include primitive segments if LIBRT_RTCMP_PRIMITIVES is set to 1 before capture is set up.

For example, run a single-threaded ray tracing application in a debugger and stop at rt_shootray for the suspect ray. Capture just that call, then compare it with a capture of the same ray from a reference build:

$ LIBRT_DEBUG=10000000 LIBRT_RTCMP_FILE=trial.json \
    gdb --args ./ray_application model.g
(gdb) break rt_shootray
(gdb) run
(gdb) call rt_rtcmp_capture_set_enabled(1)
(gdb) finish
(gdb) call rt_rtcmp_capture_set_enabled(0)
(gdb) call rt_rtcmp_capture_flush()
(gdb) quit
$ rtcmp -c reference.json trial.json

Continue to the suspect ray before enabling capture if the breakpoint first stops on another ray. Produce reference.json with the same ray and the same capture mode; set LIBRT_RTCMP_PRIMITIVES=1 for both runs when primitive segments are needed to locate a difference before Boolean evaluation.

The LIBRT_V4FLIP environment variable may be set to a true or false value to respectively force or disable endianness interpretation of v4 geometry database files. The default behavior is to automatically detect whether flipping the endian interpretation will help LIBRT read a binary-incompatible v4 geometry database file. Setting LIBRT_V4FLIP will override automatic detection.

BUGS

On a VAX, the rootfinder detects "hard" cases by taking a SIGFPE and retrying with a slower but more stable algorithm. This is unfortunate.

AUTHOR

BRL-CAD Team

This software is Copyright (c) 1986-2026 United States Government as represented by the U.S. Army Research Laboratory.

BUG REPORTS

Reports of bugs or problems should be submitted via electronic mail to devs@brlcad.org