OptixMeshViewer sample

void loadMesh( const std::string& filename )
    OptiXMesh mesh;
    mesh.context = context;
    loadMesh( filename, mesh ); 

    aabb.set( mesh.bbox_min, mesh.bbox_max );

    GeometryGroup geometry_group = context->createGeometryGroup();
    geometry_group->addChild( mesh.geom_instance );
    geometry_group->setAcceleration( context->createAcceleration( "Trbvh" ) );
    context[ "top_object"   ]->set( geometry_group ); 
    context[ "top_shadower" ]->set( geometry_group ); 

In the OptixMeshViewer sample, I don’t see any material attached to the mesh. However, the image displayed has material. Where does this sample attach the material to the mesh?

I am trying to load mesh in my own project. If I don’t set mesh.material to a certain material, it reports error. But I don’t see any code of attaching material in the sample.

The loadMesh function returns a valid optix::GeometryInstance, including an optix::Material node.

Take a look at the sutil/OptiXMesh.cpp. Particularly translateMeshToOptiX() which is called by loadMesh().

Thanks. I looked into translateMeshToOptiX() but still not sure why my program crashes if I don’t attach any material.

//bool have_textures = false;
    //for( int32_t i = 0; i < mesh.num_materials; ++i )
    //  if( !mesh.mat_params[i].Kd_map.empty() ) 
    //    have_textures = true;

    //optix::Program closest_hit = optix_mesh.closest_hit;
    //optix::Program any_hit     = optix_mesh.any_hit;
    //createMaterialPrograms( ctx, have_textures, closest_hit, any_hit );

    //for( int32_t i = 0; i < mesh.num_materials; ++i )
    //  optix_materials.push_back( createOptiXMaterial(
    //        ctx,
    //        closest_hit,
    //        any_hit,
    //        mesh.mat_params[i],
    //        have_textures ) );

    std::string ptx_path("E:/VCM/VCM/build/lib/ptx/optixPathTracer_generated_optixPathTracer.cu.ptx");
    optix::Material glass = ctx->createMaterial();
    optix::Program glass_ch = ctx->createProgramFromPTXFile(ptx_path, "glass_closest_hit_radiance");
    optix::Program glass_ah = ctx->createProgramFromPTXFile(ptx_path, "shadow");
    glass->setClosestHitProgram(0, glass_ch);
    glass->setAnyHitProgram(1, glass_ah);
    memset( mesh.mat_indices, 0, mesh.num_triangles*sizeof(int32_t) );

    optix_materials.push_back( glass );

If I comment the code in translateMeshToOptiX() which assigns a default Phong material to my mesh which doesn’t have any material and instead use a glass material as the default material, my program works well.

What’s wrong with the default Phong material?

The error I get is like this:

OptiX Error: 'Type mismatch (Details: Function "_rtContextValidate" caught excep
tion: Variable "lights" assigned type Buffer(1d, 60 byte element).  Should be Bu
ffer(1d, 32 byte element).)'

It seems like it’s affecting my next buffer.

The following is the code of my .cpp file:

OptiXMesh mesh;
    std::string filename = std::string(sutil::samplesDir()) + "/data/cow.obj";
    mesh.context = crtContext;

    loadMesh(filename, mesh, Matrix4x4::translate(make_float3(250.f, 180.f, 250.f)) * Matrix4x4::scale(make_float3(50.f)));
    // Light
    gis.push_back( createParallelogram( make_float3( 343.0f, 548.6f, 227.0f),
                                        make_float3( -130.0f, 0.0f, 0.0f),
                                        make_float3( 0.0f, 0.0f, 105.0f), crtContext) );
    setMaterial(gis.back(), diffuse_light, "emission_color", light_em);

    // Create geometry group
    GeometryGroup geometry_group = crtContext->createGeometryGroup(gis.begin(), gis.end());
    geometry_group->setAcceleration( crtContext->createAcceleration( "Trbvh" ) );
    crtContext["top_object"]->set( geometry_group );

The validation error you posted is worth looking into:

OptiX Error: 'Type mismatch (Details: Function "_rtContextValidate" caught excep
    tion: Variable "lights" assigned type Buffer(1d, 60 byte element).  Should be Bu
    ffer(1d, 32 byte element).)'

The phong material expects a buffer with 32 byte elements of type BasicLight, as defined in phong.h and commonStructs.h:


rtBuffer<BasicLight> lights;


struct BasicLight
  float3 pos;        // 12 bytes
  float3 color;      // 12
  int casts_shadow;  // 4
  int padding;       // 4
};                   // total 32 bytes

According to this error message, your host code is assigning some other buffer with an unexpected element size (60 byte elements, so something other than BasicLight) to the “lights” variable.

Can you find where in the host code you’re setting “lights”? Look for a line like something like this:

context[ "lights" ]->set( light_buffer );

It could also be set at the Program, GeometryInstance, or Material scope, but the samples tend to set them at the Context scope as shown. If you can track down where this is being set, then it will probably show you why the buffer type is wrong and you can debug it from there.

Fixed. Thank you very much!

I’m in the same situation.

In my case I need to load an OBJ geometry in the scene (OptixPathTracer sample).

I suppose that immiao has fixed it using a light of type Basic Ligth (total 32 bytes).

But in my case I need to use a Paralelogram light (5 x float3 = 60 bytes).

The material that I assign to the imported geometry is the same as for the rest of the scene:

void loadGeometry(const std::string& filename)
	OptiXMesh mesh;
	mesh.context = context;

	loadMesh(filename, mesh);

	aabb.set(mesh.bbox_min, mesh.bbox_max);

	GeometryGroup geometry_group = context->createGeometryGroup();

	mesh.material = diffuse;
	setMaterial(gis.back(), diffuse, "diffuse_color", white);

I do not understand why the type of lights used in the scene condition the imported geometry. I’m sure I’m missing something basic.

Thank you for your patience.

You might want to work through the OptiX Introduction samples I wrote to accompany my recent GTC 2018 tutorial.

At optixIntro_05 that implements direct lighting with a parallelogram area light as well. This is handled as special case of the scene geometry.
At optixIntro_07 you have everything together for a small and elegant uni-directional path tracer implementation. It also supports an importance sampled spherical HDR environment map light then.

It’s not too difficult to import geometry into that renderer. There are multiple routines showing how to build geometry at runtime (plane, sphere, box, torus).
Adding a function which builds geometry from some model file format isn’t that different, just that this would need to handle multiple GeometryInstance depending on how you want to handle the OBJ model hierarchy (all as one, per material, per group per material).
That would happen inside the Application::createScene() with some createObject() function you would have to implement.

I have a version of my OptiX Introduction examples which can load OBJ models and their material MTL files. Though I have written my own custom OBJ and MTL loader for that long ago. I just have not implemented the actual MTL material model.

Since my examples’ vertex attribute data is different, the loadMesh() function in the OptiX sutil library is incompatible.
Additionally the OptiX SDK mesh loader is putting all materials under one single GeometryInstance like done in the translateMeshToOptiX() function, which requires that “material_buffer” with those material indices used inside the intersection program to call the associated anyhit and closesthit implementations.
That’s a very special case of material assignment per triangle which is normally not needed. That’s much too fine grained for general use cases.
That might also be one reason why trying to merge that sutil mesh loader into other OptiX examples which have scene setups with only one material per GeometryInstance is going to be complicated.