This example describes the creation of custom Distiller plugins and how to use them in an application. Distiller plugins implement one or more custom distilling target material(s) to which materials can be distilled.
#include "example_shared.h"
#include "example_shared_dump.h"
#include <chrono>
struct Timing
{
explicit Timing(std::string operation)
: m_operation(operation)
{
m_start = std::chrono::steady_clock::now();
}
~Timing()
{
auto stop = std::chrono::steady_clock::now();
std::chrono::duration<double> elapsed_seconds = stop - m_start;
printf("info: %s time: %.2f ms.\n",
m_operation.c_str(),
elapsed_seconds.count() * 1000);
}
private:
std::string m_operation;
std::chrono::steady_clock::time_point m_start;
};
const std::string& module_qualified_name,
const std::string& material_simple_name)
{
mdl_impexp_api->
load_module(transaction, module_qualified_name.c_str(), context);
if (!print_messages(context))
exit_failure("Loading module '%s' failed.", module_qualified_name.c_str());
if (!module)
exit_failure("Failed to access the loaded module.");
std::string material_db_name
= std::string(module_db_name->get_c_str()) + "::" + material_simple_name;
material_db_name = mi::examples::mdl::add_missing_material_signature(
module.get(), material_db_name);
if (material_db_name.empty())
exit_failure("Failed to find the material %s in the module %s.",
material_simple_name.c_str(), module_qualified_name.c_str());
if (!material_definition)
exit_failure("Accessing definition '%s' failed.", material_db_name.c_str());
material_definition->create_function_call(0, &result);
if (result != 0)
exit_failure("Instantiating '%s' failed.", material_db_name.c_str());
return material_instance;
}
bool class_compilation)
{
Timing timing("Compiling");
material_instance2->create_compiled_material(flags, context);
check_success(print_messages(context));
return compiled_material;
}
const char* target_model)
{
distiller_api->
distill_material(compiled_material, target_model,
nullptr, &result));
std::cerr << "result: " << result << "\n";
check_success(result == 0);
distilled_material->retain();
return distilled_material.get();
}
static void usage(const char *name)
{
std::cout
<< "usage: " << name << " [options] [<material_name1> ...]\n"
<< "-h print this text\n"
<< "--material_file <file> file containing fully qualified names of materials to distill\n"
<< "--module <module_name> distill all materials from the module, can occur multiple times\n"
<< "--mdl_path <path> mdl search path, can occur multiple times.\n"
<< "--dump-original-material dump structure of distilled material\n"
<< "--dump-distilled-material dump structure of distilled material\n";
exit(EXIT_FAILURE);
}
void load_materials_from_file(const std::string & material_file, std::vector<std::string> & material_names)
{
std::fstream file;
file.open(material_file, std::fstream::in);
if (!file)
{
std::cout << "Invalid file: " + material_file;
return;
}
std::string fn;
while (getline(file, fn))
{
material_names.emplace_back(fn);
}
file.close();
}
void load_materials_from_modules(
, const std::vector<std::string> & module_names
, std::vector<std::string> & material_names)
{
for (auto module_name : module_names)
{
if (module_name.find("::") != 0)
{
module_name = std::string("::") + module_name;
}
check_success(rtn == 0 || rtn == 1);
check_success(module.is_valid_interface());
mi::Size material_count = module->get_material_count();
for (
mi::Size i = 0; i < material_count; i++)
{
std::string mname(module->get_material(i));
material_names.push_back(material->get_mdl_name());
}
}
}
int MAIN_UTF8(int argc, char* argv[])
{
std::string target_model = "mini_glossy";
std::vector<std::string> material_names;
std::vector<std::string> module_names;
std::string material_file;
bool dump_distilled_material = false;
bool dump_original_material = false;
Timing timing("Elapsed");
mi::examples::mdl::Configure_options configure_options;
for (int i = 1; i < argc; ++i) {
const char *opt = argv[i];
if (opt[0] == '-') {
if (strcmp(opt, "--mdl_path") == 0) {
if (i < argc - 1)
configure_options.additional_mdl_paths.push_back(argv[++i]);
else
usage(argv[0]);
}
else if (strcmp(opt, "--material_file") == 0) {
if (i < argc - 1)
material_file = argv[++i];
else
usage(argv[0]);
}
else if (strcmp(opt, "--module") == 0) {
if (i < argc - 1)
module_names.emplace_back(argv[++i]);
else
usage(argv[0]);
}
else if (strcmp(opt, "--dump-distilled-material") == 0) {
dump_distilled_material = true;
}
else if (strcmp(opt, "--dump-original-material") == 0) {
dump_original_material = true;
}
else
usage(argv[0]);
}
else
material_names.push_back(opt);
}
if (!material_file.empty())
load_materials_from_file(material_file, material_names);
if (!neuray.is_valid_interface())
exit_failure("Failed to load the SDK.");
if (!mi::examples::mdl::configure(neuray.get(), configure_options))
exit_failure("Failed to initialize the SDK.");
if (mi::examples::mdl::load_plugin(neuray.get(),
exit_failure("Failed to load the 'distilling_target_plugin' plugin.");
if (ret != 0)
exit_failure("Failed to initialize the SDK. Result code: %d", ret);
{
if (!module_names.empty())
{
load_materials_from_modules(mdl_factory.get(), transaction.get(), mdl_impexp_api.get(), module_names, material_names);
}
if (material_names.empty())
{
material_names.push_back(
"::nvidia::sdk_examples::tutorials_distilling::example_distilling3");
}
for (const auto& m : material_names)
{
std::string module_qualified_name, material_simple_name;
if (!mi::examples::mdl::parse_cmd_argument_material_name(
m, module_qualified_name, material_simple_name, true))
exit_failure();
create_material_instance(
mdl_factory.get(),
transaction.get(),
mdl_impexp_api.get(),
context.get(),
module_qualified_name,
material_simple_name));
compile_material_instance(instance.get(), context.get(), false));
if (dump_original_material) {
std::cout << "[[ Original material: " << m << " ]]\n";
mi::examples::mdl::dump_compiled_material(transaction.get(),
mdl_factory.get(),
compiled_material.get(),
std::cout);
}
if (!distilling_api.is_valid_interface()) {
exit_failure("Failed to obtain distiller component.");
}
create_distilled_material(
distilling_api.get(),
compiled_material.get(),
target_model.c_str()));
if (dump_distilled_material) {
std::cout << "[[ Distilled material: " << m << " (distilled to " <<
target_model << ") ]]\n";
mi::examples::mdl::dump_compiled_material(transaction.get(),
mdl_factory.get(),
distilled_material.get(),
std::cout);
}
}
}
if (neuray->shutdown() != 0)
exit_failure("Failed to shutdown the SDK.");
neuray = nullptr;
if (!mi::examples::mdl::unload())
exit_failure("Failed to unload the SDK.");
exit_success();
}
COMMANDLINE_TO_UTF8
Handle class template for interfaces, automatizing the lifetime control via reference counting.
Definition: handle.h:113
This interface represents a compiled material.
Definition: icompiled_material.h:97
This interface is used to interact with the distributed database.
Definition: idatabase.h:289
This interface represents a function call.
Definition: ifunction_call.h:52
This interface represents a function definition.
Definition: ifunction_definition.h:44
This interface represents a material instance.
Definition: imaterial_instance.h:34
@ CLASS_COMPILATION
Selects class compilation instead of instance compilation.
Definition: imaterial_instance.h:41
@ DEFAULT_OPTIONS
Default compilation options (e.g., instance compilation).
Definition: imaterial_instance.h:40
Provides access to various functionality related to MDL distilling.
Definition: imdl_distiller_api.h:47
virtual ICompiled_material * distill_material(const ICompiled_material *material, const char *target, const IMap *distiller_options=0, Sint32 *errors=0) const =0
Distills a material.
The execution context can be used to query status information like error and warning messages concern...
Definition: imdl_execution_context.h:131
Factory for various MDL interfaces and functions.
Definition: imdl_factory.h:53
virtual IMdl_execution_context * create_execution_context()=0
Creates an execution context.
virtual const IString * get_db_module_name(const char *mdl_name)=0
Returns the DB name for the MDL name of a module (or file path for MDLE modules).
API component for MDL related import and export operations.
Definition: imdl_impexp_api.h:43
virtual Sint32 load_module(ITransaction *transaction, const char *argument, IMdl_execution_context *context=0)=0
Loads an MDL module from disk (or a builtin module) into the database.
This interface represents an MDL module.
Definition: imodule.h:634
A transaction provides a consistent view on the database.
Definition: itransaction.h:82
virtual const base::IInterface * access(const char *name)=0
Retrieves an element from the database.
virtual Sint32 commit()=0
Commits the transaction.
#define MI_BASE_DLL_FILE_EXT
The operating system specific default filename extension for shared libraries (DLLs)
Definition: config.h:340
virtual const IInterface * get_interface(const Uuid &interface_id) const =0
Acquires a const interface from another.
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
signed int Sint32
32-bit signed integer.
Definition: types.h:46
#include "pch.h"
#include <string>
#include <iostream>
#include "distilling_target_plugin.h"
#include "distilling_target_plugin_rules.h"
namespace MI {
namespace DIST {
static const char* s_targets[] = {
"mini_glossy"
};
template<typename T, size_t n>
inline size_t dimension_of(T (&c)[n]) { return n; }
{
g_logger->
message( severity,
"DISTILLER:COMPILER", message);
}
std::string message = "Plugin \"";
message += MI_DISTILLER_PLUGIN_NAME;
message += "\" initialized";
return true;
}
bool Distilling_target_plugin::exit() {
g_logger = 0;
return true;
}
mi::Size Distilling_target_plugin::get_target_count()
const {
return dimension_of( s_targets);
}
const char* Distilling_target_plugin::get_target_name(
mi::Size index)
const {
return (index < dimension_of( s_targets)) ? s_targets[index] : nullptr;
}
mi::Size Distilling_target_plugin::get_required_module_count(
mi::Size target_index)
const {
return 0;
}
const char *Distilling_target_plugin::get_required_module_code(
mi::Size target_index,
mi::Size index)
const {
return nullptr;
}
const char *Distilling_target_plugin::get_required_module_name(
mi::Size target_index,
mi::Size index)
const {
return nullptr;
}
{
if ( (!material_instance) || (!options) || (target_index >= get_target_count())) {
return nullptr;
}
#define CHECK_RESULT if(error != 0) { return NULL; }
switch ( target_index) {
case 0:
{
Make_simple_rules make_simple;
CHECK_RESULT;
break;
}
}
#undef CHECK_RESULT
res->retain();
}
return nullptr;
}
extern "C"
MI_DLL_EXPORT
void* mi_plugin_factory(
void* context)
{
#if 1
if( index > 0)
return 0;
return new Distilling_target_plugin();
#else
return 0;
#endif
}
}
}
The ILogger interface class supports logging of messages.
Definition: ilogger.h:194
Options class to hold all parameters for algorithm and rule customizations.
Definition: mdl_distiller_options.h:15
The rule engine handles the transformation of a compiled material by a rule set.
Definition: mdl_distiller_plugin_api.h:30
virtual IMaterial_instance * apply_rules(IMaterial_instance const *inst, IRule_matcher &matcher, IRule_matcher_event *event_handler, const Distiller_options *options, mi::Sint32 &error)=0
Apply rules using a strategy.
An instantiated material.
Definition: mdl_generated_dag.h:1383
An interface for reporting rule matcher events.
Definition: mdl_distiller_rules.h:139
Handle<Interface> make_handle_dup(Interface *iptr)
Converts passed-in interface pointer to a handle, without taking interface over.
Definition: handle.h:439
Interface * get() const
Access to the interface. Returns 0 for an invalid interface.
Definition: handle.h:294
bool is_valid_interface() const
Returns true if the interface is valid.
Definition: handle.h:291
Message_severity
Constants for possible message severities.
Definition: enums.h:31
std::basic_ostream<C, T> & error(std::basic_ostream<C, T> &ostream)
Manipulator for mi::base::Log_stream.
Definition: ilogger.h:542
virtual void message(Message_severity level, const char *module_category, const char *message)
Emits a message to the application's log.
Definition: ilogger.h:215
@ MESSAGE_SEVERITY_INFO
This is a normal operational message.
Definition: enums.h:39
Color log(const Color &c)
Returns a color with elementwise natural logarithm of the color c.
Definition: color.h:689
Logger interface class that supports message logging.
/******************************************************************************
* Copyright 2024 NVIDIA Corporation. All rights reserved.
*****************************************************************************/
/// \file distilling_target_plugin_rules.mdltl
/// \brief Rule sets for the distilling custom target rules example.
///
//*****************************************************************************
// Rules to reduce an MDL expression to a 'simple' subset of
// distribution functions called 'mini_glossy'.
rules Make_simple_rules topdown { // bottomup would work too
import math;
// Alternative BSDFs for glossy interactions are replaced by a
// simple glossy BSDF.
microfacet_beckmann_smith_bsdf(ru,rv,tint,_,t,mode) -->
simple_glossy_bsdf( ru,rv,tint,color(0.0),t,mode) repeat_rules;
microfacet_beckmann_vcavities_bsdf(ru,rv,tint,_,t,mode) -->
simple_glossy_bsdf( ru,rv,tint,color(0.0),t,mode) repeat_rules;
microfacet_ggx_smith_bsdf(ru,rv,tint,_,t,mode) -->
simple_glossy_bsdf( ru,rv,tint,color(0.0),t,mode) repeat_rules;
microfacet_ggx_vcavities_bsdf(ru,rv,tint,_,t,mode) -->
simple_glossy_bsdf( ru,rv,tint,color(0.0),t,mode) repeat_rules;
ward_geisler_moroder_bsdf(ru,rv,tint,_,t) -->
simple_glossy_bsdf( ru,rv,tint,color(0.0),t) repeat_rules;
backscattering_glossy_reflection_bsdf(ru,rv,tint,_,t,handle) -->
simple_glossy_bsdf(ru,rv,tint,color(0.0),t,scatter_reflect,handle);
sheen_bsdf(r,tint,tintt,_,handle) -->
simple_glossy_bsdf(r,r,tint,tintt,state::texture_tangent_u(0),scatter_reflect,handle);
// Measured BSDF nodes are replaced by an invalid bsdf()
measured_bsdf(_) --> bsdf();
// Thin-film modifier is simply removed.
thin_film(_,_,base) --> base repeat_rules;
// Directional factor BSDFs are replaced by a fresnel layer (or
// just the base BSDF), using a helper function from the
// ::nvidia::distilling_support module for the IOR.
bsdf_directional_factor(tint_n,tint_g,_,base) -->
fresnel_layer( nvidia::distilling_support::float_ior_from_refl(tint_n), 1.0,
bsdf_tint( tint_g, base), bsdf());
fresnel_factor(ior,k,base) -->
bsdf_tint(nvidia::distilling_support::refl_from_ior_k(ior,k),base);
// Measured curve factor and measured factor BSDFs are removed.
measured_curve_factor(_,base) --> base repeat_rules;
measured_factor(_,base) --> base repeat_rules;
// Mixers are simplified to normalized mixers.
bsdf_clamped_mix_1(w1,df1) --> bsdf_mix_1(w1,df1);
bsdf_clamped_mix_2(w1,df1,w2,df2) --> bsdf_mix_2(w1,df1,w2,df2);
bsdf_clamped_mix_3(w1,df1,w2,df2,w3,df3) --> bsdf_mix_3(w1,df1,w2,df2,w3,df3);
bsdf_unbounded_mix_1(w1,df1) --> bsdf_mix_1(w1,df1);
bsdf_unbounded_mix_2(w1,df1,w2,df2) --> bsdf_mix_2(w1,df1,w2,df2);
bsdf_unbounded_mix_3(w1,df1,w2,df2,w3,df3) --> bsdf_mix_3(w1,df1,w2,df2,w3,df3);
bsdf_color_clamped_mix_1(w1,df1) --> bsdf_color_mix_1(w1,df1);
bsdf_color_clamped_mix_2(w1,df1,w2,df2) --> bsdf_color_mix_2(w1,df1,w2,df2);
bsdf_color_clamped_mix_3(w1,df1,w2,df2,w3,df3) --> bsdf_color_mix_3(w1,df1,w2,df2,w3,df3);
bsdf_color_unbounded_mix_1(w1,df1) --> bsdf_color_mix_1(w1,df1);
bsdf_color_unbounded_mix_2(w1,df1,w2,df2) --> bsdf_color_mix_2(w1,df1,w2,df2);
bsdf_color_unbounded_mix_3(w1,df1,w2,df2,w3,df3) --> bsdf_color_mix_3(w1,df1,w2,df2,w3,df3);
// Curve layers are also reduced to more simple constructions
// using tint BSDFs, fresnel layers and calls to helper functions.
custom_curve_layer(refl_n,refl_g,_,w,layer,base,n) -->
fresnel_layer( nvidia::distilling_support::float_ior_from_refl(refl_n), w,
bsdf_tint( color(refl_g), layer), base, n);
color_custom_curve_layer(refl_n,refl_g,_,w,layer,base,n) -->
color_fresnel_layer( nvidia::distilling_support::ior_from_refl(refl_n), w,
bsdf_tint( refl_g, layer), base, n);
measured_curve_layer(_,w,layer,base,n) -->
fresnel_layer( 1.5, w, layer, base, n);
color_measured_curve_layer(_,w,layer,base,n) -->
color_fresnel_layer( color(1.5), w, layer, base, n);
}