Iray SDK API nvidia_logo_transpbg.gif Up
Example for On-demand meshes
[Previous] [Next] [Up]

This example imports a partial scene containing definitions for the camera, a light, and some geometry (a ground plane and a yellow cube). It then replaces the triangle mesh of the yellow cube by an equivalent on-demand mesh.

New Topics

  • Creation of on-demand meshes

Detailed Description

Creation of on-demand meshes


The creation of the on-demand mesh itself is rather simple: all that needs to be done is to set the callback object that returns an instance of mi::neuraylib::ISimple_mesh holding the actual geometry data, and to set the bounding box and the maximum displacement. The interesting part is the instance of mi::neuraylib::ISimple_mesh returned by the callback object.

This example shows a sample implementation of the abstract mi::neuraylib::ISimple_mesh interface representing a fixed geometry: a unit cube centered at the origin with face normals. In a typical application this would probably be an adaptor that adapts the application-specific geometry format to the format expected by mi::neuraylib::ISimple_mesh. (Actually, the Cube class is already such an adaptor: it adapts the original data stored in m_points and m_normals with their own index arrays to the data arrays expected by the mi::neuraylib::ISimple_mesh interface with a single index array m_triangles.)

Example Source

Source Code Location: examples/example_on_demand_mesh.cpp

