Material Definition Language API nvidia_logo_transpbg.gif Up
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Example for Function Calls
[Previous] [Up] [Next]

This example uses function calls to create a textured material.

New Topics

  • Rationale for expressions vs values
  • Creating a textured material

Detailed Description

Rationale for expressions vs values


Arguments of material instances and function calls are not values, but expressions. For example, the argument for the "tint" parameter in the previous example is an instance of mi::neuraylib::IExpression, and not of mi::neuraylib::IValue_color. Why is this indirection needed?

If material instances and function calls are only used in isolation, simple values like mi::neuraylib::IValue_color would be sufficient. However, much of the flexibility of MDL comes from the fact that one can create connections between material instances and function calls (provided the return type and the parameter type match). These connections are represented by call expressions while simple values are represented by constant expressions.

Creating a textured material


The method create_texture_material() shows all the steps needed to create a textured material in a bottom-up order. First we create a DB element of type mi::neuraylib::IImage that represents the provided .png file, and a DB element of type mi::neuraylib::ITexture that references the image.

Next we load the MDL modules we want to use. The example module contains the material definition that we are going to use later. The base module contains a function definition that we are using in the next step to make use of the texture.

The function definition base::file_texture() is used to access the texture object in the DB. Apart from the texture name it provides several arguments to influence the texture lookup process. In this example we just set the texture name and leave the other arguments at their defaults. This step uses mi::neuraylib::IModule::get_function_overloads() to retrieve the exact name of a function definition (which includes the signature). Using this method frees one from hardcoding the signature if there is only one overload.

The return type of the function definition base::file_texture() is base::texture_return, a struct of two fields: "tint" of type mi::neuraylib::IType_color and "mono" of type mi::neuraylib::IType_float. Since the material definition we plan to use has a parameter of type mi::neuraylib::IType_color we cannot directly attach the function call of base::file_texture(). Instead we have to isolate the "tint" field in the returned struct. This can be done by a so-called member selection operator (see Structs for details). In this case, the name of the required struct getter is base::texture_return.tint().

Finally, we connect the just created instance of the member selection operator to the "tint" argument of our diffuse material. The dump of the material instance and all function calls clearly shows the created call expressions.

Example Source

Source Code Location: examples/mdl_sdk/calls/example_calls.cpp

