May 21, 2013 at 4:08 PM
Edited May 21, 2013 at 4:10 PM
My name is Vladeta Stojanovic and I work as a research assistant in visualisation and modelling at the University of Abertay Dundee. I'm using Optix.Net to create a real-time tool for approximating passive solar gain for arbitrary house shapes (generated using
a genetic algorithm). The approximation of the passive solar gain is computed using ray tracing methods facilitated by Optix.Net. I decided to use Optix.Net because it supports C#. Overall, I think Kyle did a great job by porting Optix to the .Net platform.
Anyways, over the past week I had a real headache trying to figure out how to compute data on the GPU and stream it back to the CPU. There seems to be very little practical documentation for Optix, let alone Optix.Net. Thus I would like outline the steps I
followed for calcuting numerical data on the GPU (using Optix and CUDA C), and streaming it back to the CPU via a simple buffer streaming operation. Overall, the entire process is very straightforward, but I had to hack, debug and guess my way to the solution.
Thus I'm writing this short tutorial post so other don't have to go through all the bumps along the way to learning and using Optix.Net. Sharing knowledge is power, after all.
So, in this example, in order to compute a floating point value on the GPU and stream it back to the CPU, the following steps should be taken:
1) Create a Optix buffer:
BufferDesc desc = new BufferDesc()
Width = (uint)Width,
Height = (uint)Height,
Format = Format.Float,
Type = BufferType.InputOutput //could just be Output
ResultsBuffer = new OptixDotNet.Buffer(Context, desc);
2) Create a mirror buffer for the Optix CUDA kernel in the desired .cu shader:
rtBuffer<float, 2> gainResults;
3) Compute the results you want and store them in the buffer via the CUDA kernel in the .cu shader:
RT_PROGRAM void envmap_miss()
prd_radiance.result = CalculateSkyColor();
gainResults[launch_index] = 66776.2133f; //test result
Notice that I'm using the RT_PROGRAM specific to the event of the rays not intersecting any geometry. Since the scene I'm using has a skybox, the result can be computed and updated every frame. Also, I'm storing the computed results in the buffer using the
launch_index, which is a 2D array operation (as it is relative to the screen width & height, as each ray is projected from each screen pixel, where the result is projected back in screen-space from world-space).
3) Then finally, back to the C# code, to stream the data back from the GPU device to the CPU host device, I use the following code:
protected override void RayTrace()
Context.Launch( 0, (uint)Width, (uint)Height );
BufferStream stream = ResultsBuffer.Map();
Hope that clarifies some things for anyone who is using Optix.Net for more scientific visualisation/computation purposes.