Manipulating Geometry with Keyboard or Mouse

Hello all,

I am playing around with the OptiX SDK example ‘sampleanimation’ where an .obj file is loaded and manipulated with a sine curve over the time. This is in sampleanimation.cpp at

void SimpleAnimationScene::updateGeometry( )

.

I dont need the animation, but I would like to manipulate a geometry(in my case there will be only one object like in the example) like stretching or compressing the object with some key or mouse input.

Optimal but firstly optional would be if I can manipulate a part of an object and not the whole thing.

Does anyone have a basic concept of how to it? I am reading the tutorials and the example programs but I dont get any references.

Thanks in advance!

Daniel

There are two concepts involved here.

If you want to change individual vertex attributes and especially the position, you must change the data inside the buffer(s) attached to the Geometry node directly and use mark-dirty calls to let OptiX rebuild/refit the acceleration structure of the scene on the next launch.
That is what the vertex animation example shows in that SimpleAnimationScene::updateGeometry().

If you only want to change parts of the geometry in some way, that would be your responsibility to implement. That is, write your own updateGeometry() function so that it changes the geometry the way you need it. Not sure what references you’re asking for here. There are too many ways to manipulate geometry to answer this.

When you only want to transform an object with a scaling operation, like stretching and compressing, that can be done faster by setting the matrices inside a Transform node above the GeometryGroup holding the sub-tree you want to manipulate. Acceleration structures above that only need to be refit instead of rebuilt then.
OptiX sample7 shows how to use Transform nodes for instancing and different transformations of the underlying Geometry.

Thank you for your fast and helpful reply!

It would be sufficient for me at first when i transform an object with a scaling operation called by a keystroke. For example if i press ‘Y’ the object would get stretched in y-direction by a certain factor.

My first approach was to change the data inside the buffer just like in SimpleAnimationScene::updateGeometry(). But i can only scale once and then if I press the button, I see no change.

Here is my edited function:

void SimpleAnimationScene::compressX()
{
    //We know that we have (only) one group in this example
    GeometryInstance geometryInstance = m_geometry_group->getChild( 0 );
    Geometry geometry = geometryInstance->getGeometry();

    /*
        All we want to do here is to compress all vertices y-position by the 10% .
    */

    Buffer vertexBuffer = geometry["vertex_buffer"]->getBuffer();
    float3* new_vertices = (float3*)vertexBuffer->map();

    RTsize numVertices;
    vertexBuffer->getSize( numVertices );

    //We don't have to set x and z here in this example
    for(unsigned int v = 0; v < numVertices; v++)
    {
        new_vertices[v].x = m_vertices[v].x * 0.9f;
    }

    vertexBuffer->unmap();

    /*
      Vertices are changed now; we have to tell the
      corresponding acceleration structure that it
      has to be rebuild.

      Mark the accel structure and geometry as dirty.
    */
    geometry->markDirty();
    m_geometry_group->getAcceleration()->markDirty();
}

My second approach is setting the matrices inside a Transform node, like you said. But i get an error like OptiX Error: Invalid value (Details: Function “RTresult _rtGroupGetChild(RTgroup, unsigned int, void**)” caught exception: Child index out of range, [2228283]). Can somebody tell me why?

Here is my second approach.

void SimpleAnimationScene::compressY()
{

    //We know that we have (only) one group in this example
    Group maingroup = m_context->createGroup();

    // we have only one group - the main group whose childs are instances of Transform
    // mainGroup is an instance of Group
    Transform transform = maingroup->getChild<Transform>(0);
    //transform->setChild(m_geometry_group);

    //float m[16];
    const float matrix[4*4] = { 1,  0,  0,  0,
                                0,  1.1,  0,  0,
                                0,  0,  1,  0,
                                0,  0,  0,  1 };

    transform->setMatrix(false, matrix, NULL);

    // mark dirty so that the acceleration structure gets rebuilt
    m_geometry_group->getAcceleration()->markDirty();

}

Thanks in advance!

Regards, Daniel

For the first problem, note that the SimpleAnimation example copies the original mesh vertices into the m_vertices array of float3 to always have the original input data available on the host.
Look at initAnimation() where the allocation and memcpy happens.

That is also done because RT_BUFFER_INPUT buffers should not be read on the host, because that is an undefined operation. RT_BUFFER_INPUT buffers should only be written on the host and read on the device. Vice versa for RT_BUFFER_OUTPUT.

Means your code line

new_vertices[v].x = m_vertices[v].x * 0.9f;

will always result in the same coordinates.
The easiest fix would be to change your hard-coded scaling factor 0.9f against a variable you change per user interaction and give that as parameter to your function.

On the second problem, errors like this normally indicate that you didn’t build a valid scene hierarchy.
If you look at the crucial information in the error message: “rtGroupGetChild(RTgroup, unsigned int, void**)” Child index out of range, that tells you that the zero-based unsigned int childIndex parameter indexing the children in a Group node has a value which trying to access a child at a bigger index than you have attached in that Group.
Since you actually didn’t call this yourself, but got the error on the getChild(0) wrapper call you have in your code, that is exactly showing you the problem.
You’re running your code through the debugger, right? If not, never start coding in release mode from now on.

In your code you create an empty Group node and then ask for the child at index zero.

Group maingroup = m_context->createGroup();
Transform transform = maingroup->getChild<Transform>(0);

The second line can obviously not work, because you have not attached any children to the Group.
Also this definitely shouldn’t be done inside the function which is called per transform change. The scene hierarchy should only be built once in this case.

These things are really too basic to be explained on this forum.
Instead I would recommend the following approach for an OptiX beginner:

  • Read the OptiX Programming Guide to learn the basic concepts.
  • Then build all SDK examples as debug version.
  • Single-step inside the debugger through the examples sample1 to sample5 to learn the OptiX C-API.
    For any function used, read the OptiX API Reference Guide to see what the functions do and what is allowed.
  • sample5pp introduces the more convenient C++ wrappers around the C-API.
    Get used to that. All further examples are based on the C++ wrappers.
  • Then work through the tutorial example.
  • Do not start with the full blown examples which load OBJ models and stuff. You need to learn how to build a Geometry yourself. Start with simple objects, from a single triangle to a box etc.
    Only then look at the other examples for topics you’re interested in.