/******************************************************************************
* Copyright 2023 NVIDIA Corporation. All rights reserved.
*****************************************************************************/
// examples/example_on_demand_mesh.cpp
//
// Creates an on-demand mesh.
//
// The example expects the following command line arguments:
//
// example_on_demand_mesh <mdl_path>
//
// mdl_path path to the MDL modules, e.g., iray-<version>/mdl
//
// The rendered image is written to a file named "example_on_demand_mesh.png".
#include <mi/neuraylib.h>
// Include code shared by all examples.
#include "example_shared.h"
// Include an implementation of IRender_target.
#include "example_render_target_simple.h"
#include <iostream>
#include <vector>
// This implementation of the mi::neuraylib::ISimple_mesh interface represents a unit cube centered
// at the origin with face normals. Texture spaces, derivatives, motion vectors, or material indices
// are not present.
//
// Each of the six faces is represented by two triangles, so the mesh consists of 12 triangles.
// Eight vertices would be sufficient for the cube, but since each vertex has different normals for
// each of the three associated faces the length of the data arrays is 24.
class Cube : public mi::base::Interface_implement<mi::neuraylib::ISimple_mesh>
{
public:
// Constructor. Sets up some of the member arrays of this class from a different representation.
Cube();
// Methods required by the mi::neuraylib::ISimple_mesh interface. In this implementation they
// simply return pointers to member arrays of the class (or 0 for not-present optional data
// arrays).
mi::Uint32 data_size() const { return m_data_size; }
const mi::Float32_3_struct* get_points() const { return &m_data_points[0]; }
const mi::Float32_3_struct* get_normals() const { return &m_data_normals[0]; }
mi::Uint32 get_texture_dimension( mi::Uint32 /*texture_space_id*/) const { return 0; }
const mi::Float32* get_texture_coordinates( mi::Uint32 /*texture_space_id*/) const { return 0; }
mi::Uint32 get_userdata_dimension(mi::Uint32 /*userdata_id*/) const { return 0; }
const mi::Float32* get_userdata(mi::Uint32 /*userdata_id*/) const { return 0; }
const char* get_userdata_name(mi::Uint32 /*userdata_id*/) const { return 0; }
const mi::Float32_3_struct* get_derivatives() const { return 0; }
mi::Uint32 get_motion_vector_count() const { return 0; }
const mi::Float32_3_struct* get_motion_vectors() const { return 0; }
mi::Uint32 triangles_size() const { return m_triangles_size; }
const mi::Uint32_3_struct* get_triangles() const { return &m_triangles[0]; }
bool has_unique_material() const { return true; }
const mi::Uint32* get_material_indices() const { return 0; }
private:
// These arrays hold the actual data used during runtime.
// The first two are set up in the constructor from the arrays below.
static const mi::Uint32 m_data_size = 24;
static const mi::Uint32 m_triangles_size = 12;
mi::Float32_3 m_data_points[m_data_size];
mi::Float32_3 m_data_normals[m_data_size];
static mi::Uint32_3 m_triangles[m_triangles_size];
// These arrays hold the original data using a multi-index format.
// They are used in the constructor to set up some of the arrays above.
static const mi::Uint32 m_n_points = 8;
static const mi::Uint32 m_n_normals = 6;
static mi::Float32_3 m_points[m_n_points];
static mi::Float32_3 m_normals[m_n_normals];
static mi::Uint32 m_point_indices[m_data_size];
static mi::Uint32 m_normal_indices[m_data_size];
};
mi::Float32_3 Cube::m_points[m_n_points] = {
mi::Float32_3( -0.5, -0.5, -0.5 ),
mi::Float32_3( 0.5, -0.5, -0.5 ),
mi::Float32_3( -0.5, 0.5, -0.5 ),
mi::Float32_3( 0.5, 0.5, -0.5 ),
mi::Float32_3( -0.5, -0.5, 0.5 ),
mi::Float32_3( 0.5, -0.5, 0.5 ),
mi::Float32_3( -0.5, 0.5, 0.5 ),
mi::Float32_3( 0.5, 0.5, 0.5 )
};
mi::Float32_3 Cube::m_normals[m_n_normals] = {
mi::Float32_3( 0, 0, -1 ),
mi::Float32_3( 0, -1, 0 ),
mi::Float32_3( -1, 0, 0 ),
mi::Float32_3( +1, 0, 0 ),
mi::Float32_3( 0, +1, 0 ),
mi::Float32_3( 0, 0, +1 )
};
mi::Uint32 Cube::m_point_indices[m_data_size] = {
0, 2, 3, 1, 0, 1, 5, 4, 0, 4, 6, 2, 1, 3, 7, 5, 2, 6, 7, 3, 4, 5, 7, 6 };
mi::Uint32 Cube::m_normal_indices[m_data_size] = {
0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 };
mi::Uint32_3 Cube::m_triangles[m_triangles_size] = {
mi::Uint32_3( 0, 1, 2 ),
mi::Uint32_3( 0, 2, 3 ),
mi::Uint32_3( 4, 5, 6 ),
mi::Uint32_3( 4, 6, 7 ),
mi::Uint32_3( 8, 9, 10 ),
mi::Uint32_3( 8, 10, 11 ),
mi::Uint32_3( 12, 13, 14 ),
mi::Uint32_3( 12, 14, 15 ),
mi::Uint32_3( 16, 17, 18 ),
mi::Uint32_3( 16, 18, 19 ),
mi::Uint32_3( 20, 21, 22 ),
mi::Uint32_3( 20, 22, 23 )
};
Cube::Cube()
{
for( mi::Size i = 0; i < m_data_size; ++i) {
m_data_points[i] = m_points[m_point_indices[i]];
m_data_normals[i] = m_normals[m_normal_indices[i]];
}
}
// A callback that always returns a new instance of the Cube class.
class Cube_callback : public mi::base::Interface_implement<mi::neuraylib::IOn_demand_mesh_callback>
{
const mi::neuraylib::ISimple_mesh* call() const { return new Cube(); }
};
// Replace the triangle mesh for the yellow cube with a equivalent on-demand mesh .
void setup_scene( mi::neuraylib::ITransaction* transaction)
{
transaction->create<mi::neuraylib::IOn_demand_mesh>( "On_demand_mesh"));
// Set the callback object that returns an instance of Cube.
mesh->set_callback( callback.get());
callback = 0;
// Set the remaining fields on the on-demand mesh.
mesh->set_bbox( mi::Bbox3( -0.5, -0.5, -0.5, 0.5, 0.5, 0.5));
mesh->set_maximum_displacement( 0);
// Set the visible attribute and the material.
mesh->create_attribute<mi::IBoolean>( "visible", "Boolean"));
visible->set_value( true);
visible = 0;
mi::base::Handle<mi::IRef> material( mesh->create_attribute<mi::IRef>( "material", "Ref"));
check_success( material->set_reference( "yellow_material") == 0);
material = 0;
// Store the on-demand mesh.
check_success( transaction->store( mesh.get(), "on_demand_mesh") == 0);
mesh = 0;
// Change the instance of the yellow cube to point to the on-demand mesh instead.
transaction->edit<mi::neuraylib::IInstance>( "cube_instance"));
check_success( instance->attach( "on_demand_mesh") == 0);
instance = 0;
}
void configuration( mi::neuraylib::INeuray* neuray, const char* mdl_path)
{
// Configure the neuray library. Here we set the search path for .mdl files.
check_success( rc->add_mdl_path( mdl_path) == 0);
check_success( rc->add_mdl_path( ".") == 0);
// Load the OpenImageIO, Iray Photoreal, and .mi importer plugins.
check_success( pc->load_plugin_library( "nv_openimageio" MI_BASE_DLL_FILE_EXT) == 0);
check_success( pc->load_plugin_library( "libiray" MI_BASE_DLL_FILE_EXT) == 0);
check_success( pc->load_plugin_library( "mi_importer" MI_BASE_DLL_FILE_EXT) == 0);
}
void rendering( mi::neuraylib::INeuray* neuray)
{
// Get the database, the global scope of the database, and create a transaction in the global
// scope for importing the scene file and storing the scene.
check_success( database.is_valid_interface());
database->get_global_scope());
scope->create_transaction());
check_success( transaction.is_valid_interface());
// Import the scene file
check_success( import_api.is_valid_interface());
import_api->import_elements( transaction.get(), "file:main.mi"));
check_success( import_result->get_error_number() == 0);
// Replace the triangle mesh by a equivalent on-demand mesh.
setup_scene( transaction.get());
// Create the scene object
transaction->create<mi::neuraylib::IScene>( "Scene"));
scene->set_rootgroup( import_result->get_rootgroup());
scene->set_options( import_result->get_options());
scene->set_camera_instance( import_result->get_camera_inst());
transaction->store( scene.get(), "the_scene");
// Create the render context using the Iray Photoreal render mode
scene = transaction->edit<mi::neuraylib::IScene>( "the_scene");
scene->create_render_context( transaction.get(), "iray"));
check_success( render_context.is_valid_interface());
mi::base::Handle<mi::IString> scheduler_mode( transaction->create<mi::IString>());
scheduler_mode->set_c_str( "batch");
render_context->set_option( "scheduler_mode", scheduler_mode.get());
scene = 0;
// Create the render target and render the scene
new Render_target( image_api.get(), "Color", 512, 384));
check_success( render_context->render( transaction.get(), render_target.get(), 0) >= 0);
// Write the image to disk
check_success( export_api.is_valid_interface());
mi::base::Handle<mi::neuraylib::ICanvas> canvas( render_target->get_canvas( 0));
export_api->export_canvas( "file:example_on_demand_mesh.png", canvas.get());
transaction->commit();
}
int main( int argc, char* argv[])
{
// Collect command line parameters
if( argc != 2) {
std::cerr << "Usage: example_on_demand_mesh <mdl_path>" << std::endl;
keep_console_open();
return EXIT_FAILURE;
}
const char* mdl_path = argv[1];
// Access the neuray library
mi::base::Handle<mi::neuraylib::INeuray> neuray( load_and_get_ineuray());
check_success( neuray.is_valid_interface());
// Configure the neuray library
configuration( neuray.get(), mdl_path);
// Start the neuray library
mi::Sint32 result = neuray->start();
check_start_success( result);
// Do the actual rendering
rendering( neuray.get());
// Shut down the neuray library
check_success( neuray->shutdown() == 0);
neuray = 0;
// Unload the neuray library
check_success( unload());
keep_console_open();
return EXIT_SUCCESS;
}
This interface represents bool.
Definition: inumber.h:122
A reference is an object that acts as a pointer to other database elements.
Definition: iref.h:25
A simple string class.
Definition: istring.h:22
Handle class template for interfaces, automatizing the lifetime control via reference counting.
Definition: handle.h:113
Mixin class template for deriving interface implementations.
Definition: interface_implement.h:41
Axis-aligned N-dimensional bounding box class template of fixed dimension.
Definition: bbox.h:74
Fixed-size math vector class template with generic operations.
Definition: vector.h:286
This interface is used to interact with the distributed database.
Definition: idatabase.h:293
This interface is used to export files.
Definition: iexport_api.h:38
This interface provides various utilities related to canvases and buffers.
Definition: iimage_api.h:49
This interface is used to import files.
Definition: iimport_api.h:100
An instance is a scene element that adds a transformation and attributes to another scene element.
Definition: iinstance.h:117
This is an object representing the Iray library.
Definition: ineuray.h:44
virtual Sint32 shutdown(bool blocking=true)=0
Shuts down the library.
virtual base::IInterface * get_api_component(const base::Uuid &uuid) const =0
Returns an API component from the Iray SDK API.
virtual Sint32 start(bool blocking=true)=0
Starts the operation of the Iray library.
Interface representing an on-demand mesh.
Definition: ion_demand_mesh.h:48
This interface is used to load plugins and to query information about loaded plugins.
Definition: iplugin_configuration.h:24
This interface is used to query and change the rendering configuration.
Definition: irendering_configuration.h:109
The scene is the top-level element describing a subset of DB elements to be rendered.
Definition: iscene.h:44
Interface representing the geometry of on-demand meshes.
Definition: isimple_mesh.h:45
A transaction provides a consistent view on the database.
Definition: itransaction.h:81
virtual base::IInterface * create(const char *type_name, Uint32 argc=0, const base::IInterface *argv[]=0)=0
Creates an object of the type type_name.
virtual base::IInterface * edit(const char *name)=0
Retrieves an element from the database and returns it ready for editing.
virtual Sint32 commit()=0
Commits the transaction.
virtual Sint32 store(base::IInterface *db_element, const char *name, Uint8 privacy=LOCAL_SCOPE)=0
Stores the element db_element in the database under the name name and with the privacy level privacy.
#define MI_BASE_DLL_FILE_EXT
The operating system specific default filename extension for shared libraries (DLLs)
Definition: config.h:340
unsigned int Uint32
32-bit unsigned integer.
Definition: types.h:49
Uint64 Size
Unsigned integral type that is large enough to hold the size of all types.
Definition: types.h:112
float Float32
32-bit float.
Definition: types.h:51
signed int Sint32
32-bit signed integer.
Definition: types.h:46
math::Vector<Uint32, 3> Uint32_3
Vector of three Uint32.
Definition: vector_typedefs.h:69
math::Vector<Float32, 3> Float32_3
Vector of three Float32.
Definition: vector_typedefs.h:90
Iray SDK API.
Generic storage class template for math vector representations storing DIM elements of type T.
Definition: vector.h:135
[Previous] [Next] [Up]