Iray SDK API nvidia_logo_transpbg.gif Up
Example for Scene Creation
[Previous] [Next] [Up]

This example programmatically creates a scene via API calls instead of importing it from a scene file.

New Topics

  • Comparison to the provided scene file "main.mi"
  • Order of scene element creation
  • Basic procedure for scene element creation
  • Categorization of scene elements

Detailed Description

Comparison to the provided scene file "main.mi"


This example is very similar to Example for Rendering, except that it does not import a provided scene file, but calls the function create_scene() which constructs a scene programmatically via API calls. The created scene is identical to the one created by importing "main.mi" except that some features which are not needed in this example have been omitted (some MDL material instances and the texture coordinates for the ground plane). The only file loaded from disk is "main.mdl" which contains the MDL definitions for the materials used in this example.

Order of scene element creation


The various scene elements are created one-by-one in a bottom-up order (this is the same order as in the "main.mi" file). The order matters as soon as references between DB elements are created. It is required that the referenced DB element exists already in the DB when the reference is set. If a top-down order is needed for some reason, one has to delay setting the reference until the referenced DB element has been stored in the DB.

Procedure for scene element creation


Creating a certain scene element is typically a three step procedure: first the scene element is created via a mi::neuraylib::ITransaction::create() call. Then its properties (including any attributes) are set up. Finally mi::neuraylib::ITransaction::store() is used to store it in the database under some name that can be used later to re-access or to reference it. MDL material instances and function deviate from that scheme as they require the use of a dedicated factory function on the corresponding material or function definition.

Categorization of scene elements


The different scene elements can roughly be categorized into four groups:

  • structural elements (e.g., instances, groups),
  • leaf nodes (e.g., cameras, lights, geometry, options),
  • MDL related elements (materials, functions),
  • miscellaneous elements (e.g., images, textures, light profiles, BSDF measurements).

The details of the various scene element types is beyond the scope of this example. See the next example for details about MDL, or the second-next example for details about triangle meshes.

Example Source

Source Code Location: examples/example_scene.cpp

