#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <fstream>
#include <thread>
#include <set>
#include "example_shared.h"
#include "example_distilling_shared.h"
#include "example_cuda_shared.h"
#include "example_distilling_unity.h"
float RADINV2[] = { 0, 0.5f, 0.25f, 0.75f, 0.125f, 0.625f, 0.375f, 0.875f, 0.0625f, 0.5625f, 0.3125f, 0.8125f, 0.1875f, 0.6875f, 0.4375f };
float RADINV3[] = { 0, 0.333333f, 0.666667f, 0.111111f, 0.444444f, 0.777778f, 0.222222f, 0.555556f, 0.888889f, 0.037037f, 0.37037f, 0.703704f, 0.148148f, 0.481481f, 0.814815f };
class Logger;
{
public:
Logger(int level)
{
set_verbosity_level(level);
}
void message(
const char* ,
const char* message)
{
if (level > m_level)
{
return;
}
const char* severity = 0;
switch (level) {
case mi::base::MESSAGE_SEVERITY_FORCE_32_BIT: return;
}
fprintf(stderr, "%s", severity);
fprintf(stderr, "%s", message);
putc('\n', stderr);
#ifdef MI_PLATFORM_WINDOWS
fflush(stderr);
#endif
}
void set_verbosity_level(int level)
{
if (level >= 0 && level <= 6)
{
m_level = level;
}
}
public:
{
}
private:
int m_level = 0;
};
#include <chrono>
#include <string>
struct LoggerTiming
{
explicit LoggerTiming(std::string operation)
: m_operation(operation)
{
m_start = std::chrono::steady_clock::now();
}
~LoggerTiming()
{
auto stop = std::chrono::steady_clock::now();
std::chrono::duration<double> elapsed_seconds = stop - m_start;
std::stringstream strStream;
strStream << "Finished '" << m_operation << "' after " << elapsed_seconds.count()
<< " seconds.";
}
private:
std::string m_operation;
std::chrono::steady_clock::time_point m_start;
};
struct Material_parameter
{
std::string value_type;
std::string bake_path;
Remap_func* remap_func;
Material_parameter() : remap_func(nullptr)
{
}
Material_parameter(
const std::string& value_type,
Remap_func* func = nullptr)
: value_type(value_type)
, remap_func(func)
{
}
};
class Material : public std::map<std::string, Material_parameter>
{
public:
{
if (!m_base_color_map.is_valid_interface())
{
}
m_base_color_map->retain();
return m_base_color_map.get();
}
bool has_base_color_map() const
{
return m_base_color_map.is_valid_interface();
}
{
if(! m_mask_map.is_valid_interface())
{
}
m_mask_map->retain();
return m_mask_map.get();
}
bool has_mask_map() const
{
return m_mask_map.is_valid_interface();
}
Material_parameter * find_parameter(const std::string & name)
{
std::map<std::string, Material_parameter>::iterator it(find(name));
if (it != end())
{
return &(it->second);
}
return NULL;
}
bool is_base_map_parm(const std::string& param_name)
{
return (param_name == "base_color" || param_name == "transparency" || param_name == "opacity");
}
bool is_mask_map_parm(const std::string& param_name)
{
return (param_name == "metallic" || param_name == "roughness");
}
{
if (is_base_map_parm(param_name))
{
return get_base_color_map(image_api, resolution);
}
else if (is_mask_map_parm(param_name))
{
return get_mask_map(image_api, resolution);
}
else
{
Material_parameter * p(find_parameter(param_name));
if (p)
{
return image_api->
create_canvas(p->value_type.c_str(), resolution, resolution);
}
}
return NULL;
}
private:
};
{
the_logger->log(message->get_severity(), message->get_string());
}
}
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)
{
context->
set_option(
"target_type", standard_material_type.get());
material_instance2->create_compiled_material(flags, context);
check_success(print_messages_local(context));
return compiled_material;
}
const char* target_model)
{
distiller_api->
distill_material(compiled_material, target_model,
nullptr, &result));
check_success(result == 0);
distilled_material->retain();
return distilled_material.get();
}
{
if(!canvas)
return;
const mi::Uint32 n = canvas->get_resolution_x() * canvas->get_resolution_y() * 3;
{
data[i] = (data[i] + 1.f) * 0.5f;
}
}
void setup_target_material(
Material& out_material)
{
lookup_call("surface.scattering", cm));
get_call_semantic(transaction, parent_call.get()));
out_material["base_color"] = Material_parameter("Color");
out_material["metallic"] = Material_parameter("Float32");
out_material["specular"] = Material_parameter("Float32");
out_material["roughness"] = Material_parameter("Float32");
out_material["normal"] = Material_parameter("Float32<3>", remap_normal);
out_material["clearcoat_weight"] = Material_parameter("Float32");
out_material["clearcoat_roughness"] = Material_parameter("Float32");
out_material["clearcoat_normal"] = Material_parameter("Float32<3>", remap_normal);
out_material["opacity"] = Material_parameter("Float32");
std::string path_prefix = "surface.scattering.";
out_material["anisotropy"] = Material_parameter("Float32");
out_material["anisotropy_rotation"] = Material_parameter("Float32");
out_material["transparency"] = Material_parameter("Float32");
out_material["transmission_color"] = Material_parameter("Rgb_fp");
out_material["attenuation_color"] = Material_parameter("Rgb_fp");
out_material["attenuation_distance"] = Material_parameter("Float32");
out_material["subsurface_color"] = Material_parameter("Rgb_fp");
out_material["volume_ior"] = Material_parameter("Rgb_fp");
out_material["attenuation_color"].bake_path = "volume.absorption_coefficient.s.v.attenuation";
out_material["subsurface_color"].bake_path = "volume.absorption_coefficient.s.v.subsurface";
out_material["attenuation_distance"].bake_path = "volume.scattering_coefficient.s.v.distance";
out_material["volume_ior"].bake_path = "ior";
{
out_material["clearcoat_weight"].bake_path = path_prefix + "weight";
out_material["clearcoat_roughness"].bake_path = path_prefix + "layer.roughness_u";
out_material["clearcoat_normal"].bake_path = path_prefix + "normal";
parent_call = lookup_call("base", cm, parent_call.get());
semantic = get_call_semantic(transaction, parent_call.get());
path_prefix += "base.";
}
{
out_material["normal"].bake_path = path_prefix + "normal";
parent_call = lookup_call("layer", cm, parent_call.get());
semantic = get_call_semantic(transaction, parent_call.get());
path_prefix += "layer.";
}
{
out_material["metallic"].bake_path = path_prefix + "components.value1.weight";
out_material["roughness"].bake_path = path_prefix + "components.value1.component.roughness_u.s.r.roughness";
out_material["anisotropy"].bake_path = path_prefix + "components.value1.component.roughness_u.s.r.anisotropy";
out_material["anisotropy_rotation"].bake_path = path_prefix + "components.value1.component.roughness_u.s.r.rotation";
out_material["base_color"].bake_path = path_prefix + "components.value1.component.tint";
parent_call = lookup_call(
"components.value0.component", cm, parent_call.get());
semantic = get_call_semantic(transaction, parent_call.get());
path_prefix += "components.value0.component.";
}
{
out_material["specular"].bake_path = path_prefix + "weight";
out_material["roughness"].bake_path = path_prefix + "layer.roughness_u.s.r.roughness";
out_material["anisotropy"].bake_path = path_prefix + "layer.roughness_u.s.r.anisotropy";
out_material["anisotropy_rotation"].bake_path = path_prefix + "layer.roughness_u.s.r.rotation";
parent_call = lookup_call("base", cm, parent_call.get());
semantic = get_call_semantic(transaction, parent_call.get());
path_prefix += "base.";
}
{
out_material["transparency"].bake_path = path_prefix + "components.value1.weight";
out_material["transmission_color"].bake_path = path_prefix + "components.value1.component.tint";
parent_call = lookup_call("components.value0.component", cm, parent_call.get());
semantic = get_call_semantic(transaction, parent_call.get());
path_prefix += "components.value0.component.";
}
if (semantic ==
{
if (out_material["metallic"].bake_path.empty())
out_material["metallic"].value = create_value(transaction, "Float32", 1.0f);
if (out_material["roughness"].bake_path.empty())
out_material["roughness"].bake_path = path_prefix + "roughness_u";
if (out_material["base_color"].bake_path.empty())
out_material["base_color"].bake_path = path_prefix + "tint";
}
else if (semantic ==
{
if (out_material["base_color"].bake_path.empty())
out_material["base_color"].bake_path = path_prefix + "tint";
}
if (cutout.is_valid_interface())
out_material["opacity"].bake_path = "geometry.cutout_opacity";
}
class Function_descriptions : public std::vector<mi::neuraylib::Target_function_description>
{
public:
void add_function(const std::string & parameter_name, const std::string & description)
{
if (!description.empty())
{
m_parms[parameter_name] = description;
}
}
{
for (auto & fd : *this)
{
if (fd.path == description)
{
function_description = fd;
return true;
}
}
return false;
}
{
Parameter_map::const_iterator it(m_parms.find(parameter_name));
if (it != m_parms.end())
{
return get_function_description(it->second, function_description);
}
return false;
}
private:
typedef std::map<std::string, std::string > Parameter_map;
Parameter_map m_parms;
};
class Baker
{
public:
Baker(
, Material& out_material
)
: m_out_material(out_material)
{
init_baker_resource(baker_resource);
init_function_descriptions();
build_baker_programs(material);
}
bool bake(
, bool parallel
) const
{
Parm_list plist;
pre_bake(plist);
if (m_bake_gpu)
{
if (bake_cuda_ptx(image_api, baking_samples, baking_resolution, plist))
{
return true;
}
}
if (m_bake_cpu)
{
if (bake_native(image_api, baking_samples, baking_resolution, plist))
{
return true;
}
}
return false;
}
private:
Function_descriptions m_descs;
Material & m_out_material;
bool m_bake_gpu = false;
bool m_bake_cpu = false;
int m_cuda_device = 0;
private:
struct Parms
{
Parms(const std::string & name, Expression_type expr_type)
: m_name(name), m_expr_type(expr_type)
{}
std::string m_name;
Expression_type m_expr_type = EXT_UNKNOWN;
};
class Parm_list : public std::vector<Parms>
{
std::set<std::string> m_added;
public:
void add_parm(const std::string & name, Expression_type expr_type = EXT_UNKNOWN)
{
if (m_added.find(name) == m_added.end())
{
m_added.insert(name);
emplace_back(Parms(name, expr_type));
}
}
void add_parms(const Material & m)
{
for (const auto & p : m)
{
add_parm(p.first);
}
}
};
void pre_bake(Parm_list & plist) const
{
plist.add_parm("roughness", EXT_ROUGHNESS);
plist.add_parm("metallic", EXT_METALLIC);
plist.add_parm("base_color", EXT_BASE_COLOR);
plist.add_parm("transparency", EXT_TRANSPARENCY);
plist.add_parm("opacity", EXT_OPACITY);
plist.add_parms(m_out_material);
}
private:
bool bake_native(
, const Parm_list& plist
) const
{
auto bake_native_function = [](
size_t index
, Expression_type expr_type
, float metallic
)
{
index * num_rows_per_frag +
((index < num_frags_with_extra_row) ? index : num_frags_with_extra_row));
start_row + num_rows_per_frag - 1 +
((index < num_frags_with_extra_row) ? 1 : 0));
const int max_tex_spaces = 4;
for (int ts = 0; ts < max_tex_spaces; ++ts)
{
}
float* data = static_cast<float*>(tile->get_data());
{
{
pixel_data = pixel;
check_success(num_samples <= 16);
{
for (int ts = 0; ts < max_tex_spaces; ++ts)
{
}
if (code->execute(
function_description.function_index, state,
nullptr,
nullptr, (
mi::Float32*)&pixel.x) != 0)
{
return;
}
pixel_data += pixel;
}
pixel_data /= num_samples;
if (expr_type == EXT_BASE_COLOR)
{
const float gammainv(1 / 2.2f);
pixel_data.x = powf(pixel_data.x, gammainv);
pixel_data.y = powf(pixel_data.y, gammainv);
pixel_data.z = powf(pixel_data.z, gammainv);
pixel_data.w = 1.0f;
}
else if (expr_type == EXT_TRANSPARENCY)
{
mi::Float32*
const pixel = data + (j + i *
static_cast<mi::Size>(tex_width)) * components_per_pixel;
pixel[3] *= 1 - pixel_data.x;
}
else if (expr_type == EXT_OPACITY)
{
mi::Float32*
const pixel = data + (j + i *
static_cast<mi::Size>(tex_width)) * components_per_pixel;
pixel[3] *= pixel_data.x;
}
else if (expr_type == EXT_METALLIC)
{
mi::Float32*
const pixel = data + (j + i *
static_cast<mi::Size>(tex_width)) * components_per_pixel;
pixel[0] = pixel_data.x;
pixel[1] = 1.0f;
}
else if (expr_type == EXT_ROUGHNESS)
{
mi::Float32*
const pixel = data + (j + i *
static_cast<mi::Size>(tex_width)) * components_per_pixel;
pixel[3] = 1 - sqrtf(pixel_data.x);
pixel[1] = 1.0f;
if (metallic > 0)
{
pixel[0] = metallic;
}
}
else
{
}
}
}
};
if (!m_native_code)
{
return false;
}
float metallic(-1);
{
Material_parameter* param = m_out_material.find_parameter("metallic");
if (param && param->bake_path.empty())
{
if (param->value_type == "Float32" && param->value)
{
value->get_value(metallic);
}
}
}
std::set<std::string> base_map_parm = {"base_color", "transparency" , "opacity"};
bool is_base_map_uniform(parms_are_uniform(base_map_parm, m_native_code.
get()));
std::set<std::string> mask_map_parm = {"metallic", "roughness"};
bool is_mask_map_uniform(parms_are_uniform(mask_map_parm, m_native_code.
get()));
for (auto& p : plist)
{
Material_parameter* param = m_out_material.find_parameter(p.m_name);
if (!param)
continue;
if (!m_descs.get_function_description(param->bake_path, function_description))
{
continue;
}
if (m_out_material.is_base_map_parm(p.m_name))
{
uniform = is_base_map_uniform;
}
else if (m_out_material.is_mask_map_parm(p.m_name))
{
uniform = is_mask_map_uniform;
}
if (uniform)
{
samples = 1;
resolution = 1;
}
if (!texture)
continue;
Expression_type expr_type(p.m_expr_type);
const mi::Uint32 tex_width(texture->get_resolution_x());
const mi::Uint32 tex_height(texture->get_resolution_y());
const mi::Size num_fragments(tex_height);
const mi::Size num_rows_per_frag(tex_height / (
int)num_fragments);
const mi::Size num_frags_with_extra_row(tex_height - num_rows_per_frag * (
int)num_fragments);
std::vector<std::thread> threads;
for (size_t index = 0; index < num_fragments; index++)
{
threads.emplace_back(std::thread(
bake_native_function
, index
, num_rows_per_frag
, num_frags_with_extra_row
, tex_width
, texture.get()
, samples
, du
, dv
, function_description
, components_per_pixel
, expr_type
, metallic
));
}
for (auto& t : threads)
{
t.join();
}
if (param->remap_func)
param->remap_func(texture.get());
param->texture = texture;
}
return true;
}
mi::Uint32 get_components_per_pixel(
const std::string & pixel_type)
const
{
if (pixel_type == "Rgb_fp")
{
return 3;
}
else if (pixel_type == "Float32")
{
return 1;
}
else if (pixel_type == "Float32<3>")
{
return 3;
}
else if (pixel_type == "Color")
{
return 4;
}
return 0;
}
bool bake_cuda_ptx(
, const Parm_list & plist
) const
{
auto bake_cuda_ptx_function = [](
, CUdeviceptr & device_outbuf
, CUdeviceptr & device_tc_data_list
, CUdeviceptr & device_arg_block_list
, CUfunction & cuda_function
, Expression_type expr_type
, float metallic
)
{
int num_samples = baking_samples;
size_t function_index(function_description.function_index);
unsigned int cpp(components_per_pixel);
dim3 threads_per_block(16, 16);
dim3 num_blocks((res_x + 15) / 16, (res_y + 15) / 16);
void *kernel_params[] = {
&device_outbuf,
&device_tc_data_list,
&device_arg_block_list,
&res_x,
&res_y,
&num_samples,
&function_index,
&cpp,
&expr_type,
&metallic
};
check_cuda_success(cuLaunchKernel(
cuda_function,
num_blocks.x, num_blocks.y, num_blocks.z,
threads_per_block.x, threads_per_block.y, threads_per_block.z,
0, nullptr, kernel_params, nullptr));
float *data = static_cast<float *>(tile->get_data());
check_cuda_success(cuMemcpyDtoH(
data, device_outbuf, res_x * res_y * sizeof(float) * components_per_pixel));
};
if (!m_gpu_code)
{
return false;
}
CUcontext cuda_context = init_cuda(m_cuda_device);
{
CUfunction cuda_function;
char const *ptx_name = "example_distilling_unity.ptx";
std::vector <mi::base::Handle<const mi::neuraylib::ITarget_code>> target_codes;
target_codes.emplace_back(m_gpu_code);
CUmodule cuda_module = build_linked_kernel(
target_codes,
(mi::examples::io::get_executable_folder() + "/" + ptx_name).c_str(),
"evaluate_mat_expr",
&cuda_function);
std::vector<size_t> arg_block_indices;
for (auto & d : m_descs)
{
arg_block_indices.emplace_back(d.argument_block_index);
}
Material_gpu_context material_gpu_context(false);
for (size_t i = 0, num_target_codes = target_codes.size(); i < num_target_codes; ++i)
{
if (!material_gpu_context.prepare_target_code_data(
m_transaction.
get(), image_api, target_codes[i].get(), arg_block_indices))
{
return false;
}
}
CUdeviceptr device_tc_data_list = material_gpu_context.get_device_target_code_data_list();
CUdeviceptr device_arg_block_list =
material_gpu_context.get_device_target_argument_block_list();
int res_x = baking_resolution;
int res_y = baking_resolution;
CUdeviceptr device_outbuf;
check_cuda_success(cuMemAlloc(&device_outbuf, res_x * res_y * sizeof(float4)));
float metallic(-1);
{
Material_parameter * param = m_out_material.find_parameter("metallic");
if (param && param->bake_path.empty())
{
if (param->value_type == "Float32" && param->value)
{
value->get_value(metallic);
}
}
}
std::set<std::string> base_map_parm = {"base_color", "transparency" , "opacity"};
bool is_base_map_uniform(parms_are_uniform(base_map_parm, m_gpu_code.
get()));
std::set<std::string> mask_map_parm = {"metallic", "roughness"};
bool is_mask_map_uniform(parms_are_uniform(mask_map_parm, m_gpu_code.
get()));
for(auto & p : plist)
{
Material_parameter * param = m_out_material.find_parameter(p.m_name);
if (!param)
continue;
if (!m_descs.get_function_description(param->bake_path, function_description))
{
continue;
}
if (m_out_material.is_base_map_parm(p.m_name))
{
uniform = is_base_map_uniform;
}
else if (m_out_material.is_mask_map_parm(p.m_name))
{
uniform = is_mask_map_uniform;
}
if (uniform)
{
samples = 1;
resolution = 1;
}
if (!texture)
continue;
Expression_type expr_type(p.m_expr_type);
check_success(components_per_pixel > 0 && components_per_pixel <= 4);
bake_cuda_ptx_function(
texture.get()
, baking_samples
, components_per_pixel
, device_outbuf
, device_tc_data_list
, device_arg_block_list
, cuda_function
, function_description
, expr_type
, metallic
);
if (param->remap_func)
param->remap_func(texture.get());
param->texture = texture;
}
check_cuda_success(cuMemFree(device_outbuf));
check_cuda_success(cuModuleUnload(cuda_module));
}
uninit_cuda(cuda_context);
return true;
}
{
switch (baker_resource)
{
m_bake_gpu = true;
break;
m_bake_cpu = true;
break;
m_bake_gpu = true;
m_bake_cpu = true;
break;
default:
break;
}
}
void init_function_descriptions()
{
for (auto & m : m_out_material)
{
Material_parameter& param = m.second;
m_descs.add_function(m.first, param.bake_path);
}
}
)
{
check_success(link_unit.is_valid_interface());
mi::Sint32 result = link_unit->add_material(material, m_descs.data(), m_descs.size(), m_context.
get());
check_success(0 == result);
}
{
if (m_bake_cpu)
{
check_success(backend.is_valid_interface());
m_native_code = build_baker_programs_for_backend_kind(material, backend.get());
}
if (m_bake_gpu)
{
check_success(backend.is_valid_interface());
check_success(backend->
set_option(
"num_texture_spaces",
"1") == 0);
check_success(backend->
set_option(
"tex_lookup_call_mode",
"direct_call") == 0);
check_success(backend->
set_option(
"enable_ro_segment",
"off") == 0);
check_success(backend->
set_option(
"fast_math",
"off") == 0);
m_gpu_code = build_baker_programs_for_backend_kind(material, backend.get());
}
}
{
mi::neuraylib::ITarget_code::State_usage render_state_usage =
return ((render_state_usage &
}
{
for (auto& pname : parms)
{
Material_parameter* param = m_out_material.find_parameter(pname);
if (!param)
continue;
if (!m_descs.get_function_description(param->bake_path, function_description))
{
continue;
}
{
return false;
}
}
return true;
}
};
void bake_target_material_inputs(
, Material& out_material
, bool parallel
)
{
Baker baker(baker_resource, transaction, material, out_material, context, mdl_backend_api);
check_success(baker.bake(image_api, baking_samples, baking_resolution, parallel));
}
class Canvas_exporter
{
bool m_in_parallel = true;
public:
Canvas_exporter(bool parallel)
: m_in_parallel(parallel)
{
}
{
}
{
{
check_success(mdl_impexp_api->
export_canvas(filename, canvas) == 0);
};
std::vector<std::thread> threads;
for (auto & canvas_file : m_canvases)
{
const char * filename(canvas_file.first.c_str());
if (m_in_parallel)
{
threads.emplace_back(
std::thread(export_canvas, filename, canvas)
);
}
else
{
export_canvas(filename, canvas);
}
}
for (auto & t : threads)
{
t.join();
}
}
};
void process_target_material(
const std::string& target_model,
const std::string& material_name,
const Material& material,
bool save_baked_textures,
bool parallel,
{
Canvas_exporter canvas_exporter(parallel);
for(Material::const_iterator it = material.begin();
it != material.end(); ++it)
{
const std::string& param_name = it->first;
const Material_parameter& param = it->second;
bool mask_map(false);
bool base_map(false);
if (param_name == "transparency" && material.has_base_color_map())
{
continue;
}
if (param_name == "opacity" && material.has_base_color_map())
{
continue;
}
if (param_name == "roughness" && material.has_mask_map())
{
continue;
}
if (param_name == "metallic" && material.has_mask_map())
{
mask_map = true;
}
else if (param_name == "base_color" && material.has_base_color_map())
{
base_map = true;
}
std::stringstream log_message;
if(param.texture)
{
bool skip_uniform(false);
if (param.texture->get_resolution_x() == 1 && param.texture->get_resolution_y() == 1)
{
skip_uniform = true;
if (mask_map)
{
log_message << "Mask Map (metallic, ao, detail, smoothness) constant ";
skip_uniform = false;
}
else if (base_map)
{
log_message << "Base Map (base_color, opacity) constant ";
skip_uniform = false;
}
else
{
log_message << param_name << " baked to constant ";
}
param.texture->get_tile()->get_pixel(0, 0, (
mi::Float32*)&pixel_data.x);
std::string type(param.texture->get_type());
if (type == "Rgb_fp")
{
log_message << "color: ("
<< pixel_data[0] << ", " << pixel_data[1] << ", " << pixel_data[2] << ")";
}
else if (type == "Float32")
{
log_message << "float: " << pixel_data[0];
}
else if (type == "Float32<3>")
{
log_message << "vector: ("
<< pixel_data[0] << ", " << pixel_data[1] << ", " << pixel_data[2] << ")";
}
else if (type == "Color")
{
log_message << "color: ("
<< pixel_data[0] << ", " << pixel_data[1] << ", " << pixel_data[2] << ", " << pixel_data[3] << ")";
if (base_map)
{
if (pixel_data[0] >= 0 && pixel_data[0] <= 1 &&
pixel_data[1] >= 0 && pixel_data[1] <= 1 &&
pixel_data[2] >= 0 && pixel_data[2] <= 1)
{
log_message << " (hexadecimal color: "
<< std::setfill('0') << std::setw(2) << std::hex << int(pixel_data[0] * 255)
<< std::setfill('0') << std::setw(2) << std::hex << int(pixel_data[1] * 255)
<< std::setfill('0') << std::setw(2) << std::hex << int(pixel_data[2] * 255) << ")";
}
}
}
else
{
}
if (!log_message.str().empty())
{
}
log_message = std::stringstream();
}
if (save_baked_textures && !skip_uniform)
{
std::stringstream file_name;
if (mask_map)
{
file_name << material_name << "-" << "mask_map" << ".png";
}
else if (base_map)
{
file_name << material_name << "-" << "base_map" << ".png";
}
else
{
file_name << material_name << "-" << param_name << ".png";
}
log_message << param_name << " baked to texture : " << file_name.str();
canvas_exporter.add_canvas(file_name.str(), param.texture.get());
}
}
if (!log_message.str().empty())
{
}
}
canvas_exporter.do_export(impexp_api);
}
static void usage(const char *name)
{
std::cout
<< "usage: " << name << " [options] [<material_name1> ...]\n"
<< "-h print this text\n"
<< "--verbosity verbosity level (0: no messages, 1: fatal, 2: error, 3: warning, 4: info, 5: verbose, 6: debug)\n"
<< "--baker_resource baking device: gpu|cpu|gpu_with_cpu_fallback (default: cpu)\n"
<< "--samples baking samples (default: 4, max: 16)\n"
<< "--resolution baking resolution (default: 1024)\n"
<< "--material_file <file> file containing fully qualified names of materials to distill\n"
<< "--do_not_save_textures if set, avoid saving baked textures to file\n"
<< "--module <module_name> distill all materials from the module, can occur multiple times\n"
<< "--no_parallel do not save texture files in parallel threads\n"
<< "--mdl_path <path> mdl search path, can occur multiple times.\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(std::string(material->get_mdl_module_name()) + "::" + std::string(material->get_mdl_simple_name()));
}
}
}
int MAIN_UTF8(int argc, char* argv[])
{
std::string target_model = "transmissive_pbr";
bool parallel = true;
std::vector<std::string> material_names;
std::vector<std::string> module_names;
std::string material_file;
bool save_baked_textures(true);
the_logger = new Logger(verbosity_level);
mi::examples::mdl::Configure_options configure_options;
configure_options.add_admin_space_search_paths = false;
configure_options.add_user_space_search_paths = false;
configure_options.add_example_search_path = false;
configure_options.logger = the_logger.
get();
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, "--baker_resource") == 0) {
if (i < argc - 1) {
std::string res = argv[++i];
if (res == "gpu")
else if (res == "gpu_with_cpu_fallback")
else if (res != "cpu")
usage(argv[0]);
}
else
usage(argv[0]);
}
else if (strcmp(opt, "--samples") == 0) {
if (i < argc - 1)
{
int val(atoi(argv[++i]));
if (val > 0 && val <= 16)
baking_samples = val;
else
std::cout << "Invalid number of samples ignored\n";
}
else
usage(argv[0]);
}
else if (strcmp(opt, "--resolution") == 0) {
if (i < argc - 1)
{
int val(atoi(argv[++i]));
if (val > 0)
baking_resolution = val;
else
std::cout << "Invalid resolution ignored\n";
}
else
usage(argv[0]);
}
else if (strcmp(opt, "--verbosity") == 0) {
if (i < argc - 1)
{
int val(atoi(argv[++i]));
if (val >= 0 && val <= 6)
verbosity_level = val;
else
std::cout << "Invalid verbosity ignored\n";
}
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, "--do_not_save_textures") == 0) {
save_baked_textures = false;
}
else if (strcmp(opt, "--no_parallel") == 0) {
parallel = false;
}
else if (strcmp(opt, "--module") == 0) {
if (i < argc - 1)
module_names.emplace_back(argv[++i]);
else
usage(argv[0]);
}
else
usage(argv[0]);
}
else
material_names.push_back(opt);
}
the_logger->set_verbosity_level(verbosity_level);
if (configure_options.additional_mdl_paths.empty())
configure_options.add_example_search_path = true;
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.");
exit_failure("Failed to load the mdl_distiller plugin.");
if (ret != 0)
exit_failure("Failed to initialize the SDK. Result code: %d", ret);
{
LoggerTiming timing("Load, distill and bake all materials");
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_distilling1");
}
size_t n_materials_done(0);
size_t n_materials_todo(material_names.size());
for (const auto& m : material_names)
{
LoggerTiming timing("Distill and bake");
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(
mdl_factory.get(),
transaction.get(),
instance.get(),
context.get(),
false));
create_distilled_material(
distilling_api.get(),
compiled_material.get(),
target_model.c_str()));
Material out_material;
setup_target_material(
transaction.get(),
distilled_material.get(),
out_material);
bake_target_material_inputs(
baker_resource,
baking_samples,
baking_resolution,
transaction.get(),
distilled_material.get(),
image_api.get(),
out_material,
context.get(),
mdl_backend_api.get(),
parallel);
process_target_material(
target_model,
material_simple_name,
out_material,
save_baked_textures,
parallel,
mdl_impexp_api.get());
n_materials_done++;
std::stringstream strStream;
strStream << "Progress: " << (float(n_materials_done) / n_materials_todo) * 100 << " % (" << n_materials_done << "/" << n_materials_todo << ")";
}
}
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
This interface represents mi::Float32.
Definition: inumber.h:221
A 32-bit unsigned counter with atomic arithmetic, increments, and decrements.
Definition: atom.h:41
Handle class template for interfaces, automatizing the lifetime control via reference counting.
Definition: handle.h:113
The basic extensible interface.
Definition: iinterface.h:103
Mixin class template for deriving interface implementations.
Definition: interface_implement.h:41
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
virtual Uint32 get_resolution_y() const =0
Returns the resolution of the canvas in y direction.
virtual Uint32 get_resolution_x() const =0
Returns the resolution of the canvas in x direction.
Abstract interface for a canvas represented by a rectangular array of tiles.
Definition: icanvas.h:89
virtual const ITile * get_tile(Uint32 layer=0) const =0
Returns the tile for the given layer.
This interface represents a compiled material.
Definition: icompiled_material.h:97
virtual const IExpression * lookup_sub_expression(const char *path) const =0
Looks up a sub-expression of the compiled material.
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
Semantics
All known semantics of functions definitions.
Definition: ifunction_definition.h:54
@ DS_INTRINSIC_DF_MICROFACET_GGX_VCAVITIES_BSDF
The df::microfacet_ggx_vcavities() function.
Definition: ifunction_definition.h:295
@ DS_INTRINSIC_DF_DIFFUSE_REFLECTION_BSDF
The df::diffuse_reflection_bsdf() function.
Definition: ifunction_definition.h:259
@ DS_INTRINSIC_DF_NORMALIZED_MIX
The df::normalized_mix() function.
Definition: ifunction_definition.h:274
@ DS_INTRINSIC_DF_CUSTOM_CURVE_LAYER
The df::custom_curve_layer() function.
Definition: ifunction_definition.h:278
@ DS_INTRINSIC_DF_WEIGHTED_LAYER
The df::weighted_layer() function.
Definition: ifunction_definition.h:276
This interface provides various utilities related to canvases and buffers.
Definition: iimage_api.h:72
virtual ICanvas * create_canvas(const char *pixel_type, Uint32 width, Uint32 height, Uint32 layers=1, bool is_cubemap=false, Float32 gamma=0.0f) const =0
Creates a canvas with given pixel type, resolution, and layers.
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
This interface can be used to obtain the MDL backends.
Definition: imdl_backend_api.h:56
@ MB_NATIVE
Generate native code.
Definition: imdl_backend_api.h:64
@ MB_CUDA_PTX
Generate CUDA PTX code.
Definition: imdl_backend_api.h:61
MDL backends allow to transform compiled material instances or function calls into target code.
Definition: imdl_backend.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
virtual Sint32 set_option(const char *name, const char *value)=0
Sets a string option.
virtual Size get_error_messages_count() const =0
Returns the number of error messages.
virtual Size get_messages_count() const =0
Returns the number of messages.
virtual const IMessage * get_message(Size index) const =0
Returns the message at index or NULL, if no such index exists.
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 IType_factory * create_type_factory(ITransaction *transaction)=0
Returns an MDL type factory for the given transaction.
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 export_canvas(const char *filename, const ICanvas *canvas, const IMap *export_options=0) const =0
Exports a canvas to a file on disk.
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
Represents target code of an MDL backend.
Definition: imdl_backend.h:783
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.
@ SID_MATERIAL
The "::material" struct type.
Definition: itype.h:484
#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.
Handle<Interface> make_handle_dup(Interface *iptr)
Converts passed-in interface pointer to a handle, without taking interface over.
Definition: handle.h:439
Handle<Interface> make_handle(Interface *iptr)
Returns a handle that holds the interface pointer passed in as argument.
Definition: handle.h:428
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
@ MESSAGE_SEVERITY_FATAL
A fatal error has occurred.
Definition: enums.h:33
@ MESSAGE_SEVERITY_DEBUG
This is debug message.
Definition: enums.h:43
@ MESSAGE_SEVERITY_WARNING
A warning has occurred.
Definition: enums.h:37
@ MESSAGE_SEVERITY_INFO
This is a normal operational message.
Definition: enums.h:39
@ MESSAGE_SEVERITY_VERBOSE
This is a more verbose message.
Definition: enums.h:41
@ MESSAGE_SEVERITY_ERROR
An error has occurred.
Definition: enums.h:35
Uint32 swap(const Uint32 rhs)
Assigns rhs to the counter and returns the old value of counter.
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
float Float32
32-bit float.
Definition: types.h:51
signed int Sint32
32-bit signed integer.
Definition: types.h:46
Color frac(const Color &c)
Returns a color with the elementwise positive fractional part of the color c.
Definition: color.h:625
Color log(const Color &c)
Returns a color with elementwise natural logarithm of the color c.
Definition: color.h:689
math::Vector<Float32, 3> Float32_3
Vector of three Float32.
Definition: vector_typedefs.h:90
virtual const ITarget_code * translate_link_unit(const ILink_unit *lu, IMdl_execution_context *context)=0
Transforms a link unit to target code.
virtual Sint32 set_option(const char *name, const char *value)=0
Sets a backend option.
virtual ILink_unit * create_link_unit(ITransaction *transaction, IMdl_execution_context *context)=0
Creates a new link unit.
Size function_index
The index of the generated function for accessing the callable function information of the link unit ...
Definition: imdl_backend.h:1801
virtual State_usage get_callable_function_render_state_usage(Size index) const =0
Returns the potential render state usage of callable function in the target code.
@ SU_TEXTURE_COORDINATE
uses state::texture_coordinate()
Definition: imdl_backend.h:791
@ SU_POSITION
uses state::position()
Definition: imdl_backend.h:787
Baker_resource
Identifies the resource(s) to be used by a baker.
Definition: imdl_distiller_api.h:30
@ BAKE_ON_CPU
Use only the CPU for texture baking.
Definition: imdl_distiller_api.h:33
@ BAKE_ON_GPU_WITH_CPU_FALLBACK
Prefer using the GPU for texture baking, use the CPU as fallback.
Definition: imdl_distiller_api.h:37
@ BAKE_ON_GPU
Use only the GPU for texture baking.
Definition: imdl_distiller_api.h:35
Common namespace for APIs of NVIDIA Advanced Rendering Center GmbH.
Definition: example_derivatives.dox:5
Structured details to log messages.
Definition: ilogger.h:71
The MDL material state structure inside the MDL SDK is a representation of the renderer state as defi...
Definition: target_code_types.h:210
tct_float3 normal
The result of state::normal().
Definition: target_code_types.h:217
char const * ro_data_segment
A pointer to a read-only data segment.
Definition: target_code_types.h:271
tct_int object_id
The result of state::object_id().
Definition: target_code_types.h:291
traits::tct_derivable_float3 position
The result of state::position().
Definition: target_code_types.h:225
tct_float4 const * world_to_object
A 4x4 transformation matrix in row-major order transforming from world to object coordinates.
Definition: target_code_types.h:278
tct_float3 const * tangent_v
An array containing the results of state::texture_tangent_v(i).
Definition: target_code_types.h:248
tct_float4 const * object_to_world
A 4x4 transformation matrix in row-major order transforming from object to world coordinates.
Definition: target_code_types.h:285
traits::tct_derivable_float3 const * text_coords
An array containing the results of state::texture_coordinate(i).
Definition: target_code_types.h:234
tct_float animation_time
The result of state::animation_time().
Definition: target_code_types.h:229
tct_float3 geom_normal
The result of state::geometry_normal().
Definition: target_code_types.h:221
tct_float3 const * tangent_u
An array containing the results of state::texture_tangent_u(i).
Definition: target_code_types.h:241
tct_float4 * text_results
The texture results lookup table.
Definition: target_code_types.h:256
Description of target function.
Definition: imdl_backend.h:1764