RenderKit / ospray

An Open, Scalable, Portable, Ray Tracing Based Rendering Engine for High-Fidelity Visualization
http://ospray.org
Apache License 2.0
1.02k stars 186 forks source link

Multi-level instancing? #304

Open paulmelis opened 5 years ago

paulmelis commented 5 years ago

I'm trying to debug some code that is not showing any geometry in the rendered output, so I wanted to verify if what I'm doing is actually supported when it comes to instancing. See the code below, should the multiple levels of wrapping an ospGeometry into an ospModel followed by instancing, i.e. base -> container -> world, actually work? Or is it limited to two levels?

// Create base object

OSPGeometry mesh_geometry = ospNewGeometry("triangles");
    // ... set mesh data
ospCommit(mesh_geometry);

OSPModel mesh_model = ospNewModel();
    ospAddGeometry(mesh_model, mesh_geometry);
ospCommit(mesh_model);

// Instantiate many objects

OSPModel container = ospNewModel();

OSPGeometry     instance;
osp::affine3f   xform;

for (int i = 0; i < N; i++)
{
    // read tx, ty, tz, rx, ry, rz from file, compute M based on these values
    M = ...

    xform.l.vx.x = M[0];
    xform.l.vx.y = M[1];
    xform.l.vx.z = M[2];

    xform.l.vy.x = M[4];
    xform.l.vy.y = M[5];
    xform.l.vy.z = M[6];

    xform.l.vz.x = M[8];
    xform.l.vz.y = M[9];
    xform.l.vz.z = M[10];

    xform.p = { tx, ty, tz };

    instance = ospNewInstance(mesh_model, xform);

    ospAddGeometry(container, instance);
}

// Add container to scene, as instance

OSPRenderer renderer = renderer = ospNewRenderer("scivis");

OSPModel world = ospNewModel();

OSPGeometry instance = ospNewInstance(container, xform);    
ospAddGeometry(world, instance);    
ospRelease(instance);

ospCommit(world);
ospSetObject(renderer, "model",  world);
ospCommit(renderer);
jeffamstutz commented 5 years ago

Hi,

Only single-level instancing is supported in OSPRay. In OSPRay v2.0+, we intend on making this explicit in the API by having OSPGeometry-->OSPGeometryInstance-->OSPWorld, where OSPWorld replaces OSPModel. This will directly express the single-level instancing constraint in the API, but allow us to introduce multi-level instancing later if we can do so with a satisfactory design (i.e. introduce recursively defined OSPInstanceGroup).

The biggest issue we face with multi-level instancing is the meta-data around what instances represent in the scene (i.e. overriding attributes such as material lists). Our scene graph which we implement on top of OSPRay does support multi-level instancing, but it is yet-to-be documented...

The solution for OSPRay v1.x is to flatten all instances into a single OSPModel, where each OSPModel that is instanced represents the smallest group of geometries to be instanced.

Cheers, Jeff

paulmelis commented 5 years ago

Dang, so my hunch was right :disappointed:

The section of the docs under Model is then a bit too general as it claims, without mentioning the one-level limit

Models are a container of scene data. They can hold the different geometries and volumes as well as references to (and instances of) other models.

johguenther commented 5 years ago

Well, the truth is somewhere in-between "supporting" and "not supporting" multi-level instancing. The original goal (as written in the documentation) was to support it, but the current implementation has several limitations and hacks (so we opted for a clean cut in OSPRay v2). For "simple" materials and multi-level instances of "basic" geometries it should work. More complex setups (nested material lists, geometry lights) will likely be broken.

I just tried myself, it worked. Be sure to commit each instance / model / geometry, otherwise a zero-only transformation matrix will be used (and the instances just vanish); i.e. call ospCommit(instance); in the loop before adding it to the container and also before adding the container to the world. (BTW: in OSPRay v2 we also like to relax these commit constraints, commits are so easy to forget)