/******************************************************************************
* Copyright 2023 NVIDIA Corporation. All rights reserved.
*****************************************************************************/
// examples/example_scene.cpp
//
// Creates a scene programmatically, renders the scene, and writes the image to disk.
//
// The example expects the following command line arguments:
//
// example_scene <scene_file> <mdl_path>
//
// scene_file some scene file, e.g., main.mi
// mdl_path path to the MDL modules, e.g., iray-<version>/mdl
//
// The rendered image is written to a file named "example_scene.png".
#include <iostream>
#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"
// Geometry of the yellow cube.
const mi::Uint32 cube_n_points = 8;
const mi::Uint32 cube_n_normals = 6;
const mi::Uint32 cube_n_uvs = 4;
const mi::Uint32 cube_n_triangles = 12;
mi::Float32_3 cube_points[cube_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_normals[cube_n_normals] = {
mi::Float32_3( 0.0, 0.0, -1.0),
mi::Float32_3( 0.0, -1.0, 0.0),
mi::Float32_3( -1.0, 0.0, 0.0),
mi::Float32_3( 0.0, 0.0, 1.0),
mi::Float32_3( 0.0, 1.0, 0.0),
mi::Float32_3( 1.0, 0.0, 0.0) };
mi::Float32_2 cube_uvs[cube_n_uvs] = {
mi::Float32_2( 0.0, 0.0),
mi::Float32_2( 1.0, 0.0),
mi::Float32_2( 0.0, 1.0),
mi::Float32_2( 1.0, 1.0) };
mi::neuraylib::Triangle_point_indices cube_mesh_connectivity[cube_n_triangles] = {
mi::neuraylib::Triangle_point_indices cube_normal_connectivity[cube_n_triangles] = {
mi::neuraylib::Triangle_point_indices cube_uv_connectivity[cube_n_triangles] = {
// Geometry of the grey ground plane.
const mi::Uint32 ground_n_points = 4;
const mi::Uint32 ground_n_normals = 1;
const mi::Uint32 ground_n_uvs = 4;
const mi::Uint32 ground_n_triangles = 2;
mi::Float32_3 ground_points[ground_n_points] = {
mi::Float32_3( -2.0, 0.0, -2.0),
mi::Float32_3( -2.0, 0.0, 2.0),
mi::Float32_3( 2.0, 0.0, 2.0),
mi::Float32_3( 2.0, 0.0, -2.0) };
mi::Float32_3 ground_normals[ground_n_normals] = {
mi::Float32_3( 0.0, 1.0, 0.0) };
mi::Float32_2 ground_uvs[ground_n_uvs] = {
mi::Float32_2( 0.0, 1.0),
mi::Float32_2( 0.0, 0.0),
mi::Float32_2( 1.0, 0.0),
mi::Float32_2( 1.0, 1.0) };
mi::neuraylib::Triangle_point_indices ground_mesh_connectivity[ground_n_triangles] = {
mi::neuraylib::Triangle_point_indices ground_normal_connectivity[ground_n_triangles] = {
mi::neuraylib::Triangle_point_indices ground_uv_connectivity[ground_n_triangles] = {
// Creates an attribute "name" of type "Boolean" on "attribute_set" and sets its value to "value".
void create_flag( mi::neuraylib::IAttribute_set* attribute_set, const char* name, bool value)
{
attribute_set->create_attribute<mi::IBoolean>( name, "Boolean"));
attribute->set_value( value);
}
// Programmatically creates a scene via API calls (the same scene as in "main.mi").
mi::neuraylib::IScene* create_scene(
{
mdl_factory->create_value_factory( transaction));
mdl_factory->create_expression_factory( transaction));
{
// Import the MDL module "main"
check_success( import_api.is_valid_interface());
import_api->import_elements( transaction, "file:${shader}/main.mdl"));
check_success( import_result->get_error_number() == 0);
}
{
// Create the options "options"
transaction->create<mi::neuraylib::IOptions>( "Options"));
transaction->store( options.get(), "options");
}
{
// Create the MDL material instance "yellow_material" used by "cube_instance"
value_factory->create_color( 0.942f, 0.807216f, 0.33441f));
expression_factory->create_constant( value.get()));
expression_factory->create_expression_list());
arguments->add_expression( "tint", expression.get());
"mdl::main::diffuse_material(color)"));
definition->create_function_call( arguments.get()));
check_success( material.get());
transaction->store( material.get(), "yellow_material");
}
{
// Create the MDL material instance "grey_material" used by "ground_instance"
value_factory->create_color( 0.306959f, 0.306959f, 0.306959f));
expression_factory->create_constant( value.get()));
expression_factory->create_expression_list());
arguments->add_expression( "tint", expression.get());
"mdl::main::diffuse_material(color)"));
definition->create_function_call( arguments.get()));
check_success( material.get());
transaction->store( material.get(), "grey_material");
}
{
// Create the MDL material instance "white_light" used by "light"
value_factory->create_color( 1000.0f, 1000.0f, 1000.0f));
expression_factory->create_constant( value.get()));
expression_factory->create_expression_list());
arguments->add_expression( "tint", expression.get());
"mdl::main::diffuse_light(color)"));
definition->create_function_call( arguments.get()));
check_success( material.get());
transaction->store( material.get(), "white_light");
}
{
// Create the triangle mesh "cube"
transaction->create<mi::neuraylib::ITriangle_mesh>( "Triangle_mesh"));
create_flag( mesh.get(), "visible", true);
create_flag( mesh.get(), "reflection_cast", true);
create_flag( mesh.get(), "reflection_recv", true);
create_flag( mesh.get(), "refraction_cast", true);
create_flag( mesh.get(), "refraction_recv", true);
create_flag( mesh.get(), "shadow_cast", true);
create_flag( mesh.get(), "shadow_recv", true);
// Set point data and mesh connectivity
mesh->reserve_points( cube_n_points);
for( mi::Uint32 i = 0; i < cube_n_points; ++i)
mesh->append_point( cube_points[i]);
mesh->reserve_triangles( cube_n_triangles);
for( mi::Uint32 i = 0; i < cube_n_triangles; ++i)
mesh->append_triangle( cube_mesh_connectivity[i]);
// Set normal data and normal connectivity
mesh->create_connectivity());
for( mi::Uint32 i = 0; i < cube_n_triangles; ++i)
normal_connectivity->set_triangle_indices(
mi::neuraylib::Triangle_handle( i), cube_normal_connectivity[i]);
normal_connectivity->create_attribute_vector( mi::neuraylib::ATTR_NORMAL));
for( mi::Uint32 i = 0; i < cube_n_normals; ++i)
normals->append_vector3( cube_normals[i]);
check_success( normal_connectivity->attach_attribute_vector( normals.get()) == 0);
check_success( mesh->attach_connectivity( normal_connectivity.get()) == 0);
// Set uv data and uv connectivity
mesh->create_connectivity());
for( mi::Uint32 i = 0; i < cube_n_triangles; ++i)
uv_connectivity->set_triangle_indices(
mi::neuraylib::Triangle_handle( i), cube_uv_connectivity[i]);
uv_connectivity->create_attribute_vector( mi::neuraylib::ATTR_TEXTURE, 2));
for( mi::Uint32 i = 0; i < cube_n_uvs; ++i)
uvs->append_float32( &cube_uvs[i][0], 2);
check_success( uv_connectivity->attach_attribute_vector( uvs.get()) == 0);
check_success( mesh->attach_connectivity( uv_connectivity.get()) == 0);
transaction->store( mesh.get(), "cube");
}
{
// Create the instance "cube_instance" referencing "cube"
transaction->create<mi::neuraylib::IInstance>( "Instance"));
check_success( instance->attach( "cube") == 0);
mi::Float64_4_4 matrix( 1.0f);
matrix.translate( 1.3f, -0.5f, 1.0f);
instance->set_matrix( matrix);
instance->create_attribute<mi::IRef>( "material", "Ref"));
check_success( material->set_reference( "yellow_material") == 0);
transaction->store( instance.get(), "cube_instance");
}
{
// Create the triangle mesh "ground"
transaction->create<mi::neuraylib::ITriangle_mesh>( "Triangle_mesh"));
create_flag( mesh.get(), "visible", true);
create_flag( mesh.get(), "reflection_cast", true);
create_flag( mesh.get(), "reflection_recv", true);
create_flag( mesh.get(), "refraction_cast", true);
create_flag( mesh.get(), "refraction_recv", true);
create_flag( mesh.get(), "shadow_cast", true);
create_flag( mesh.get(), "shadow_recv", true);
// Set point data and mesh connectivity
mesh->reserve_points( ground_n_points);
for( mi::Uint32 i = 0; i < ground_n_points; ++i)
mesh->append_point( ground_points[i]);
mesh->reserve_triangles( ground_n_triangles);
for( mi::Uint32 i = 0; i < ground_n_triangles; ++i)
mesh->append_triangle( ground_mesh_connectivity[i]);
// Set normal data and normal connectivity
mesh->create_connectivity());
for( mi::Uint32 i = 0; i < ground_n_triangles; ++i)
normal_connectivity->set_triangle_indices(
mi::neuraylib::Triangle_handle( i), ground_normal_connectivity[i]);
normal_connectivity->create_attribute_vector( mi::neuraylib::ATTR_NORMAL));
for( mi::Uint32 i = 0; i < ground_n_normals; ++i)
normals->append_vector3( ground_normals[i]);
check_success( normal_connectivity->attach_attribute_vector( normals.get()) == 0);
check_success( mesh->attach_connectivity( normal_connectivity.get()) == 0);
// Set uv data and uv connectivity
mesh->create_connectivity());
for( mi::Uint32 i = 0; i < ground_n_triangles; ++i)
uv_connectivity->set_triangle_indices(
mi::neuraylib::Triangle_handle( i), ground_uv_connectivity[i]);
uv_connectivity->create_attribute_vector( mi::neuraylib::ATTR_TEXTURE, 2));
for( mi::Uint32 i = 0; i < ground_n_uvs; ++i)
uvs->append_float32( &ground_uvs[i][0], 2);
check_success( uv_connectivity->attach_attribute_vector( uvs.get()) == 0);
check_success( mesh->attach_connectivity( uv_connectivity.get()) == 0);
transaction->store( mesh.get(), "ground");
}
{
// Create the instance "ground_instance" referencing "ground"
transaction->create<mi::neuraylib::IInstance>( "Instance"));
check_success( instance->attach( "ground") == 0);
instance->create_attribute<mi::IRef>( "material", "Ref"));
check_success( material->set_reference( "grey_material") == 0);
transaction->store( instance.get(), "ground_instance");
}
{
// Create the light "light"
transaction->create<mi::neuraylib::ILight>( "Light"));
create_flag( light.get(), "shadow_cast", true);
light->create_attribute<mi::IRef>( "material", "Ref"));
check_success( material->set_reference( "white_light") == 0);
transaction->store( light.get(), "light");
}
{
// Create the instance "light_instance" referencing "light"
transaction->create<mi::neuraylib::IInstance>( "Instance"));
check_success( instance->attach( "light") == 0);
mi::Float64_4_4 matrix( 1.0f);
matrix.translate( 5.1f, -7.3f, -1.6f);
instance->set_matrix( matrix);
transaction->store( instance.get(), "light_instance");
}
{
// Create the camera "camera"
transaction->create<mi::neuraylib::ICamera>( "Camera"));
camera->set_focal( 50.0f);
camera->set_aperture( 44.0f);
camera->set_aspect( 1.33333f);
camera->set_resolution_x( 512);
camera->set_resolution_y( 384);
camera->set_clip_min( 0.1);
camera->set_clip_max( 1000);
transaction->store( camera.get(), "camera");
}
{
// Create the instance "camera_instance" referencing "camera"
transaction->create<mi::neuraylib::IInstance>( "Instance"));
check_success( instance->attach( "camera") == 0);
0.68826f, 0.37107f, -0.623382f, 0.0f,
0.00000f, 0.85929f, 0.511493f, 0.0f,
0.72546f, -0.35204f, 0.591414f, 0.0f,
0.00000f, 0.00000f, -6.256200f, 1.0f);
instance->set_matrix( matrix);
transaction->store( instance.get(), "camera_instance");
}
{
// Create the group "rootgroup" containing all instances
transaction->create<mi::neuraylib::IGroup>( "Group"));
check_success( group->attach( "cube_instance" ) == 0);
check_success( group->attach( "ground_instance") == 0);
check_success( group->attach( "light_instance" ) == 0);
check_success( group->attach( "camera_instance") == 0);
transaction->store( group.get(), "rootgroup");
}
// Create the scene object itself and return it.
mi::neuraylib::IScene* scene = transaction->create<mi::neuraylib::IScene>( "Scene");
scene->set_rootgroup( "rootgroup");
scene->set_camera_instance( "camera_instance");
scene->set_options( "options");
return scene;
}
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.is_valid_interface());
check_success( rc->add_mdl_path( mdl_path) == 0);
check_success( rc->add_mdl_path( ".") == 0);
// Load the OpenImageIO and Iray Photoreal 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);
}
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());
// Create the scene
mi::base::Handle<mi::neuraylib::IScene> scene( create_scene( neuray, transaction.get()));
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_scene.png", canvas.get());
transaction->commit();
}
int main( int argc, char* argv[])
{
// Collect command line parameters
if( argc != 2) {
std::cerr << "Usage: example_scene <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
NxM-dimensional matrix class template of fixed dimensions.
Definition: matrix.h:367
Fixed-size math vector class template with generic operations.
Definition: vector.h:286
The attribute set comprises all attributes attached to a database element.
Definition: iattribute_set.h:332
virtual IData * create_attribute(const char *name, const char *type)=0
Creates a new attribute name of the type type.
The camera defines the viewpoint from which the scene is rendered.
Definition: icamera.h:56
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 represents a function definition.
Definition: ifunction_definition.h:44
A group is a container for other scene elements.
Definition: igroup.h:39
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
Point, spot, directional and area lighting.
Definition: ilight.h:68
Factory for various MDL interfaces and functions.
Definition: imdl_factory.h:53
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.
A scene element that stores scene-specific settings.
Definition: ioptions.h:115
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
virtual Sint32 set_camera_instance(const char *camera)=0
Sets the camera instance of this scene.
virtual Sint32 set_options(const char *options)=0
Sets the options of this scene.
virtual IRender_context * create_render_context(ITransaction *transaction, const char *render_mode, Sint32 *errors=0)=0
Creates a render context suitable for rendering the scene with a given render mode.
virtual Sint32 set_rootgroup(const char *root)=0
Sets the root group of this scene.
A transaction provides a consistent view on the database.
Definition: itransaction.h:81
virtual const base::IInterface * access(const char *name)=0
Retrieves an element from the database.
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.
Interface representing a triangle mesh.
Definition: itriangle_mesh.h:122
Handle class for type-safety.
Definition: identifier.h:66
A triangle defined by three point indices, starting at index 0.
Definition: itriangle_connectivity.h:33
#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
signed int Sint32
32-bit signed integer.
Definition: types.h:46
math::Vector<Float32, 2> Float32_2
Vector of two Float32.
Definition: vector_typedefs.h:83
math::Vector<Float32, 3> Float32_3
Vector of three Float32.
Definition: vector_typedefs.h:90
@ ATTR_TEXTURE
Texture coordinates of type mi::Float32[] per point or per vertex (also called texture space).
Definition: iattribute_vector.h:101
@ ATTR_NORMAL
Surface normals of type mi::Float32_3 per point or per vertex.
Definition: iattribute_vector.h:65
Iray SDK API.
[Previous] [Next] [Up]