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:
- imageBGRArray -
User-supplied buffer for images to be returned when requested.
Returned images use 3 bytes per pixel with the colors in BGR
order and the pixels arranged in row major order. The size in
bytes of the buffer must be at least 3*width*height of the image.
- viewingMode - Controls
which image is returned in the
imageBGRArray. Can be the normal reconstructed image or
any of several intermediate or visualization images. See code for
the list of defined values.
- filterFlags - A boolean
mask of bits that allows you to enable/disable some of the
filters that are normally used in reconstructing render cache
images. See code for defined values (which can be boolean "or"ed
together).
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)