/******************************************************************************
* Copyright 2020 NVIDIA Corporation. All rights reserved.
*****************************************************************************/
// examples/mdl_sdk/calls/example_calls.cpp
//
// Uses function calls to create a textured material.
#include <iostream>
#include <string>
#include "example_shared.h"
// Utility function to dump the arguments of a material instance or function call.
template <class T>
void dump_instance(
mi::neuraylib::IExpression_factory* expression_factory, const T* material, std::ostream& s)
{
mi::Size count = material->get_parameter_count();
mi::base::Handle<const mi::neuraylib::IExpression_list> arguments( material->get_arguments());
for( mi::Size index = 0; index < count; index++) {
arguments->get_expression( index));
std::string name = material->get_parameter_name( index);
expression_factory->dump( argument.get(), name.c_str(), 1));
s << " argument " << argument_text->get_c_str() << std::endl;
}
s << std::endl;
}
// Creates a textured material.
void create_textured_material( mi::neuraylib::INeuray* neuray)
{
mi::base::Handle<mi::neuraylib::IScope> scope( database->get_global_scope());
mi::base::Handle<mi::neuraylib::ITransaction> transaction( scope->create_transaction());
mdl_factory->create_value_factory( transaction.get()));
mdl_factory->create_expression_factory( transaction.get()));
mdl_factory->create_execution_context());
{
// Create a DB element for the image and the texture referencing it.
transaction->create<mi::neuraylib::IImage>( "Image"));
check_success( image->reset_file( "nvidia/sdk_examples/resources/example.png") == 0);
transaction->store( image.get(), "nvidia_image");
transaction->create<mi::neuraylib::ITexture>( "Texture"));
texture->set_image( "nvidia_image");
transaction->store( texture.get(), "nvidia_texture");
}
{
// Import the "::nvidia::sdk_examples::tutorials" and "base" module.
// The "::nvidia::sdk_examples::tutorials" module is found via the
// configured module search path.
check_success( mdl_impexp_api->load_module(
transaction.get(), "::nvidia::sdk_examples::tutorials", context.get()) >= 0);
check_success( print_messages( context.get()));
check_success( mdl_impexp_api->load_module(
transaction.get(), "::base", context.get()) >= 0);
check_success( print_messages( context.get()));
}
{
// Lookup the exact name of the DB element for the MDL function "base::file_texture".
transaction->access<mi::neuraylib::IModule>( "mdl::base"));
module->get_function_overloads( "mdl::base::file_texture"));
check_success( overloads->get_length() == 1);
overloads->get_element<mi::IString>( static_cast<mi::Uint32>( 0)));
// Prepare the arguments of the function call for "mdl::base::file_texture": set the
// "texture" argument to the "nvidia_texture" texture.
file_texture_name->get_c_str()));
function_definition->get_parameter_types());
mi::base::Handle<const mi::neuraylib::IType> arg_type( types->get_type( "texture"));
check_success( arg_type.is_valid_interface());
value_factory->create<mi::neuraylib::IValue_texture>( arg_type.get()));
check_success( arg_value.is_valid_interface());
check_success( arg_value->set_value( "nvidia_texture") == 0);
expression_factory->create_constant( arg_value.get()));
expression_factory->create_expression_list());
arguments->add_expression( "texture", arg_expr.get());
// Create a function call from the function definition "mdl::base::file_texture" with the
// just prepared arguments.
mi::Sint32 result;
function_definition->create_function_call( arguments.get(), &result));
check_success( result == 0);
transaction->store( function_call.get(), "call of file_texture");
}
{
// Prepare the arguments of the function call for "mdl::base::texture_return.tint": set the
// "s" argument to the "call of file_texture" function call.
expression_factory->create_call( "call of file_texture"));
check_success( arg_expr.is_valid_interface());
expression_factory->create_expression_list());
arguments->add_expression( "s", arg_expr.get());
// Create a function call from the function definition "mdl::base::file_texture" with the
// just prepared arguments.
"mdl::base::texture_return.tint(::base::texture_return)"));
mi::Sint32 result;
function_definition->create_function_call( arguments.get(), &result));
check_success( result == 0);
transaction->store( function_call.get(), "call of texture_return.tint");
}
{
// Prepare the arguments of the material instance for
// "mdl::nvidia::sdk_examples::tutorials::example_material":
// set the "tint" argument to the "call of texture_return.tint" function call.
expression_factory->create_call( "call of texture_return.tint"));
check_success( arg_expr.is_valid_interface());
expression_factory->create_expression_list());
arguments->add_expression( "tint", arg_expr.get());
// Create a material instance from the material definition
// "mdl::nvidia::sdk_examples::tutorials::example_material"
// with the just prepared arguments.
"mdl::nvidia::sdk_examples::tutorials::example_material"));
mi::Sint32 result;
material_definition->create_material_instance( arguments.get(), &result));
check_success( result == 0);
transaction->store( material_instance.get(), "instance of example_material");
}
{
// Dump the created material instance and function calls.
transaction->access<mi::neuraylib::IMaterial_instance>(
"instance of example_material"));
std::cout << "Dumping material instance \"instance of example_material\":" << std::endl;
dump_instance( expression_factory.get(), material_instance.get(), std::cout);
transaction->access<mi::neuraylib::IFunction_call>(
"call of texture_return.tint"));
std::cout << "Dumping function call \"call of texture_return.tint\":" << std::endl;
dump_instance( expression_factory.get(), function_call.get(), std::cout);
function_call = transaction->access<mi::neuraylib::IFunction_call>(
"call of file_texture");
std::cout << "Dumping function call \"call of file_texture\":" << std::endl;
dump_instance( expression_factory.get(), function_call.get(), std::cout);
}
transaction->commit();
}
int MAIN_UTF8( int argc, char* argv[])
{
// Access the MDL SDK
mi::base::Handle<mi::neuraylib::INeuray> neuray(mi::examples::mdl::load_and_get_ineuray());
if (!neuray.is_valid_interface())
exit_failure("Failed to load the SDK.");
// Configure the MDL SDK
if (!mi::examples::mdl::configure(neuray.get()))
exit_failure("Failed to initialize the SDK.");
// Start the MDL SDK
mi::Sint32 ret = neuray->start();
if (ret != 0)
exit_failure("Failed to initialize the SDK. Result code: %d", ret);
// Create a textured material
create_textured_material( neuray.get());
// Shut down the MDL SDK
if (neuray->shutdown() != 0)
exit_failure("Failed to shutdown the SDK.");
// Unload the MDL SDK
neuray = nullptr;
if (!mi::examples::mdl::unload())
exit_failure("Failed to unload the SDK.");
exit_success();
}
// Convert command line arguments to UTF8 on Windows
COMMANDLINE_TO_UTF8
[Previous] [Up] [Next]