Refit of spheres

Hello to everyone,

I’m currently implementing some rendering plugin using optix and are struggling with some refine issues.
The data to visualize is a set of particle data from a fluid simulation represented as spheres (>100k). As a matter of fact all the elements need to move. Some of them similar to others, some totally different.
Just for a first attempt (of course there will be improved solutions):

  • created one geometry instance and added it to a geometry group
  • created one transform instance for every sphere needed
  • each transform instance transforms the one geometry group
  • added all transforms to group
  • used the group as top-group
  • During rendering all the transforms get a new matrix as the spheres move. I reduced the problem to eight spheres (top four falling down into bottom four) The result is the following (cropped screenshots, not exactly frame-by-frame):

    https://ibb.co/h4UZsw
    https://ibb.co/j10JKb
    https://ibb.co/mDxyKb
    https://ibb.co/bCs9QG

    The geometry group uses Bvh, refit = 1 as acceleration.
    The top-group uses MedianBvh.

    I tried several accelerations and acceleration-settings.

    Obvious questions:

  • Did I generally misunderstand the idea of transforms in optix?
  • As (if correct) several transforms are applied to one geometry group is the geometry group's or the top-group's acceleration-property responsible for managing the change?
  • Do you have a suggestion to manage this issue?
  • Any help is appreciated.

    Many thanks and kind regards
    Benny

    This sounds rather similar to this recent thread about the same problem.
    https://devtalk.nvidia.com/default/topic/1026659/optix/interactive-geometry-replacement/

    Simply pretransform the positions and use a single Geometry with all spheres in one buffer and no Transforms. Use the Trbvh builder for that.
    The root node Acceleration would be the one which needs the refit property and marked dirty after updating the Geometry’s primitive buffer.

    Thanks for the hint. I’ll have a look at it and try it tomorrow.

    The actual problem you have shown inside the pictures is the usual case when you transform some geometry but kept the former acceleration structure. The traversal still happens on the outdated axis aligned bounding boxes while the intersection shader was using the newly transformed primitive locations, alas the clipping effect on the boxes.
    That normally indicates missing markDirty() calls on the Acceleration nodes higher up in the OptiX scene hierarchy.

    That should all be easily solvable when following the advices in the linked post and the links in that.

    Maybe get some inspiration from here about what data sets are actually possible:
    http://on-demand.gputechconf.com/gtc/2017/presentation/s7175-hernandez-exploratory-visualization-petascale-particle-data-nvidia-dgx-1.pdf

    I looked into all hints (and found some more) but now I don’t get any result (except the bg-color).
    This is really hard to debug as Nsight-debugging does’t work with optix and rtPrintf doesn’t print anything. Not even from my “miss” function which is definitely called (I set the context to printEnabled(true) and set the printBufferSize).

    Creation

    m_posBuffer = m_context->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, m_numSpheres);
    context["sphere_buffer"]->setBuffer(m_posBuffer);
    
    Geometry particles = context->createGeometry();
    particles->setPrimitiveCount(m_numSpheres);
    particles->setBoundingBoxProgram(context->createProgramFromPTXFile("sphere.ptx", "bounds"));
    particles->setIntersectionProgram(context->createProgramFromPTXFile("sphere.ptx", "intersect"));
    
    GeometryInstance gi = context->createGeometryInstance();
    gi->setGeometry(particles);
    gi->setMaterialCount(1);
    gi->setMaterial(0, material);
    
    GeometryGroup geometrygroup = context->createGeometryGroup();
    geometrygroup->setChildCount(1);
    geometrygroup->setChild(0, gi);
    
    Acceleration accel = context->createAcceleration("Trbvh");
    geometrygroup->setAcceleration(accel);
    
    context["top_object"]->set(geometrygroup);
    context["top_shadower"]->set(geometrygroup);
    

    Rendering

    float3*	positions = reinterpret_cast<float3*>(m_posBuffer->map());
    
    for (int cnt = 0; cnt < m_numSpheres; ++cnt) {
    	positions->x = tmpData[7 * cnt + 0];
    	positions->y = tmpData[7 * cnt + 1];
    	positions->z = tmpData[7 * cnt + 2];
    	++positions;
    }
    m_posBuffer->unmap();
    
    m_context->launch(0, m_width, m_height);
    

    sphere.cu

    ...
    rtBuffer<float3> sphere_buffer;
    ...
    
    void intersect_sphere(int primIdx)
    {
    	const float3	center = sphere_buffer[primIdx];
    	const float	radius = 0.025f;
    	...
    }
    
    RT_PROGRAM void intersect(int primIdx)
    {
    	intersect_sphere<false>(primIdx);
    }
    
    
    RT_PROGRAM void robust_intersect(int primIdx)
    {
    	intersect_sphere<true>(primIdx);
    }
    
    
    RT_PROGRAM void bounds(int primIdx, float result[6])
    {
    	const float3	cen = sphere_buffer[primIdx];
    	const float	rad = 0.025f;
    	....
    }
    

    I’m really sorry but I cannot find any logical mistake in doing it as I did. And I have no possibility to check either the contents of sphere_buffer or the function of my device-code…

    Thanks again for further hints ;)

    Haha - forget about it. Just found out some old .ptx were used.

    It works - but only using “Bvh” ;)

    Yeah, the code excerpts looked OK and from those I wouldn’t have been able to tell what’s wrong.

    What do you mean only Bvh works? Are you saying Trbvh fails? In what way?
    If you animate the geometric primitive data, Trbvh should result in faster acceleration structure builds and that simply must work.

    What’s your system configuration?
    OS version, installed GPU(s), display driver version, OptiX version (major.minor.micro), CUDA toolkit with which you translated the CUDA code to PTX.

    In fact my small example using eight spheres works on Bvh. The result using Trbvh is as in post #1.
    The original version using 350k spheres doesn’t work using either of the two.

    OS Version: Win 10 Prof, Version 1709, OS build 16299.98
    GPU: NVIDIA GeForce GTX 1070, Driver-Version 22.21.13.8554
    OptiX 4.1.1
    CUDA 9.0.176

    CUDA 9.0 is not officially supported to be used with OptiX 4 versions when generating the input PTX code. Please try CUDA 8.0 as mentioned inside the OptiX Release notes.

    Are you using markDirty() on the acceleration structure?
    What’s the behavior without acceleration property “refit” set to “1” and with it?

    If that leads to no results, we would need a reproducer. Search the OptiX forum for “OptiX API Capture” (OAC) to find a way to provide a reproducer to us without the need for the application.

    Thank you so much.
    During rewrting the code I must have killed the part setting the markDirty-flag.

    For 350k spheres I now have 30fps using Trbvh without any visible errors. Setting property refit to “1” results in performance dropping to 0.225fps ;)

    But I can continue working on the project. Thanks a lot.

    Very nice!

    Thanks for testing. If the acceleration structure on the Geometry group with the particles is the root traversal node, there isn’t much benefit in using refit on that. The extreme drop in performance when it’s enabled needs to be investigated in-house.