RenderKit / embree

Embree ray tracing kernels repository.
Apache License 2.0
2.37k stars 389 forks source link

Is there a way to update a vertex or index buffer contents and reuse it? #389

Closed mathemaphysics closed 1 year ago

mathemaphysics commented 2 years ago

I tried to build a scene inside a class. I built it somewhat like this. It does this bizarre thing where as I move a triangulated sphere along a vector in the i-loop below in traceTheSceneProgression(), the opposite wall, the one it was moving toward stayed fixed in place as if there were two spheres.

And to be clear, I'm not talking about a sphere as in an RTCGeometry type. The sphere was a surface-meshed object stored in STL format and loaded in using PCL.

Am I calling the geometry/scene setup, commit, and allocation functions in the right order here? The only way I could get it to work was by recreating the scene every single trace. That works, but I have to reallocate the vertex and triangle buffer every time. I'm just trying to figure out if there's a faster way to trace a progression of moving triangles.

class MeshProjector
{
public:
    MeshProjector()
        : _device(rtcNewDevice(nullptr)),
          _scene(rtcNewScene(_device))
    {}

    ~MeshProject()
    {
        rtcReleaseScene(_scene);
        rtcReleaseDevice(_device);
    }

    void createTheScene(const pcl::PolygonMesh& sceneObject)
    {
        // Create the geometry buffers for vertices and indexes
        _geometry = rtcNewGeometry(_device, RTC_GEOMETRY_TYPE_TRIANGLE);
        _vertices = (float*) rtcSetNewGeometryBuffer(
            _geometry, RTC_BUFFER_TYPE_VERTEX, 0,
            RTC_FORMAT_FLOAT3, 3 * sizeof(float),
            sceneObject.cloud.width * sceneObject.cloud.height
        );
        _triangles = (unsigned*) rtcSetNewGeometryBuffer(
            _geometry, RTC_BUFFER_TYPE_INDEX, 0,
            RTC_FORMAT_UINT3, 3 * sizeof(unsigned),
            sceneObject.polygons.size()
        );

        // Now add set all the points and triangles inside to its `sceneObject` contents
    }

    void traceTheSceneProgression(float *raysToTrace)
    {
        for (int i = 0; 100; ++i)
        {
            // Update mesh with new locations and possibly structure
            updateMeshPolygons(); // <- Changes `_vertices` and `_triangles` contents
            rtcCommitGeometry(_geometry);
            rtcAttachGeometry(_scene, _geometry);
            rtcReleaseGeometry(_geometry);
            rtcCommitScene(_scene);

            RTCRayHit rayhit;
            for (int j = 0; j < 50; ++j)
            {
                // Set rayhit origin and direction, and default geomID from raysToTrace, then...
                RTCIntersectContext context;
                rtcInitIntersectionContext(&context);
                rtcIntersect1(_scene, &context, rayhit);

                // Now plot results of `rayhit` somehow to visualize
                // These points intersecting the sphere via `rayhit` are the points
                // which appear to move only on one side of the sphere; the source
                // of the rays is _inside_ the sphere initially, then the sphere moves
            }
        }
    }

private:
    RTCDevice _device;
    RTCScene _scene;
    RTCGeometry _geometry;
    float *_vertices;
    unsigned *_triangles;
}

int main(int argc, char **argv)
{
    MeshProjector meshProjector();

    pcl::PolygonMesh sceneObject;
    pcl::io::loadPolygonFileSTL("sphere.stl", sceneObject);
    meshProjector.createTheScene(sceneObject);

    float *raysToTrace = {...}; // Ray origins and directions, normalized
    meshProjector.traceTheSceneProgression(raysToTrace);

    return 0;
}

To be clear, this does not work. I get what appears to be a merger of two identical shapes, one moving as I require it to and other fixed in place and running into the other one. I tried calling buffer update functions but that didn't work either. I would like to make this setup as efficient as possible, as little memory allocated and reallocated over and over again as possible.

I debugged this problem extensively. I checked the input object. It moves correctly and internal variables show that this is true. Even the _vertices and _triangles buffers clearly have the right contents at any given time. I've plotted it to show that everything is working as it should be right up until rtcIntersect1. I'm certain the order I'm calling the kernel functions is the problem. I just don't know how. Any ideas?

svenwoop commented 2 years ago

In the traceTheSceneProgression function you release the reference to the _geometry object in a loop. Thus geometry object will disappear and memory corruptions occurs. If you remove the rtcReleaseGeometry(_geometry); call then code may work.

mathemaphysics commented 2 years ago

Thanks @svenwoop I'll give it a try.

mathemaphysics commented 1 year ago

@svenwoop I've since made changes and tried removing the rtcReleaseGeometry from the above code, and it doesn't result in any errors, but it doesn't appear to trace the geometry correctly. It looks to be getting corrupted somehow.

Is this code with the rtcReleaseGeometry removed a valid way to trace a scene? Specifically, should it work the way it's intended? I'd like to only allocate the geometry buffers once, but to make this work, I have to reallocate the buffer in every loop.

Should I be using a shared geometry buffer?

Thanks in advance. Embree has really made my work possible. It's appreciated.

svenwoop commented 1 year ago

I see no other issues with your code. Please give the shared geometry buffers a try, this is anyway the recommended way of using Embree.

mathemaphysics commented 1 year ago

@svenwoop I tried just creating the device and scene once at the beginning and destroying each in the destructor, but I get this smearing of my object through space as it moves rather than a fresh trace at each step (see image below). And this happens even when creating and destroying the geometry and geometry buffer at each time step while the scene and device persist.

When I destroy and recreate the scene and device at each step it works as intended. It's like all meshes are still there inside the same scene. Do I need to remove the triangles every iteration somehow?

I'll be trying the shared buffer next, but was wondering if I'm just missing something.

image

svenwoop commented 1 year ago

Do I need to remove the triangles every iteration somehow? No this is not required.

mathemaphysics commented 1 year ago

@svenwoop Good news. It appears that switching to a shared buffer took care of that issue. I don't have to reallocate the buffers in every loop.

Thanks again!