Image accumulaiton in path tracer example

I’m having problems saving images from the pathTracer example that match the quality of the interactive window display after a few seconds. I’d like to save images after going through the render loop for like 5 seconds but without an interactive window. Just launching multiple sub frames and saving afterwards didn’t do the trick. Is there some kind of accumulation inside of the gl display? I guess this is an easy one, but i’d appreciate any help on where to look for this!

1 Like

Have you read through the optixPathTracer.cpp code?

That offers a command line option --file | -f <filename> File for image output and that sets the std::string outfile variable which is then used inside the main loop to select between interactive progressive accumulation with display to the window and single shot rendering with saving of the image data to the specified image.

So if you want that saved image to be progressively refined the same way as the interactive display, you would need to replace the single launchSubframe() with a similar loop used inside the interactive display which updates the launch params with the proper subframe_index (untested code):

            handleCameraUpdate( state.params );
            handleResize( output_buffer, state.params );
            // launchSubframe( output_buffer, state ); // OLD CODE
            for (unsigned int subframe = 0; subframe < NUM_SUBFRAMES; ++subframe)
                    state.params.subframe_index = subframe; // This subframe_index increment was probably missing in your experiment.
                    updateState( output_buffer, state.params );
                    launchSubframe( output_buffer, state );

            sutil::ImageBuffer buffer;
           = output_buffer.getHostPointer();
            buffer.width        = output_buffer.width();
            buffer.height       = output_buffer.height();
            buffer.pixel_format = sutil::BufferImageFormat::UNSIGNED_BYTE4;

            sutil::saveImage( outfile.c_str(), buffer, false );

Background Information:

The accumulation happens only inside the ray generation program.
Inside the extern void __raygen__rg() this line does the accumulation:
accum_color = lerp( accum_color_prev, accum_color, a );
and the two lines after that store the result into the float4 accum_buffer and as uchar4 into the frame_buffer:

params.accum_buffer[ image_index ] = make_float4( accum_color, 1.0f);
params.frame_buffer[ image_index ] = make_color ( accum_color );

Now if you search the host code for these two buffers, you see that the float4 accum_buffer is a device buffer allocated with cudaMalloc() inside void initLaunchParams( PathTracerState& state ) and on each resize of the window in handleResize().

The uchar4 frame_buffer which is used for display, is wrapped by the sutil::CUDAOutputBuffer<uchar4>& output_buffer instead. to make that work with and without OpenGL interop.

The place where the uchar4 frame_buffer ( == output_buffer) is transferred into the OpenGL texture for display is inside the function displaySubframe() and there inside the gl_display.display() function.

Now if you look at what that does in sutil\GLDisplay.cpp, the glTexImage2D() calls in there are transferring the image data to the OpenGL texture image.
So you would need to work your way backwards from there to store the same image.

This whole example is written with interactive OpenGL display in mind.
If you want an offscreen process which does the same, you would need to replace basically the whole OpenGL part of that example application framework and only launch as many sub-frames as you like and and save the result into a image.


Thanks for the help! I actually forgot to augment the subframe_index in the params… I knew it had to be something stupid i forgot.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.