Editing and creating materials
- typical MDL-related tasks such as modifying inputs of material instances, creating new material instances, and attaching function calls to material inputs:
- The program example_mdl.cpp, which uses the scene main.mi to demonstrate typical MDL-related tasks.
Modifying inputs of existing material instances
This section describes the steps for modifying the input of an existing material instance. In particular, it explains how to change the color of the material instance yellow_material, which is used for the cube and other scene elements in example_mdl.cpp.
To change the color, an interface is required that represents the new value. The method get_argument_type() of the mi::neuraylib::IMdl_material_instance interface yields the type name of the tint argument, which is Attachable. Passing this type name to mi::neuraylib::ITransaction::create() yields the required interface.
To set the value, the free function set_value(mi::IData *data, const mi::Spectrum &value) is used. This template function is quite useful when dealing with instances of mi::IData and mi::neuraylib::IAttribute_set. It tries to match the dynamic type of the mi::IData instance with the static type of the second argument, converts it as necessary, and calls the appropriate setter method. In particular, when dealing with attachables, it avoids the extra call of mi::IAttachable::get_value().
The new value is then set with the set_argument() method.
These steps are shown in example_mdl.cpp in full detail for illustrative purposes. The helper class mi::neuraylib::Mdl_argument_editor can be used to simplify such workflows, as shown in the second code block.
Creating new material instances
This section describes the steps for creating a new material instance and an example for its use.
As described in the previous section, the material instance of yellow_material is shared by a number of scene elements. When the color of this material instance is changed, then the change is reflected in all scene elements that use the shared material. To change the color of the cube only, requires three steps: preparing the arguments of a new material instance, creating the new material instance, and then attaching it to the cube. The steps are described in more detail as follows:
- Prepare an attribute container that holds the arguments of the new material instance. This is mandatory if the material definition has parameters without default initializers, otherwise it is optional. In both cases, arguments can be modified after creation of the material instance as shown above.
- Use the method create_material_instance() to create a new material instance from the material definition mdl::main::diffuse_material (the same definition that was used for yellow_material). The newly created material instance is stored in the database.
- Replace the previously used material instance, yellow_material, with the newly created material instance by changing the material attribute of cube_instance.
These steps are shown in example_mdl.cpp in full detail.
Attaching function calls to material inputs
The preceding sections of this topic focused on constant inputs for material instances. This section describes how to connect another MDL function to the input of the material instance.
The interface mi::IAttachable is used to handle these two modes for arguments of material instances (or function calls). This interface can represent the following:
- A reference to another database element (similar to mi::IRef), which is used to represent MDL function calls
- A fixed value (of type mi::IData), which is used to represent constant inputs, for example color, as described in the preceding sections of this topic
The program example_mdl.cpp shows how to apply a texture to the ground plane:
- Create the necessary database elements of type mi::neuraylib::IImage and mi::neuraylib::ITexture, which will hold the texture to be used.
- Import the MDL module base, which contains the MDL function mdl::base::file_texture to be used.
- Instantiate the function definition mdl::base::file_texture with the argument texture set to the database element of type mi::neuraylib::ITexture created in step 1. Actually, the true name of the database element representing the MDL function base::file_texture is not mdl::base::file_texture, but quite a long name that includes the function signature. Hence, the method mi::neuraylib::IMdl_module::get_function_overloads(const char *name, const char *param_sig) const =0 is used to retrieve the exact name of the database element without hard-coding it.
- The return type of mdl::base::file_texture is the structure texture_return, which does not match the desired argument type Attachable of the tint argument of the material instance. Hence, the MDL function mdl::base::texture_return.tint is used, which extracts the tint field of the texture_return structure. In this case, the helper function get_function_overloads() was not used, rather the full name mdl::base::texture_return.tint(::base::texture_return) directly.
- The function definition is instantiated and its s argument is set to the instance of mdl::base::file_texture.
- The tint argument of the material instance used for the ground plane is changed to point to the new function call. The program example_mdl.cpp shows how this step can be simplified using the helper class mi::neuraylib::Mdl_argument_editor.
example_mdl.cpp
001 /****************************************************************************** 002 * © 1986, 2016 NVIDIA Corporation. All rights reserved. 003 *****************************************************************************/ 004 005 // examples/example_mdl.cpp 006 // 007 // Imports a scene file, performs various MDL-related operations, and writes the rendered results 008 // to disk. 009 // 010 // The example expects the following command line arguments: 011 // 012 // example_mdl <mdl_path> 013 // 014 // mdl_path path to the MDL modules, e.g., iray-<version>/mdl 015 // 016 // The rendered images are written to files named "example_mdl_*.png". 017 018 #include <iostream> 019 020 #include <mi/neuraylib.h> 021 022 // Include code shared by all examples. 023 #include "example_shared.h" 024 // Include an implementation of IRender_target. 025 #include "example_render_target_simple.h" 026 027 void configuration( mi::base::Handle<mi::neuraylib::INeuray> neuray, const char* mdl_path) 028 { 029 // Configure the neuray library. Here we set the search path for .mdl files. 030 mi::base::Handle<mi::neuraylib::IRendering_configuration> rendering_configuration( 031 neuray->get_api_component<mi::neuraylib::IRendering_configuration>()); 032 check_success( rendering_configuration.is_valid_interface()); 033 check_success( rendering_configuration->add_mdl_path( mdl_path) == 0); 034 035 // Load the FreeImage, Iray Photoreal, and .mi importer plugins. 036 mi::base::Handle<mi::neuraylib::IPlugin_configuration> plugin_configuration( 037 neuray->get_api_component<mi::neuraylib::IPlugin_configuration>()); 038 #ifndef MI_PLATFORM_WINDOWS 039 check_success( plugin_configuration->load_plugin_library( "freeimage.so") == 0); 040 check_success( plugin_configuration->load_plugin_library( "libiray.so") == 0); 041 check_success( plugin_configuration->load_plugin_library( "mi_importer.so") == 0); 042 #else 043 check_success( plugin_configuration->load_plugin_library( "freeimage.dll") == 0); 044 check_success( plugin_configuration->load_plugin_library( "libiray.dll") == 0); 045 check_success( plugin_configuration->load_plugin_library( "mi_importer.dll") == 0); 046 #endif 047 } 048 049 void render_and_export( 050 mi::base::Handle<mi::neuraylib::INeuray> neuray, 051 mi::base::Handle<mi::neuraylib::ITransaction> transaction, 052 const char* uri) 053 { 054 // Create the render context using the Iray Photoreal render mode. 055 mi::base::Handle<mi::neuraylib::IScene> scene( 056 transaction->edit<mi::neuraylib::IScene>( "the_scene")); 057 mi::base::Handle<mi::neuraylib::IRender_context> render_context( 058 scene->create_render_context( transaction.get(), "iray")); 059 check_success( render_context.is_valid_interface()); 060 mi::base::Handle<mi::IString> scheduler_mode( transaction->create<mi::IString>()); 061 scheduler_mode->set_c_str( "batch"); 062 render_context->set_option( "scheduler_mode", scheduler_mode.get()); 063 scene = 0; 064 065 // Create the render target and render the scene. 066 mi::base::Handle<mi::neuraylib::IImage_api> image_api( 067 neuray->get_api_component<mi::neuraylib::IImage_api>()); 068 mi::base::Handle<mi::neuraylib::IRender_target> render_target( 069 new Render_target( image_api.get(), "Color", 512, 384)); 070 check_success( render_context->render( transaction.get(), render_target.get(), 0) >= 0); 071 072 // Write the image to disk. 073 mi::base::Handle<mi::neuraylib::IExport_api> export_api( 074 neuray->get_api_component<mi::neuraylib::IExport_api>()); 075 check_success( export_api.is_valid_interface()); 076 mi::base::Handle<mi::neuraylib::ICanvas> canvas( render_target->get_canvas( 0)); 077 export_api->export_canvas( uri, canvas.get()); 078 } 079 080 void import_and_render_original_scene( 081 mi::base::Handle<mi::neuraylib::INeuray> neuray, 082 mi::base::Handle<mi::neuraylib::IScope> scope) 083 { 084 // Create a transaction for importing the scene file and storing the scene. 085 mi::base::Handle<mi::neuraylib::ITransaction> transaction( 086 scope->create_transaction()); 087 check_success( transaction.is_valid_interface()); 088 089 // Import the scene file. 090 mi::base::Handle<mi::neuraylib::IImport_api> import_api( 091 neuray->get_api_component<mi::neuraylib::IImport_api>()); 092 check_success( import_api.is_valid_interface()); 093 mi::base::Handle<const mi::neuraylib::IImport_result> import_result( 094 import_api->import_elements( transaction.get(), "file:main.mi")); 095 check_success( import_result->get_error_number() == 0); 096 097 // Create the scene object. 098 mi::base::Handle<mi::neuraylib::IScene> scene( 099 transaction->create<mi::neuraylib::IScene>( "Scene")); 100 scene->set_rootgroup( import_result->get_rootgroup()); 101 scene->set_options( import_result->get_options()); 102 scene->set_camera_instance( import_result->get_camera_inst()); 103 transaction->store( scene.get(), "the_scene"); 104 105 render_and_export( neuray, transaction, "file:example_mdl_original.png"); 106 transaction->commit(); 107 } 108 109 void modify_material_instance( 110 mi::base::Handle<mi::neuraylib::INeuray> neuray, 111 mi::base::Handle<mi::neuraylib::IScope> scope, 112 mi::base::Handle<mi::neuraylib::IFactory> factory) 113 { 114 // Create a transaction. 115 mi::base::Handle<mi::neuraylib::ITransaction> transaction( 116 scope->create_transaction()); 117 check_success( transaction.is_valid_interface()); 118 119 { 120 // Create a new value for the "tint" argument and set it to bright grey. 121 mi::base::Handle<mi::neuraylib::IMdl_material_instance> yellow_material( 122 transaction->edit<mi::neuraylib::IMdl_material_instance>( "yellow_material")); 123 mi::base::Handle<mi::IAttachable> tint( 124 transaction->create<mi::IAttachable>( yellow_material->get_argument_type( "tint"))); 125 mi::math::Spectrum bright_grey( 0.7f, 0.7f, 0.7f); 126 mi::set_value( tint.get(), bright_grey); 127 128 // Set the new value for the "tint" argument of "yellow_material". 129 yellow_material->set_argument( "tint", tint.get()); 130 } 131 // The same effect as in the preceding code block can alternatively be achieved by using the 132 // helper class Mdl_argument_editor as follows: 133 { 134 // Set the "tint" argument of "yellow_material" to bright grey. 135 mi::neuraylib::Mdl_argument_editor yellow_material( 136 transaction.get(), "yellow_material", factory.get()); 137 check_success( 138 yellow_material.set_value( "tint", mi::math::Spectrum( 0.7f, 0.7f, 0.7f)) == 0); 139 140 } 141 142 render_and_export( neuray, transaction, "file:example_mdl_modified_material_argument.png"); 143 transaction->commit(); 144 } 145 146 void create_new_material_instance( 147 mi::base::Handle<mi::neuraylib::INeuray> neuray, 148 mi::base::Handle<mi::neuraylib::IScope> scope, 149 mi::base::Handle<mi::neuraylib::IFactory> /*factory*/) 150 { 151 // Create a transaction. 152 mi::base::Handle<mi::neuraylib::ITransaction> transaction( 153 scope->create_transaction()); 154 check_success( transaction.is_valid_interface()); 155 156 { 157 // Prepare the arguments for the new material instance: set the "tint" argument to white. 158 mi::base::Handle<const mi::neuraylib::IMdl_material_definition> material_definition( 159 transaction->access<mi::neuraylib::IMdl_material_definition>( 160 "mdl::main::diffuse_material")); 161 mi::base::Handle<mi::neuraylib::IAttribute_container> arguments( 162 transaction->create<mi::neuraylib::IAttribute_container>( "Attribute_container")); 163 mi::base::Handle<mi::IAttachable> tint( arguments->create_attribute<mi::IAttachable>( 164 "tint", material_definition->get_argument_type( "tint"))); 165 mi::math::Spectrum white( 1.0f, 1.0f, 1.0f); 166 mi::set_value( tint.get(), white); 167 168 // Create a material instance of the material definition "mdl::main::diffuse_material" with 169 // the just prepared arguments. 170 mi::Sint32 result; 171 mi::base::Handle<mi::neuraylib::IMdl_material_instance> material_instance( 172 material_definition->create_material_instance( arguments.get(), &result)); 173 check_success( result == 0); 174 transaction->store( material_instance.get(), "white_material"); 175 176 // Attach the newly created material instance to the scene element "cube_instance", thereby 177 // replacing the existing material instance "yellow_material". 178 mi::base::Handle<mi::neuraylib::IInstance> instance( 179 transaction->edit<mi::neuraylib::IInstance>( "cube_instance")); 180 mi::base::Handle<mi::IArray> material( instance->edit_attribute<mi::IArray>( "material")); 181 check_success( 182 mi::set_value( material.get(), static_cast<mi::Size>( 0), "white_material") == 0); 183 } 184 185 render_and_export( neuray, transaction, "file:example_mdl_new_material_instance.png"); 186 transaction->commit(); 187 } 188 189 void attach_function_call( 190 mi::base::Handle<mi::neuraylib::INeuray> neuray, 191 mi::base::Handle<mi::neuraylib::IScope> scope, 192 mi::base::Handle<mi::neuraylib::IFactory> factory) 193 { 194 // Create a transaction. 195 mi::base::Handle<mi::neuraylib::ITransaction> transaction( 196 scope->create_transaction()); 197 check_success( transaction.is_valid_interface()); 198 199 { 200 // Create a DB element for the image and the texture referencing it. 201 mi::base::Handle<mi::neuraylib::IImage> image( 202 transaction->create<mi::neuraylib::IImage>( "Image")); 203 check_success( image->reset_file( "nvidia_logo.png") == 0); 204 transaction->store( image.get(), "nvidia_image"); 205 mi::base::Handle<mi::neuraylib::ITexture> texture( 206 transaction->create<mi::neuraylib::ITexture>( "Texture")); 207 texture->set_image( "nvidia_image"); 208 transaction->store( texture.get(), "nvidia_texture"); 209 } 210 { 211 // Import the "base.mdl" module. 212 mi::base::Handle<mi::neuraylib::IImport_api> import_api( 213 neuray->get_api_component<mi::neuraylib::IImport_api>()); 214 mi::base::Handle<const mi::neuraylib::IImport_result> import_result( 215 import_api->import_elements( transaction.get(), "${shader}/base.mdl")); 216 check_success( import_result->get_error_number() == 0); 217 } 218 { 219 // Lookup the exact name of the DB element for the MDL function "base::file_texture". 220 mi::base::Handle<const mi::neuraylib::IMdl_module> module( 221 transaction->access<mi::neuraylib::IMdl_module>( "mdl::base")); 222 mi::base::Handle<const mi::IArray> overloads( 223 module->get_function_overloads( "mdl::base::file_texture")); 224 check_success( overloads->get_length() == 1); 225 mi::base::Handle<const mi::IString> file_texture_name( 226 overloads->get_element<mi::IString>( static_cast<mi::Uint32>( 0))); 227 228 // Prepare the arguments of the function call for "mdl::base::file_texture": set the 229 // "texture" argument to the "nvidia_texture" texture. 230 mi::base::Handle<const mi::neuraylib::IMdl_function_definition> function_definition( 231 transaction->access<mi::neuraylib::IMdl_function_definition>( 232 file_texture_name->get_c_str())); 233 mi::base::Handle<mi::neuraylib::IAttribute_container> arguments( 234 transaction->create<mi::neuraylib::IAttribute_container>( "Attribute_container")); 235 mi::base::Handle<mi::IAttachable> texture( arguments->create_attribute<mi::IAttachable>( 236 "texture", function_definition->get_argument_type( "texture"))); 237 mi::base::Handle<mi::IRef> texture_value( texture->get_value<mi::IRef>()); 238 check_success( mi::set_value( texture_value.get(), "nvidia_texture") == 0); 239 240 // Create a function call from the function definition "mdl::base::file_texture" with the 241 // just prepared arguments. 242 mi::Sint32 result; 243 mi::base::Handle<mi::neuraylib::IMdl_function_call> function_call( 244 function_definition->create_function_call( arguments.get(), &result)); 245 check_success( result == 0); 246 function_definition = 0; 247 transaction->store( function_call.get(), "file_texture_call"); 248 } 249 { 250 // Prepare the arguments of the function call for "mdl::base::texture_return.tint": set the 251 // "s" argument to the "file_texture_call" function call. 252 mi::base::Handle<const mi::neuraylib::IMdl_function_definition> function_definition( 253 transaction->access<mi::neuraylib::IMdl_function_definition>( 254 "mdl::base::texture_return.tint(::base::texture_return)")); 255 mi::base::Handle<mi::neuraylib::IAttribute_container> arguments( 256 transaction->create<mi::neuraylib::IAttribute_container>( "Attribute_container")); 257 mi::base::Handle<mi::IAttachable> s( arguments->create_attribute<mi::IAttachable>( 258 "s", function_definition->get_argument_type( "s"))); 259 check_success( mi::set_value( s.get(), "file_texture_call") == 0); 260 261 // Create a function call from the function definition "mdl::base::file_texture" with the 262 // just prepared arguments. 263 mi::Sint32 result; 264 mi::base::Handle<mi::neuraylib::IMdl_function_call> function_call( 265 function_definition->create_function_call( arguments.get(), &result)); 266 check_success( result == 0); 267 transaction->store( function_call.get(), "texture_return.tint_call"); 268 } 269 { 270 // Create a new value for the "tint" argument and set it to the "texture_return.tint_call" 271 // function call. 272 mi::base::Handle<mi::neuraylib::IMdl_material_instance> grey_material( 273 transaction->edit<mi::neuraylib::IMdl_material_instance>( "grey_material")); 274 mi::base::Handle<mi::IAttachable> tint( 275 transaction->create<mi::IAttachable>( grey_material->get_argument_type( "tint"))); 276 check_success( mi::set_value( tint.get(), "texture_return.tint_call") == 0); 277 278 // Set the new value for the "tint" argument of "grey_material". 279 grey_material->set_argument( "tint", tint.get()); 280 } 281 // The same effect as in the preceding code block can alternatively be achieved by using the 282 // helper class Mdl_argument_editor as follows: 283 { 284 // Attach "texture_return.tint_call" to the "tint" argument of "grey_material". 285 mi::neuraylib::Mdl_argument_editor grey_material( 286 transaction.get(), "grey_material", factory.get()); 287 check_success( grey_material.set_attachment( "tint", "texture_return.tint_call") == 0); 288 } 289 290 render_and_export( neuray, transaction, "file:example_mdl_attached_function_call.png"); 291 transaction->commit(); 292 } 293 294 void create_preset( 295 mi::base::Handle<mi::neuraylib::INeuray> neuray, 296 mi::base::Handle<mi::neuraylib::IScope> scope, 297 mi::base::Handle<mi::neuraylib::IFactory> factory) 298 { 299 // Create a transaction. 300 mi::base::Handle<mi::neuraylib::ITransaction> transaction( 301 scope->create_transaction()); 302 check_success( transaction.is_valid_interface()); 303 304 { 305 // Prepare new defaults as clone of the current arguments of "grey material". 306 mi::base::Handle<const mi::neuraylib::IMdl_material_instance> grey_material( 307 transaction->access<mi::neuraylib::IMdl_material_instance>( "grey_material")); 308 mi::base::Handle<mi::neuraylib::IAttribute_container> defaults( 309 transaction->create<mi::neuraylib::IAttribute_container>( "Attribute_container")); 310 mi::Uint32 count = grey_material->get_parameter_count(); 311 for( mi::Uint32 i = 0; i < count; ++i) { 312 mi::base::Handle<const mi::IData> source( grey_material->get_argument( i)); 313 const char* name = grey_material->get_parameter_name( i); 314 mi::base::Handle<mi::IData> target( 315 defaults->create_attribute( name, grey_material->get_argument_type( i))); 316 factory->assign_from_to( source.get(), target.get()); 317 } 318 319 // Create an ::anno::description annotation. 320 mi::base::Handle<mi::neuraylib::IAttribute_container> annotations( 321 transaction->create<mi::neuraylib::IAttribute_container>( "Attribute_container")); 322 mi::base::Handle<mi::IStructure> annotation( 323 annotations->create_attribute<mi::IStructure>( 324 "::anno::description", "String_annotation")); 325 mi::base::Handle<mi::IString> annotation_arg( 326 annotation->get_value<mi::IString>( static_cast<mi::Size>( 0))); 327 annotation_arg->set_c_str( "a textured variant of ::main::diffuse_material"); 328 329 // Set up preset data: an array with a single element of type Preset_data for preset name, 330 // prototype name, new defaults, and the annotation created above. 331 mi::base::Handle<mi::IArray> preset_data( 332 transaction->create<mi::IArray>( "Preset_data[1]")); 333 mi::base::Handle<mi::IStructure> preset( 334 preset_data->get_value<mi::IStructure>( static_cast<mi::Size>( 0))); 335 mi::base::Handle<mi::IString> preset_name( 336 preset->get_value<mi::IString>( "preset_name")); 337 preset_name->set_c_str( "textured_material") ; 338 mi::base::Handle<mi::IString> prototype_name( 339 preset->get_value<mi::IString>( "prototype_name")); 340 prototype_name->set_c_str( "mdl::main::diffuse_material"); 341 check_success( preset->set_value( "defaults", defaults.get()) == 0); 342 check_success( preset->set_value( "annotations", annotations.get()) == 0); 343 344 // Create the preset. 345 mi::base::Handle<mi::neuraylib::IMdl_factory> mdl_factory( 346 neuray->get_api_component<mi::neuraylib::IMdl_factory>()); 347 check_success( 348 mdl_factory->create_presets( transaction.get(), "::presets", preset_data.get()) == 0); 349 } 350 { 351 // Instantiate the preset. 352 mi::base::Handle<const mi::neuraylib::IMdl_material_definition> textured_material_def( 353 transaction->access<mi::neuraylib::IMdl_material_definition>( 354 "mdl::presets::textured_material")); 355 mi::Sint32 result = 0; 356 mi::base::Handle<mi::neuraylib::IMdl_material_instance> textured_material( 357 textured_material_def->create_material_instance( 0, &result)); 358 check_success( result == 0); 359 transaction->store( textured_material.get(), "textured_material"); 360 361 // Attach the instantiated preset to the scene element "ground_instance", thereby 362 // replacing the existing material instance "grey_material" it was created from. 363 mi::base::Handle<mi::neuraylib::IInstance> instance( 364 transaction->edit<mi::neuraylib::IInstance>( "ground_instance")); 365 mi::base::Handle<mi::IArray> material( instance->edit_attribute<mi::IArray>( "material")); 366 check_success( 367 mi::set_value( material.get(), static_cast<mi::Size>( 0), "textured_material") == 0); 368 } 369 { 370 // Export the preset. 371 mi::base::Handle<mi::IArray> elements( transaction->create<mi::IArray>( "String[1]")); 372 mi::base::Handle<mi::IString> element( 373 elements->get_element<mi::IString>( static_cast<mi::Size>( 0))); 374 element->set_c_str( "mdl::presets"); 375 mi::base::Handle<mi::neuraylib::IExport_api> export_api( 376 neuray->get_api_component<mi::neuraylib::IExport_api>()); 377 export_api->export_elements( transaction.get(), "presets.mdl", elements.get()); 378 } 379 380 render_and_export( neuray, transaction, "file:example_mdl_preset.png"); 381 transaction->commit(); 382 } 383 384 void rendering( mi::base::Handle<mi::neuraylib::INeuray> neuray) 385 { 386 // Get the database and the global scope of the database. 387 mi::base::Handle<mi::neuraylib::IDatabase> database( 388 neuray->get_api_component<mi::neuraylib::IDatabase>()); 389 check_success( database.is_valid_interface()); 390 mi::base::Handle<mi::neuraylib::IScope> scope( 391 database->get_global_scope()); 392 393 // Import the scene and render it. 394 import_and_render_original_scene( neuray, scope); 395 396 // Perform various MDL-related modifications, render the scene, and export the image to disk. 397 mi::base::Handle<mi::neuraylib::IFactory> factory( 398 neuray->get_api_component<mi::neuraylib::IFactory>()); 399 modify_material_instance( neuray, scope, factory); 400 create_new_material_instance( neuray, scope, factory); 401 attach_function_call( neuray, scope, factory); 402 create_preset( neuray, scope, factory); 403 } 404 405 int main( int argc, char* argv[]) 406 { 407 // Collect command line parameters 408 if( argc != 2) { 409 std::cerr << "Usage: example_mdl <mdl_path>" << std::endl; 410 keep_console_open(); 411 return EXIT_FAILURE; 412 } 413 const char* mdl_path = argv[1]; 414 415 // Access the neuray library 416 mi::base::Handle<mi::neuraylib::INeuray> neuray( load_and_get_ineuray()); 417 check_success( neuray.is_valid_interface()); 418 419 // Configure the neuray library 420 configuration( neuray, mdl_path); 421 422 // Start the neuray library 423 mi::Sint32 result = neuray->start(); 424 check_start_success( result); 425 426 // Do the actual rendering 427 rendering( neuray); 428 429 // Shut down the neuray library 430 check_success( neuray->shutdown() == 0); 431 neuray = 0; 432 433 // Unload the neuray library 434 check_success( unload()); 435 436 keep_console_open(); 437 return EXIT_SUCCESS; 438 }