Beast provides access to the renderings it creates through data structures called framebuffers. For each render pass that you add to a render target in your job, one or more framebuffers are created to hold the output. After the rendering job has completed, you use the Beast API to retrieve these framebuffers and read back the rendered data they contain.
A framebuffer is a data structure that records a set of data for each pixel in an image texture with a given width and height. Once you have retrieved a handle on a framebuffer as described under Retrieving the Rendered Output below, you can determine the width and height of the framebuffer by calling ILBGetResolution().
For each pixel, the framebuffer records a number of output values, called channels. The number, type and significance of these channels is determined by the type of render pass whose data the framebuffer was created to handle. For example, when you carry out a full shading pass, each pixel in the framebuffer records five channels: the RGBA values of that pixel, and the Z-channel value (depth from the camera).
You can determine how many channels a framebuffer contains by calling ILBGetChannelCount(), and you can retrieve a string name that identifies each channel by calling ILBGetChannelName().
By default, all render passes produce output values with high dynamic range (HDR). The value of each output channel is expressed using a floating-point number. If you need low-dynamic-range values expressed as a value in the range 0-255, you have the following options:
The way you retrieve the framebuffer that contains your rendering results depends on the type of render target the framebuffer handles.
Camera targets and texture targets always result in a single framebuffer for each rendering pass that you assign to the target.
You can retrieve this framebuffer through a single call to ILBGetFramebuffer(). In your call, you identify the render target and render pass whose framebuffer you want to retrieve. Since these types of targets always produce a single framebuffer, you should always use the index value 0.
ILBFramebufferHandle frameBuffer; ILBGetFramebuffer(target, pass, 0, &frameBuffer);
Atlased texture targets may result in more than one framebuffer being created for each rendering pass that you assign to the target, since they pack the lightmaps for multiple mesh instances into each output texture.
You can retrieve each framebuffer through individual calls to ILBGetFramebuffer(). In your calls, you identify the render target and render pass whose framebuffer you want to retrieve, and the index of the framebuffer you want to retrieve from the list of framebuffers generated for that target and pass.
int count; ILBGetFramebufferCount(target, &count); for (int i_buffer = 0; i_buffer < count; i_buffer++ ) { ILBFramebufferHandle frameBuffer; ILBGetFramebuffer(target, pass, i_buffer, &frameBuffer); ... // read and handle data }
Vertex targets and point cloud targets produce baked data that doesn't suit a rectangular framebuffer with a width and height. Instead, the data for each vertex or point is stored sequentially in a special kind of framebuffer called a vertex buffer, which always has a height of 1, and a width equal to the number of vertices or points baked. A separate vertexbuffer is created for each target entity that you set for the target (each mesh instance or each point cloud that you asked the target to bake).
To get the vertexbuffers, you make multiple calls to ILBGetVertexbuffer(). In each call, you identify the render target, render pass, and target entity whose vertexbuffer you want to retrieve. The vertex data is stored in the framebuffer handle that you provide.
ILBFramebufferHandle vertexBuffer; ILBGetVertexbuffer(target, pass, entity, &vertexBuffer);
Once you have acquired the framebuffer that contains the vertex data, you read the vertex data from it as you do for regular framebuffers, using the ILBReadRegionHDR() function, as described under Retrieving the Rendered Output below. Keep in mind that the height will always be 1, and that ILBReadRegionLDR() is not supported for vertexbuffers.
While a live eRnsT job is running, Beast periodically provides you with framebuffers that contain updated renderings for the targets being handled by that job. For details on how to retrieve the framebuffers generated during a live eRnsT session, see Monitoring Jobs and Retrieving Updates.
After the live eRnsT job is finished, you can retrieve the last set of rendered data using the functions listed in the sections above.
You read pixel data from a framebuffer by calling either of the following functions:
When you call the ILBReadRegionHDR() or ILBReadRegionLDR() function, you specify which channels you want to retrieve by providing an element from the ILBChannelSelection enumeration. For each pixel in the region you specify, all the values for all channels you request are written sequentially to an array that you provide. You must ensure that the size of this array is at least equal to the number of pixels in the region you have requested, multiplied by the number of channels you request.
Pixels are read from left to right, starting at the bottom left corner of the region you specified, and progressing upward line by line. In other words, the bottom horizontal line in the region is read from left to right; then the next line up starting from the left again; etc.
For example, the following code retrieves all data from all channels for all pixels:
int width, height; ILBGetResolution(frameBuffer, &width, &height); int channels; ILBGetChannelCount(frameBuffer, &channels); buffersize = width * height * channels; float buffer[buffersize]; ILBReadRegionHDR(frameBuffer, 0, 0, width, height, ILB_CS_ALL, &buffer[0]);
API functions related to framebuffers are declared in the beastframebuffer.h file.