Iray Programmer's Manual

Editing and creating materials

This topic introduces:
  1. typical MDL-related tasks such as modifying inputs of material instances, creating new material instances, and attaching function calls to material inputs:
  2. 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:

  1. 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.
  2. 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.
  3. 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:

  1. Create the necessary database elements of type mi::neuraylib::IImage and mi::neuraylib::ITexture, which will hold the texture to be used.
  2. Import the MDL module base, which contains the MDL function mdl::base::file_texture to be used.
  3. 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.
  4. 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.
  5. The function definition is instantiated and its s argument is set to the instance of mdl::base::file_texture.
  6. 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 }