Using the Render Cache with other Renderers

The render cache has a simple interface making it easy to adapt other renderers (e.g., your own code or your favorite ray tracer) to use the render cache.  Note the license allows for non-commercial research use only.  You may not redistribute, sell, or otherwise use the render cache software for commercial purposes.  If you would like a version under a different license (e.g., to include in a commercial package), please contact me.  You can also get the C++ library source code under the GNU Public license if you prefer.

To use the render cache with your own renderer, you should first download the DLL and Java demo source code from this page.  The render cache code is precompiled into a DLL, but source code is provided for the other components.  I strongly reccommend that you study the Java demo code to see how to use the render cache.  I provide both C and Java bindings, with the same functionality.  The functions are listed below and available in the rendercachejava.RenderCache.java and  RenderCacheCBind.h files.

Version

rcGetVersionNumber()
Get render cache dll version number.  Major version in upper 16 bits.  Minor version in lower 16 bits.

Creating and Destroying

 rcInstance*   rcCreate(int width, int height, bool flipVertically)
Create and return a new instance of the render cache.  Will generate images with the specified width and height (in pixels) and optionally flip the images vertically, if desired.

rcDestroy(rcInstance *rcache)
Destroys a render cache instance, free all the memory used for its internal data structures.

Frame Update Routines

Some parameter notes:
int  rcUpdatePointCache(rcInstance *rcache, bool agePoints)
Integrate any new results (from rcReturnRayResults() method) into the current point cloud, age the existing points, and apply any aging penalties.  You should call this method once per frame.  The agePoints parameter lets you disable point aging; this is useful if you want to freeze the point cloud (force it to be static), since points are discarded once they reach a certain maximum age.

rcSetCamera(rcInstance *rcache,  float originX, float originY, float originZ
float viewdirX, float viewdirY, float viewdirZ
float updirX, float updirY, float updirZ
float screenWidth, float screenHeight, float screenDistance)
This routine sets the camera parameters to be used when next projecting the point cloud onto the image plane.  This is a pinhole perspective camera defined by an origin, a viewing direction, an up direction, and a virtual screen which controls the size of the viewing frustrum.  The viewing and up directions are usually normalized (unit vectors) but this is not required as they will be normalized internally.  The frustrum is defined by the camera's origin and a rectangle which is screenDistance units from the origin in the viewing direction whose size is defined by screenWidth and screenHeight (these lengths are in world units, not pixels).

int  rcPredictOccupancyAndRequest(rcInstance *rcache,  int viewingMode, char *imageBGRArray, int maxRequests)
Will project the current point cloud according to the current camera and then generate ray request for image regions without points.  The actual number of requests generated is returned, and will be between 0 and maxRequests, depending on the presence of gaps in the projected data.  Requests are then available for retrivieval through the rcGetRayQueries() method.  Typically you first set the camera to a position predicted several frames ahead and then use this method to generate requests for missing data so that it can be computed before the regions without data become visible

rcProjectFilterAndRequest(rcInstance *rcache, short filterFlags, int viewingMode, char *imageBGRArray, int maxRequests)
Will project the current point cloud according to the current camera, filter the results depending on the enabled filters, and produce an output image depending on the current viewing mode.  It will also generate requests for rays (pixels) to be shaded depending on the density and ages of the points.  The number of requests generated will be very close to maxRequests, but may vary slightly due to the error-diffusion-dither process.  Requests then are available for retrieval using the rcGetRayQueries() method.

State Change Commands

rcResetPointsAndImage(rcInstance *rcache)
Remove all current points from the point cloud and reset the image to black.  Useful for example, if you have just loaded a new scene and the old data is no longer relevant.

rcChangeToneMapping(rcInstance *rcache, float whitePoint, float gamma)
Change the tone mapping for all points in the cache.  Render cache stores both tone mapped and raw (rgbe floating point format) colors for all points.  This allows you to change the tone mapping quickly without having to replace all the points.  The tone mapping used is a simple scaling plus gamma correction type.  Each color channel is divided by the white point, raised to the power gamma, and then converted to a 8bit value.

Retrieving Ray Requests and Returning Shaded Points

All of the above methods are not reentrant and should only be called from a single thread (ie the display thread).  The methods below are totally thread-safe and may safely be called from any thread at any time (as long as the render cache instance is not destroyed). 

int  rcGetRayQueries(rcInstance *rcache, int maxQueries, rcQuery *queryArray)
Get a set of rays (queries) that the render cache has requested for shading.  These requests are generated by the rcPredictOccupancyAndRequest() and rcProjectFilterAndRequest() methods.  Each request contains an origin and direction for an eye ray, and a reference id-number to be returned with the results.  The renderer should trace the ray to find its intersection with the scene and shade the resulting point.  This information is then passed back to the render cache using the rcReturnRayResults() method.  The queryArray is a user-supplied buffer that must be large enough to hold at least maxQueries queries.  The return value is the actual number of queries copied into the supplied buffer.  May be zero is there are no queries currently available.

rcReturnRayResults(rcInstance *rcache, int frameNumber, int numResults, rcResult *resultArray)
Use this method to return a set of shaded points to the render cache.  Results will not actually be integrated into the point cloud until the next call to the rcUpdatePointCache() method.  In most cases, these should be the result of computing rays retrieved using the rcGetRayQueries() method.  The rcResult record contains the location of the point, its color (in rgbe floating point format), the reference id-number from the rcQuery, and an object id.  (Object id is to provide improved support for moving objects, but this functionality is not  currently available through the public interface).  The frameNumber should be sequential and incremented once per call to the rcProjectFilterAndRequest() method (used for special moving object support which is not yet publicly available).

Typical Usage

The display thread code would typically look something like:

rcache = rcCreate(width,height,false);
framenumber = 0;
viewingMode = /*DefaultViewingMode*/;
filterFlags = /*DefaultFilterFlags*/;
imageBGRArray = new byte[3*width*height];
while (!done) {
maxRequests = /*estimated number of results that can be shaded per frame*/;
rcUpdatePointCache(rcache,true);
if (usingPredictiveSampling) {
rcSetCamera(rcache,/*predicted camera parameters*/);
maxRequests -= rcPredictOccupancyAndRequest(rcache,viewingMode,imageBGRArray,maxRequests);
}
rcSetCamera(rcache,/*current camera parameters*/);
rcProjectFilterAndRequest(rcache,filterFlags,viewingMode,imageBGRArray,maxRequests);
/*display image from imageBGRArray*/
frameNumber += 1;
}
rcDestroy(rcache);

And the typical rendering thread code would typically look something like:

queryBuf = new rcQuery[bufsize];
resultBuf = new rcResult[bufsize];
while (!done) {
num = rcGetRayQueries(rcache,bufsize,queryBuf);
if (num == 0) {
sleep(1ms);  //if no queries available, wait a bit before asking again to avoid burning cycles unnecessarily
continue;
}
for(int i=0; i<num; i++) {
/*Get ray from queryBuf[i] and intersect it with the scene*/
/*Shade the resulting point and store the results in resultBuf[i]*/
}
rcReturnRayResults(rcache,frameNumber,num,resultBuf);
}


Page prepared by Bruce Walter, (email: bjw at graphics.cornell.edu)