This example loads an X-Rite AxF(Appearance Exchange Format) file and converts it to an equivalent representation in MDL format.
#include "axf_importer_reader.h"
#include "axf_importer_state.h"
#include "axf_importer_clearcoat_brdf_utils.h"
#include "example_shared.h"
#include "utils/strings.h"
#include "utils/ospath.h"
#include <AxF/decoding/AxF_basic_io.h>
#include <AxF/decoding/Sampler.h>
#include <AxF/decoding/TextureDecoder.h>
#include <cassert>
#include <cctype>
#include <sstream>
#include <vector>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef WIN_NT
#include <unistd.h>
#endif
using namespace mi::examples::strings;
using namespace mi::examples::ospath;
namespace examples {
namespace impaxf {
using namespace std;
namespace AXF = axf::decoding;
void Axf_importer::report_message(
const std::string& error_message,
const Axf_impexp_state* import_state)
{
std::ostringstream message;
message << import_state->get_uri()
<< ':' << import_state->get_line_number() << ": "
<< error_message;
printf("%s\n", message.str().c_str());
};
Axf_reader::Axf_reader(
: m_neuray(neuray),
m_transaction(transaction),
m_target_color_space(NULL),
m_glossy_brdf_type(BRDF_TYPE_UNKNOWN),
m_isotropic(true),
m_fresnel_type(FRESNEL_NONE)
{}
namespace {
static const char *s_axf_supported_color_spaces[] = {
AXF_COLORSPACE_CIE_1931_XYZ,
AXF_COLORSPACE_LINEAR_SRGB_E,
AXF_COLORSPACE_LINEAR_ADOBE_RGB_E,
AXF_COLORSPACE_LINEAR_ADOBE_WIDEGAMUT_RGB_E,
AXF_COLORSPACE_LINEAR_PROPHOTO_RGB_E,
NULL
};
static const char *s_prototype_names[3] = {
"mdl::nvidia::axf_importer::axf_importer::svbrdf("
"texture_2d,texture_2d,texture_2d,texture_2d,texture_2d,texture_2d,texture_2d,"
"::nvidia::axf_importer::axf_importer::brdf_type,bool,"
"::nvidia::axf_importer::axf_importer::fresnel_type,texture_2d,bool,texture_2d,texture_2d,"
"texture_2d,::base::texture_coordinate_info,bool,float,float,float,float,float,float,"
"::tex::wrap_mode,float,float3,float,texture_2d,texture_2d,texture_2d,texture_2d,"
"texture_2d,texture_2d)",
"mdl::nvidia::axf_importer::axf_importer::carpaint(color[brdf_colors_size],float,float,float,"
"float,float3,float3,float3,texture_2d,::base::texture_coordinate_info,bool,float,float,"
"float,float,float,float,::tex::wrap_mode,float3,bool,float3,"
"int[flake_importace_data_size],float,float,float,float,bool,bsdf_measurement,"
"float[flake_orientation_falloff_size],texture_2d,bool)",
"mdl::nvidia::axf_importer::axf_importer::volumetric(color,color,float,float)"
};
static void compute_spectral_texture_metadata(
std::vector<char> &meta_data_buf,
const std::vector<float> &wavelengths)
{
const size_t num_lambda = wavelengths.size();
std::vector<float> matrix(num_lambda * num_lambda, 0.0f);
for (unsigned int i = 0; i < num_lambda; ++i) {
matrix[i * num_lambda + i] = 1.0f;
}
const size_t meta_data_size = sizeof(Texture_spectral_metadata) +
(matrix.size() - 1) * sizeof(float);
meta_data_buf.resize(meta_data_size);
Texture_spectral_metadata *meta_data =
(Texture_spectral_metadata *)meta_data_buf.data();
memcpy(
meta_data->marker,
TEXTURE_SPECTRAL_METADATA_MARKER, TEXTURE_SPECTRAL_METADATA_MARKER_SIZE);
meta_data->lambda_min = wavelengths[0];
meta_data->lambda_max = wavelengths[num_lambda - 1];
meta_data->num_lambda = num_lambda;
memcpy(meta_data->matrix, matrix.data(), matrix.size() * sizeof(float));
}
static size_t compute_num_spectral_meta_layers(
size_t &offset0,
const size_t layer_size_bytes,
const size_t num_layers,
const size_t meta_data_size)
{
offset0 = num_layers * layer_size_bytes;
if (offset0 % 4)
offset0 = 4 - (offset0 % 4);
else
offset0 = 0;
return (meta_data_size + offset0 + layer_size_bytes - 1) / layer_size_bytes;
}
static void expand_spectrum(std::vector<float> &spectrum)
{
#if 1
return;
#else
const int num = (int)spectrum.size();
int idx = -1;
for (int i = 0; i < num; ++i)
if (spectrum[i] > 0.0f) {
idx = i;
break;
}
for (int i = 0; i < idx; ++i)
spectrum[i] = spectrum[idx];
idx = num;
for (int i = num - 1; i >= 0; --i)
if (spectrum[i] > 0.0f) {
idx = i;
break;
}
for (int i = num - 1; i > idx; --i)
spectrum[i] = spectrum[idx];
#endif
}
struct Scope_axf_file_handler
{
Scope_axf_file_handler(AXF::AXF_FILE_HANDLE file) : m_axf_file(file) {}
~Scope_axf_file_handler() { if (m_axf_file) AXF::axfCloseFile(&m_axf_file); }
AXF::AXF_FILE_HANDLE m_axf_file;
};
template <typename T>
class Scope_handler
{
public:
Scope_handler(T* inst) : m_inst(inst) {}
~Scope_handler() { T::destroy(&m_inst); }
operator bool() const { return m_inst != 0; }
T* operator->() { return m_inst; }
const T* operator->() const { return m_inst; }
T* get() { return m_inst; }
const T* get() const { return m_inst; }
private:
T* m_inst;
};
bool is_file(
const char* const path)
{
struct stat buf;
if (::stat(path, &buf) == 0)
return (buf.st_mode & S_IFREG) != 0;
return false;
}
string get_axf_texture_prefix() { return "__AxF_imported_tex_"; }
string get_axf_image_prefix() { return "__AxF_imported_img_"; }
string get_axf_pimage_prefix() { return "__AxF_imported_pimg_"; }
string get_axf_mbsdf_prefix() { return "__AxF_imported_mbsdf__"; }
string get_axf_spectrum_prefix() { return "__AxF_imported_spectrum__"; }
}
bool Axf_reader::read(
const char* file_name,
Axf_impexp_state* impexp_state)
{
AXF::axfDisableLogging();
const char *cs = impexp_state->get_target_color_space();
for (int i = 0; ; ++i) {
const char *s = s_axf_supported_color_spaces[i];
if (!s) {
const string msg = string("Unsupported target color space \"") + cs
+ string("\", defaulting to \"" AXF_COLORSPACE_LINEAR_SRGB_E "\"");
msg, impexp_state);
m_target_color_space = AXF_COLORSPACE_LINEAR_SRGB_E;
break;
}
if (strcmp(cs, s) == 0) {
m_target_color_space = s;
break;
}
}
if (!file_name || !is_file(file_name))
{
string msg = string("Could not find AxF file: ") + file_name;
msg, impexp_state);
return false;
}
m_filename = file_name;
Scope_axf_file_handler file_h(AXF::axfOpenFile(file_name, true));
if (!file_h.m_axf_file) {
string msg = string("Failed to open AxF file ") + m_filename;
msg, impexp_state);
return false;
}
if (!access_mdl_material_definitions(impexp_state))
return false;
const int num_materials = AXF::axfGetNumberOfMaterials(file_h.m_axf_file);
for (int m = 0; m < num_materials; ++m) {
bool success = read_material(file_h.m_axf_file, m, impexp_state);
if (!success)
return false;
}
const unsigned int num_variants = handle_collected_variants(impexp_state);
if (num_variants > 0)
{
std::string("Loaded ") + std::to_string(num_variants) +
std::string(" materials from file ") + m_filename, impexp_state);
return true;
}
else
return false;
}
bool Axf_reader::read_material(
AXF::AXF_FILE_HANDLE file,
const int material_idx,
Axf_impexp_state* impexp_state)
{
AXF::AXF_MATERIAL_HANDLE material_h = AXF::axfGetMaterial(file, material_idx);
char name_buf[AXF::AXF_MAX_KEY_SIZE];
if (!AXF::axfGetMaterialIDString(material_h, name_buf, AXF::AXF_MAX_KEY_SIZE)) {
string msg = string("Cannot retrieve material name from file ") + m_filename
+ string(" for ") + string(std::to_string(material_idx)) + string(". material.");
msg, impexp_state);
return false;
}
m_material_name = name_buf;
m_material_display_name.clear();
const size_t display_name_buf_size = AXF::axfGetMaterialDisplayName(material_h, nullptr, 0);
if (display_name_buf_size > 0) {
std::vector<wchar_t> display_name_buf(display_name_buf_size);
if (AXF::axfGetMaterialDisplayName(
material_h, display_name_buf.data(), display_name_buf_size))
{
m_material_display_name = wchar_to_utf8(display_name_buf.data());
}
}
const AXF::VersionedCompatibilityProfile supported_base_profiles_carpaint[] = {
{AXF_COMPAT_PROF_CARPAINT2, 1}
};
const AXF::VersionedCompatibilityProfile supported_coating_profiles_carpaint[] = {
{AXF_COMPAT_PROF_CLEARCOAT_NO_REFRACT, 1},
{AXF_COMPAT_PROF_CLEARCOAT_REFRACT, 1}
};
const AXF::VersionedCompatibilityProfile supported_base_profiles_volumetric[] = {
{AXF_COMPAT_PROF_VOLUMETRIC, 1}
};
const AXF::VersionedCompatibilityProfile supported_coating_profiles_volumetric[] = {
{AXF_COMPAT_PROF_CLEARCOAT_REFRACT, 1}
};
const AXF::VersionedCompatibilityProfile supported_base_profiles_svbrdf[] = {
{AXF_COMPAT_PROF_SVBRDF_WARD, 1},
{AXF_COMPAT_PROF_SVBRDF_WARD, 2},
{AXF_COMPAT_PROF_SVBRDF_WARD, 3},
{AXF_COMPAT_PROF_SVBRDF_GGX, 1},
{AXF_COMPAT_PROF_SVBRDF_GGX, 2},
{AXF_COMPAT_PROF_SVBRDF_GGX, 3}
};
const AXF::VersionedCompatibilityProfile supported_coating_profiles_svbrdf[] = {
{AXF_COMPAT_PROF_CLEARCOAT_NO_REFRACT, 1}
};
#define NUMEL(v) (sizeof(v) / sizeof(v[0]))
int conversion_flags;
AXF::AXF_REPRESENTATION_HANDLE rep_h = AXF::axfGetBestCompatibleRepresentation(
material_h,
supported_base_profiles_carpaint, NUMEL(supported_base_profiles_carpaint),
supported_coating_profiles_carpaint, NUMEL(supported_coating_profiles_carpaint),
conversion_flags);
if (!rep_h) {
rep_h = AXF::axfGetBestCompatibleRepresentation(
material_h,
supported_base_profiles_volumetric, NUMEL(supported_base_profiles_volumetric),
supported_coating_profiles_volumetric, NUMEL(supported_coating_profiles_volumetric),
conversion_flags);
}
if (!rep_h) {
rep_h = AXF::axfGetBestCompatibleRepresentation(
material_h,
supported_base_profiles_svbrdf, NUMEL(supported_base_profiles_svbrdf),
supported_coating_profiles_svbrdf, NUMEL(supported_coating_profiles_svbrdf),
conversion_flags);
}
#undef NUMEL
bool success = false;
if (rep_h)
success = handle_representation(rep_h, conversion_flags, impexp_state);
if (!success) {
const string msg = string("No supported representation found for AxF material ") +
m_material_name;
}
return success;
}
static void split_texture(
std::vector<float>& out_a,
std::vector<float>& out_b,
const std::vector<float>& tex_buffer)
{
const size_t num_pixels = out_a.size();
assert(out_b.size() == num_pixels);
assert(tex_buffer.size() == 2 * num_pixels);
for (size_t i = 0; i < num_pixels; ++i)
{
out_a[i] = tex_buffer[2 * i];
out_b[i] = tex_buffer[2 * i + 1];
}
}
static int get_property_index(
AXF::TextureDecoder *tex_decoder,
const char *const name)
{
#if 0
const int idx = tex_decoder->getPropertyIndexFromName(name);
#else
int idx = -1;
for (int p = 0; p < tex_decoder->getNumProperties(); ++p)
{
char buf[AXF::AXF_MAX_KEY_SIZE];
if (!tex_decoder->getPropertyName(p, buf, AXF::AXF_MAX_KEY_SIZE))
continue;
if (strcmp(buf, name) == 0)
{
idx = p;
break;
}
}
#endif
return idx;
}
static bool get_property(
void *target,
const size_t target_size,
AXF::TextureDecoder *tex_decoder,
const AXF::PropertyType type,
const char *name,
Axf_impexp_state* impexp_state,
const bool report_error)
{
memset(target, 0, target_size);
const char *
error = NULL;
const int idx = get_property_index(tex_decoder, name);
if (idx < 0)
if (!
error && tex_decoder->getPropertyType(idx) != type)
if (!
error && tex_decoder->getPropertySize(idx) != target_size)
if (!
error && !tex_decoder->getProperty(idx, target, type, target_size))
error =
"retrieval failed";
{
if (report_error)
Axf_importer::report_message(
std::string("property \"") + std::string(name) +
std::string(
"\": ") + std::string(
error),
impexp_state);
return false;
}
return true;
}
template <typename T>
static bool get_array_property(
std::vector<T> &data,
AXF::TextureDecoder *tex_decoder,
const AXF::PropertyType type,
const char *name,
Axf_impexp_state* impexp_state,
const bool report_error)
{
const char *
error = NULL;
const int idx = get_property_index(tex_decoder, name);
if (idx < 0)
if (!
error && tex_decoder->getPropertyType(idx) != type)
{
const int size = tex_decoder->getPropertySize(idx);
assert(size % sizeof(T) == 0);
assert(size >= 0);
data.resize(size / sizeof(T));
if (size > 0)
{
if (!tex_decoder->getProperty(idx, data.data(), type, size))
error =
"retrieval failed";
}
}
{
if (report_error)
Axf_importer::report_message(
std::string("property \"") + std::string(name) +
std::string(
"\": ") + std::string(
error),
impexp_state);
return false;
}
return true;
}
static bool flake_sanitize(float &r, float &g, float &b, const float threshold)
{
r = std::max(r, 0.0f);
g = std::max(g, 0.0f);
b = std::max(b, 0.0f);
return (std::max(r, std::max(g, b)) >= threshold);
}
static unsigned int hist_idx(const float x, const unsigned int size)
{
int idx = (int)(x * (float)size);
return (unsigned int)std::max(0, std::min((int)size - 1, idx));
}
static void initialize_carpaint_flakes(
std::vector<unsigned int> &flake_importance_data,
float &flake_intensity_scale,
float flake_uvw_scale[3],
std::vector<float> &flake_orientation_falloff,
const unsigned int width,
const unsigned int height,
const std::vector<float> &flake_btf_data,
const int flake_btf_num_theta_i,
const int flake_btf_num_theta_f,
const std::vector<int> &flake_btf_slice_lut)
{
flake_importance_data.clear();
flake_intensity_scale = 0.0f;
flake_uvw_scale[0] = flake_uvw_scale[1] = flake_uvw_scale[2] = 0.01f;
if (flake_btf_num_theta_i <= 0 || flake_btf_num_theta_f <= 0 || flake_btf_data.size() == 0)
return;
const unsigned int l_hist_size = 64;
const unsigned int c_hist_size = 16;
flake_importance_data.resize(l_hist_size + c_hist_size * c_hist_size, 0);
unsigned int *hist_l = &flake_importance_data[0];
unsigned int *hist_c = &flake_importance_data[l_hist_size];
const float *slice_data = &flake_btf_data[flake_btf_slice_lut[0] * width * height * 3];
float max_l = 0.0f;
float sum_l = 0.0f;
for (unsigned int i = 0; i < width * height; ++i) {
float r = slice_data[3 * i];
float g = slice_data[3 * i + 1];
float b = slice_data[3 * i + 2];
flake_sanitize(r, g, b, 0.0f);
const float l = r + g + b;
sum_l += l;
max_l = fmaxf(l, max_l);
}
for (unsigned int i = 0; i < width * height; ++i) {
float r = slice_data[3 * i];
float g = slice_data[3 * i + 1];
float b = slice_data[3 * i + 2];
const bool is_flake = flake_sanitize(r, g, b, 0.1f * max_l);
float l = r + g + b;
r /= l;
g /= l;
l /= max_l;
++hist_l[hist_idx(l, l_hist_size)];
if (is_flake)
++hist_c[hist_idx(r, c_hist_size) * c_hist_size + hist_idx(g, c_hist_size)];
}
flake_orientation_falloff.resize(flake_btf_num_theta_f, 0.0f);
if (sum_l > 0.0f) {
for (int i_f = 0; i_f < flake_btf_slice_lut[1]; ++i_f) {
const float *f = slice_data + i_f * width * height * 3;
float sum_l_i = 0.0f;
for (unsigned int i = 0; i < width * height; ++i) {
float r = f[3 * i];
float g = f[3 * i + 1];
float b = f[3 * i + 2];
flake_sanitize(r, g, b, 0.0f);
const float l = r + g + b;
sum_l_i += l;
}
flake_orientation_falloff[i_f] = sum_l_i / sum_l;
}
}
for (unsigned int i = 1; i < l_hist_size; ++i)
hist_l[i] += hist_l[i - 1];
for (unsigned int i = 1; i < c_hist_size * c_hist_size; ++i)
hist_c[i] += hist_c[i - 1];
const float intensity_scale_factor = 0.4f;
flake_intensity_scale = max_l * intensity_scale_factor;
const float flake_size_btf_u = 0.75f / (float)width;
const float flake_size_btf_v = 0.75f / (float)height;
const float flake_size_procedural = 1.3f;
flake_uvw_scale[0] = flake_size_procedural / flake_size_btf_u;
flake_uvw_scale[1] = flake_size_procedural / flake_size_btf_v;
flake_uvw_scale[2] = 0.5f * (flake_uvw_scale[0] + flake_uvw_scale[1]);
}
static void upscale_tex_buffer(
std::vector<float> &tex,
unsigned int &rx, unsigned int &ry,
const unsigned int t_rx, const unsigned int t_ry,
const unsigned int num_channels)
{
if (rx == t_rx && ry == t_ry)
return;
assert(t_rx > 1 && t_ry > 1);
std::vector<float> t_tex(t_rx * t_ry * num_channels);
if (rx == 1 && ry == 1)
{
for (unsigned int i = 0; i < t_rx * t_ry * num_channels; i += num_channels) {
for (unsigned int j = 0; j < num_channels; ++j)
t_tex[i + j] = tex[j];
}
}
else
{
const float step_y = 1.0f / (float)(t_ry - 1);
const float step_x = 1.0f / (float)(t_rx - 1);
for (unsigned int y = 0; y < t_ry; ++y) {
const float v = (float)y * step_y;
for (unsigned int x = 0; x < t_rx; ++x) {
const float u = (float)x * step_x;
const unsigned int t_idx = (y * t_rx + x) * num_channels;
tex_lookup(num_channels, &t_tex[t_idx], u, v, rx, ry, &tex[0]);
}
}
}
tex.swap(t_tex);
rx = t_rx;
ry = t_ry;
}
enum Clearcoat_model_variant {
CLEARCOAT_DEFAULT,
CLEARCOAT_NO_SOLID_ANGLE_COMPRESSION,
CLEARCOAT_DSPBR2020X
};
static bool get_clearcoat_params(
bool &refractive,
Clearcoat_model_variant &variant,
const AXF::TextureDecoder *const tex_decoder)
{
refractive = false;
variant = CLEARCOAT_DEFAULT;
const bool has_clearcoat = tex_decoder->hasClearCoat();
if (has_clearcoat) {
char type_key[AXF::AXF_MAX_KEY_SIZE];
if (!tex_decoder->getClearCoatTransmissionModelType(type_key, AXF::AXF_MAX_KEY_SIZE)) {
assert(!"clearcoat type retrieval should not fail");
return false;
}
refractive = strcmp(type_key, AXF_TYPEKEY_TRANSMISSION_REFRACTIVE_DIRAC) == 0;
if (!tex_decoder->getClearCoatTransmissionModelVariant(type_key, AXF::AXF_MAX_KEY_SIZE)) {
assert(!"clearcoat variant retrieval should not fail");
return false;
}
if (strcmp(type_key, AXF_TRANSMISSION_VARIANT_NO_SOLID_ANGLE_COMPRESSION) == 0)
variant = CLEARCOAT_NO_SOLID_ANGLE_COMPRESSION;
else if (strcmp(type_key, AXF_TRANSMISSION_VARIANT_DSPBR2020X) == 0)
variant = CLEARCOAT_DSPBR2020X;
}
return has_clearcoat;
}
bool Axf_reader::check_texture_type(
const unsigned int channels,
const Input_texture_type type,
const char *tex_name,
Axf_impexp_state* impexp_state)
{
const char *channel_error = nullptr;
if (type == INPUT_TEXTURE_COLOR) {
if (m_wavelengths.empty()) {
if (channels != 3)
channel_error = "RGB";
} else {
if (channels != m_wavelengths.size())
channel_error = "spectrum";
}
} else if (type == INPUT_TEXTURE_NORMAL) {
if (channels != 3)
channel_error = "normalmap";
} else if (type == INPUT_TEXTURE_FLOAT) {
if (channels != 1)
channel_error = "float";
} else if (type == INPUT_TEXTURE_FLOAT12) {
if (channels > 2)
channel_error = "float/float2";
}
if (channel_error)
{
ostringstream str;
str << "Encountered texture \"" << tex_name
<< "\" with unexpected number of channels in AxF material " << m_material_name
<< ", expected type: " << channel_error;
Axf_importer::report_message(
6021,
str.str(), impexp_state);
return false;
}
return true;
}
static bool is_unmodified_normal(
const std::vector<float> tex_buffer)
{
return
(tex_buffer.size() == 3) &&
(tex_buffer[0] == 0.0f) &&
(tex_buffer[1] == 0.0f) &&
(tex_buffer[2] == 1.0f);
}
bool Axf_reader::handle_carpaint_representation(
AXF::AXF_REPRESENTATION_HANDLE rep_h,
const int conversion_flags,
AXF::TextureDecoder *tex_decoder,
Axf_impexp_state* impexp_state)
{
m_ior = 1.5f;
m_ct_diffuse = 0.0f;
for (int i = 0; i < 3; ++i) {
m_ct_coeffs[i] = 0.0f;
m_ct_f0s[i] = 0.0f;
m_ct_spreads[i] = 0.0f;
}
m_brdf_colors_scale = 1.0f;
m_brdf_colors_2d.clear();
m_brdf_colors_2d_rx = m_brdf_colors_2d_ry = 1;
m_flake_intensity_scale = 0.0f;
m_flake_uvw_scale[0] = m_flake_uvw_scale[1] = m_flake_uvw_scale[2] = 1.0f;
Clearcoat_model_variant clearcoat_variant;
const bool has_clearcoat = get_clearcoat_params(
m_refractive_clearcoat, clearcoat_variant, tex_decoder);
if (has_clearcoat) {
assert(
(m_refractive_clearcoat && (clearcoat_variant == CLEARCOAT_NO_SOLID_ANGLE_COMPRESSION))
|| (!m_refractive_clearcoat && (clearcoat_variant == CLEARCOAT_DEFAULT))
);
get_property(
&m_ior, sizeof(m_ior),
tex_decoder, AXF::TYPE_FLOAT,
AXF_CARPAINT2_PROPERTY_CC_IOR, impexp_state,
true);
} else
m_ior = 1.0f;
get_property(
&m_ct_diffuse, sizeof(m_ct_diffuse),
tex_decoder, AXF::TYPE_FLOAT,
AXF_CARPAINT2_PROPERTY_BRDF_CT_DIFFUSE, impexp_state,
true);
std::vector<float> fvalues;
get_array_property(
fvalues,
tex_decoder, AXF::TYPE_FLOAT_ARRAY,
AXF_CARPAINT2_PROPERTY_BRDF_CT_COEFFS, impexp_state,
true);
for (size_t i = 0; i < std::min(fvalues.size(), size_t(3)); ++i)
m_ct_coeffs[i] = fvalues[i];
const size_t size = fvalues.size();
if (size > 3)
"more than 3 BRDF lobes for carpaint are not supported", impexp_state);
m_ct_coeffs[0] *= 4.0f;
m_ct_coeffs[1] *= 4.0f;
m_ct_coeffs[2] *= 4.0f;
get_array_property(
fvalues,
tex_decoder, AXF::TYPE_FLOAT_ARRAY,
AXF_CARPAINT2_PROPERTY_BRDF_CT_F0S, impexp_state,
true);
for (size_t i = 0; i < std::min(fvalues.size(), size_t(3)); ++i)
m_ct_f0s[i] = fvalues[i];
assert(size == fvalues.size());
get_array_property(
fvalues,
tex_decoder, AXF::TYPE_FLOAT_ARRAY,
AXF_CARPAINT2_PROPERTY_BRDF_CT_SPREADS, impexp_state,
true);
for (size_t i = 0; i < std::min(fvalues.size(), size_t(3)); ++i)
m_ct_spreads[i] = fvalues[i];
assert(size == fvalues.size());
#if 0
int max_theta_i = 0;
get_property(
&max_theta_i, sizeof(max_theta_i),
tex_decoder, AXF::TYPE_INT,AXF_CARPAINT2_PROPERTY_FLAKES_MAX_THETAI , impexp_state,
true);
#endif
int num_theta_i = 0;
get_property(
&num_theta_i, sizeof(num_theta_i),
tex_decoder, AXF::TYPE_INT,AXF_CARPAINT2_PROPERTY_FLAKES_NUM_THETAI , impexp_state,
true);
int num_theta_f = 0;
get_property(
&num_theta_f, sizeof(num_theta_f),
tex_decoder, AXF::TYPE_INT, AXF_CARPAINT2_PROPERTY_FLAKES_NUM_THETAF , impexp_state,
true);
std::vector<int> slice_lut;
get_array_property(
slice_lut,
tex_decoder, AXF::TYPE_INT_ARRAY, AXF_CARPAINT2_PROPERTY_FLAKES_THETAFI_SLICE_LUT,
impexp_state, true);
assert(slice_lut.size() >= (size_t)num_theta_f);
std::map<std::string, std::string> tex_to_param;
for (int i=0, cnt=tex_decoder->getNumTextures(); i<cnt; ++i) {
char tex_name[AXF::AXF_MAX_KEY_SIZE];
if (!tex_decoder->getTextureName(i, tex_name, AXF::AXF_MAX_KEY_SIZE)) {
string msg = string("Cannot retrieve texture name from AxF material ") +
m_material_name;
msg, impexp_state);
return false;
}
const bool is_brdf_colors = strcmp(tex_name, AXF_CARPAINT2_TEXTURE_NAME_BRDF_COLORS) == 0;
const bool is_normal = strcmp(tex_name, AXF_CARPAINT2_TEXTURE_NAME_CLEARCOAT_NORMAL) == 0;
const bool is_flake_btf = strcmp(tex_name, AXF_CARPAINT2_TEXTURE_NAME_BTF_FLAKES) == 0;
if (!is_brdf_colors && !is_normal && !is_flake_btf)
continue;
const int mip_level = 0;
int width, height, depth, channels, datatype;
tex_decoder->getTextureSize(i, mip_level, width, height, depth, channels, datatype);
std::vector<float> tex_buffer(width * height * depth * channels);
tex_decoder->getTextureData(i, mip_level, AXF::TYPE_FLOAT, tex_buffer.data());
Input_texture_type expected_type;
if (is_normal)
expected_type = INPUT_TEXTURE_NORMAL;
else if (is_flake_btf)
expected_type = INPUT_TEXTURE_RGB;
else
expected_type = INPUT_TEXTURE_COLOR;
if (!check_texture_type(channels, expected_type, tex_name, impexp_state))
return false;
if (is_normal)
{
if (is_unmodified_normal(tex_buffer))
continue;
for (size_t i = 0; i < tex_buffer.size(); ++i)
tex_buffer[i] = tex_buffer[i] * 0.5f + 0.5f;
const string texture_name = write_texture(
impexp_state,
tex_name,
tex_buffer,
width,
height,
channels,
TEXTURE_NORMAL);
if (texture_name.empty())
{
const string msg =
string("Error while creating textures from AxF material ") + m_material_name;
Axf_importer::report_message(
msg, impexp_state);
return false;
}
else
tex_to_param.insert(make_pair(texture_name, "clearcoat_normal_texture"));
}
else if (is_flake_btf)
{
#ifdef DUMP_TEXTURES
write_texture(
impexp_state, tex_name, tex_buffer, width, height * depth,
channels, TEXTURE_RGB);
#endif
initialize_carpaint_flakes(
m_flake_importance_data,
m_flake_intensity_scale,
m_flake_uvw_scale,
m_flake_orientation_falloff,
width, height,
tex_buffer, num_theta_i, num_theta_f, slice_lut);
}
else
{
assert(is_brdf_colors);
const bool bake_brdf_colors = m_wavelengths.empty();
if (bake_brdf_colors) {
m_brdf_colors_2d = tex_buffer;
m_brdf_colors_2d_rx = width;
m_brdf_colors_2d_ry = height;
} else {
m_brdf_colors_2d.clear();
m_brdf_colors_2d_rx = m_brdf_colors_2d_ry = 0;
}
if (m_refractive_clearcoat)
recode_brdf_colors(tex_buffer, width, height, channels, m_ior, !bake_brdf_colors);
{
std::vector<float> tex_buffer2(tex_buffer.size());
size_t pos = 0;
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
const size_t idx = ((width - x - 1) * height + y) * channels;
for (int c = 0; c < channels; ++c) {
tex_buffer2[idx + c] = tex_buffer[pos++];
}
}
}
tex_buffer.swap(tex_buffer2);
std::swap(width, height);
}
m_brdf_colors_scale = 1.0f;
if (!bake_brdf_colors) {
float max_val = 0.0f;
for (size_t i = 0; i < tex_buffer.size(); ++i)
max_val = std::max(tex_buffer[i], max_val);
if (max_val > 1.0f)
{
m_brdf_colors_scale = max_val;
const float scale = 1.0f / max_val;
for (size_t i = 0; i < tex_buffer.size(); ++i)
tex_buffer[i] *= scale;
}
}
const string texture_name = write_texture(
impexp_state, tex_name, tex_buffer, width, height,
channels, m_wavelengths.empty() ? TEXTURE_RGB : TEXTURE_SPECTRAL);
tex_to_param.insert(make_pair(texture_name, "brdf_colors_2d"));
}
}
create_variant(
impexp_state, "carpaint",
tex_decoder->getWidthMM(), tex_decoder->getHeightMM(),
tex_to_param);
return true;
}
bool Axf_reader::handle_volumetric_representation(
AXF::AXF_REPRESENTATION_HANDLE rep_h,
const int conversion_flags,
AXF::TextureDecoder *tex_decoder,
Axf_impexp_state* impexp_state)
{
m_ior = 1.0f;
const unsigned int col_size = m_wavelengths.empty() ? 3 : m_wavelengths.size();
m_sigma_a.resize(col_size, 0.0f);
m_sigma_s.resize(col_size, 0.0f);
m_phasefunc_g = 0.0f;
get_property(
&m_ior, sizeof(m_ior),
tex_decoder, AXF::TYPE_FLOAT,
AXF_VOLUMETRIC_PROPERTY_NAME_IOR, impexp_state,
true);
for (int i=0, cnt=tex_decoder->getNumTextures(); i<cnt; ++i) {
char tex_name[AXF::AXF_MAX_KEY_SIZE];
if (!tex_decoder->getTextureName(i, tex_name, AXF::AXF_MAX_KEY_SIZE)) {
string msg = string("Cannot retrieve texture name from AxF material ") +
m_material_name;
msg, impexp_state);
return false;
}
const bool is_sigma_a = strcmp(tex_name, AXF_VOLUMETRIC_TEXTURE_NAME_SIGMAA) == 0;
const bool is_sigma_s = strcmp(tex_name, AXF_VOLUMETRIC_TEXTURE_NAME_SIGMAS) == 0;
const bool is_phasefunc_g = strcmp(tex_name, AXF_VOLUMETRIC_TEXTURE_NAME_PHASEFUNCG) == 0;
if (!is_sigma_a && !is_sigma_s && !is_phasefunc_g)
continue;
const int mip_level = 0;
int width, height, depth, channels, datatype;
tex_decoder->getTextureSize(i, mip_level, width, height, depth, channels, datatype);
std::vector<float> tex_buffer(width * height * depth * channels);
tex_decoder->getTextureData(i, mip_level, AXF::TYPE_FLOAT, tex_buffer.data());
if (is_phasefunc_g) {
assert(channels == 1);
m_phasefunc_g = tex_buffer[0];
}
else {
assert(channels == col_size);
memcpy(
is_sigma_a ? m_sigma_a.data() : m_sigma_s.data(),
tex_buffer.data(),
col_size * sizeof(float));
}
}
for (unsigned int i = 0; i < col_size; ++i) {
m_sigma_a[i] *= 1000.0f;
m_sigma_s[i] *= 1000.0f;
}
if (!m_wavelengths.empty()) {
expand_spectrum(m_sigma_a);
expand_spectrum(m_sigma_s);
}
std::map<std::string, std::string> tex_to_param;
create_variant(
impexp_state, "volumetric",
tex_decoder->getWidthMM(), tex_decoder->getHeightMM(),
tex_to_param);
return true;
}
bool Axf_reader::handle_representation(
AXF::AXF_REPRESENTATION_HANDLE rep_h,
const int conversion_flags,
Axf_impexp_state* impexp_state)
{
char typekey[AXF::AXF_MAX_KEY_SIZE];
if (!AXF::axfGetRepresentationClass(rep_h, typekey, AXF::AXF_MAX_KEY_SIZE)) {
const string msg = string("No representation type key found for AxF material ") +
m_material_name;
msg, impexp_state);
return false;
}
if (strcmp(typekey, AXF_REPRESENTATION_CLASS_CARPAINT2) == 0)
m_type = REP_CARPAINT;
else if (strcmp(typekey, AXF_REPRESENTATION_CLASS_SVBRDF) == 0)
m_type = REP_SVBRDF;
else if (strcmp(typekey, AXF_REPRESENTATION_CLASS_VOLUMETRIC) == 0)
m_type = REP_VOLUMETRIC;
else if (strcmp(typekey, AXF_REPRESENTATION_CLASS_EPSVBRDF) == 0) {
assert((conversion_flags & AXF::CONVERT_EPSVBRDF_TO_SVBRDF) != 0);
m_type = REP_SVBRDF;
}
else
return false;
handle_preview_images(rep_h, impexp_state);
const bool has_spectral_representation = AXF::axfGetRepresentationIsSpectral(rep_h);
const Color_representation color_rep = impexp_state->get_color_rep();
bool success = true;
unsigned int reps_converted = 0;
for (unsigned int i = 0; (i < 2) && success; ++i) {
if (i == 0) {
if (has_spectral_representation && (color_rep == COLOR_REP_SPECTRAL))
continue;
m_wavelengths.clear();
m_spectral_tex_meta_data.clear();
} else {
if (!has_spectral_representation || (color_rep == COLOR_REP_RGB))
break;
float lambda_min, lambda_max;
int num_lambda;
if (!axfGetRepresentationWavelengthRange(rep_h, lambda_min, lambda_max, num_lambda) ||
num_lambda <= 0) {
success = false;
break;
}
m_wavelengths.resize(num_lambda);
const float lambda_step =
(num_lambda > 1) ? ((lambda_max - lambda_min) / float(num_lambda - 1)) : 0.0f;
for (int j = 0; j < num_lambda; ++j)
m_wavelengths[j] = lambda_min + j * lambda_step;
compute_spectral_texture_metadata(
m_spectral_tex_meta_data, m_wavelengths);
}
Scope_handler<AXF::TextureDecoder> tex_decoder(
(i == 1)
? AXF::TextureDecoder::createSpectral(
rep_h, m_wavelengths.data(), m_wavelengths.size(),
AXF::ORIGIN_TOPLEFT, conversion_flags)
: AXF::TextureDecoder::create(
rep_h, m_target_color_space, AXF::ORIGIN_TOPLEFT, conversion_flags));
if (!tex_decoder) {
const string msg = string("Cannot create texture decoder for AxF material ") +
m_material_name;
Axf_importer::report_message(
return false;
}
assert(success);
m_skip_non_color_maps = reps_converted > 0;
if (m_type == REP_CARPAINT)
success = handle_carpaint_representation(
rep_h, conversion_flags, tex_decoder.get(), impexp_state);
else if (m_type == REP_VOLUMETRIC)
success = handle_volumetric_representation(
rep_h, conversion_flags, tex_decoder.get(), impexp_state);
else {
assert(m_type == REP_SVBRDF);
success = handle_svbrdf_representation(
rep_h, conversion_flags, tex_decoder.get(), impexp_state);
}
if (success)
++reps_converted;
}
return success && (reps_converted > 0);
}
bool Axf_reader::handle_svbrdf_representation(
AXF::AXF_REPRESENTATION_HANDLE rep_h,
const int conversion_flags,
AXF::TextureDecoder *tex_decoder,
Axf_impexp_state* impexp_state)
{
int rep_version_major, rep_version_minor, rep_version_rev;
axfGetRepresentationVersion( rep_h, rep_version_major, rep_version_minor, rep_version_rev);
AXF::AXF_REPRESENTATION_HANDLE spec_model_h =
AXF::axfGetSvbrdfSpecularModelRepresentation(rep_h);
AXF::AXF_REPRESENTATION_HANDLE diff_model_h =
AXF::axfGetSvbrdfDiffuseModelRepresentation(rep_h);
if (!spec_model_h && !diff_model_h) {
const string msg = string("Failed to retrieve SVBRDF model for AxF material ") +
m_material_name;
msg, impexp_state);
return false;
}
if (spec_model_h) {
char typekey[AXF::AXF_MAX_KEY_SIZE];
if (!AXF::axfGetRepresentationTypeKey(spec_model_h, typekey, AXF::AXF_MAX_KEY_SIZE)) {
ostringstream str;
str << "No specular SVBRDF representation type key found for AxF material "
<< m_material_name;
str.str(), impexp_state);
return false;
}
m_glossy_brdf_type = BRDF_TYPE_UNKNOWN;
m_fresnel_type = FRESNEL_NONE;
bool is_anisotropic = false;
bool has_fresnel = false;
char variant[AXF::AXF_MAX_KEY_SIZE];
if (!AXF::axfGetSvbrdfSpecularModelVariant(
spec_model_h,variant,AXF::AXF_MAX_KEY_SIZE,is_anisotropic,has_fresnel)) {
ostringstream str;
str << "Failed to retrieve specular model variant for AxF material "
<< m_material_name;
str.str(),impexp_state);
return false;
}
m_isotropic = !is_anisotropic;
if (!strcmp(typekey,AXF_TYPEKEY_SVBRDF_SPECULAR_WARD)) {
if (!strcmp(variant,AXF_SVBRDF_SPECULAR_WARD_VARIANT_GEISLERMORODER))
m_glossy_brdf_type = BRDF_WARD_GEISLERMORODER;
else {
m_glossy_brdf_type = BRDF_WARD_GEISLERMORODER;
ostringstream str;
str << "Unsupported or unknown specular BRDF model variant " << typekey
<< " (" << variant << ')'
<< " for AxF material " << m_material_name;
Axf_importer::report_message(6017,
str.str(),impexp_state);
}
}
else if (!strcmp(typekey,AXF_TYPEKEY_SVBRDF_SPECULAR_COOKTORRANCE)) {
m_glossy_brdf_type = BRDF_COOKTORRANCE;
}
else if (!strcmp(typekey,AXF_TYPEKEY_SVBRDF_SPECULAR_GGX)) {
m_glossy_brdf_type = BRDF_GGX;
}
if (m_glossy_brdf_type == BRDF_TYPE_UNKNOWN) {
ostringstream str;
str << "Unsupported or unknown specular BRDF model " << typekey
<< " (" << variant << ')'
<< " for AxF material " << m_material_name;
str.str(), impexp_state);
return false;
}
if (has_fresnel) {
char fresnel_type[AXF::AXF_MAX_KEY_SIZE];
if (!axfGetSvbrdfSpecularFresnelVariant(
spec_model_h, fresnel_type, AXF::AXF_MAX_KEY_SIZE))
{
ostringstream str;
str << "Failed to retrieve Fresnel type " << " for AxF material "
<< m_material_name;
Axf_importer::report_message(6022,
str.str(),impexp_state);
return false;
}
if (strcmp(fresnel_type, AXF_SVBRDF_FRESNEL_VARIANT_SCHLICK) == 0)
m_fresnel_type = FRESNEL_SCHLICK;
else if (strcmp(fresnel_type, AXF_SVBRDF_FRESNEL_VARIANT_SCHLICK_COLORED) == 0) {
assert((conversion_flags & AXF::CONVERT_EPSVBRDF_TO_SVBRDF) != 0);
m_fresnel_type = FRESNEL_SCHLICK;
}
#if 0
else if (strcmp(fresnel_type, AXF_SVBRDF_FRESNEL_VARIANT_FRESNEL) == 1)
m_fresnel_type = FRESNEL_FRESNEL;
#endif
else
{
ostringstream str;
str << "Unsupported Fresnel type " << fresnel_type
<< " for AxF material " << m_material_name;
Axf_importer::report_message(6023,
str.str(),impexp_state);
return false;
}
}
}
bool refractive_clearcoat;
Clearcoat_model_variant clearcoat_variant;
m_has_clearcoat = get_clearcoat_params(refractive_clearcoat, clearcoat_variant, tex_decoder);
if (m_has_clearcoat && refractive_clearcoat) {
assert(!"should not get refractive clearcoat");
ostringstream str;
str << "Refractive clearcoat in SVBRDF representation is not supported"
<< " for AxF material " << m_material_name;
Axf_importer::report_message(
str.str(), impexp_state);
return false;
}
assert(clearcoat_variant != CLEARCOAT_DSPBR2020X);
unsigned int diffuse_tex_rx = 0, diffuse_tex_ry = 0;
std::vector<float> diffuse_tex;
unsigned int fresnel_tex_rx = 0, fresnel_tex_ry = 0;
std::vector<float> fresnel_tex;
std::string fresnel_tex_name;
unsigned int specular_color_tex_rx = 0, specular_color_tex_ry = 0;
std::vector<float> specular_color_tex;
std::string specular_color_tex_name;
unsigned int trans_color_tex_rx = 0, trans_color_tex_ry = 0;
std::vector<float> trans_color_tex;
map<string, string> tex_to_param;
for (int i=0, cnt=tex_decoder->getNumTextures(); i<cnt; ++i) {
char tex_name[AXF::AXF_MAX_KEY_SIZE];
if (!tex_decoder->getTextureName(i, tex_name, AXF::AXF_MAX_KEY_SIZE)) {
string msg = string("Cannot retrieve texture name from AxF material ") +
m_material_name;
msg, impexp_state);
return false;
}
const bool is_normal =
strcmp(tex_name, AXF_SVBRDF_TEXTURE_NAME_NORMAL) == 0;
const bool is_clearcoat_normal =
strcmp(tex_name, AXF_SVBRDF_TEXTURE_NAME_CLEARCOAT_NORMAL) == 0;
const bool is_clearcoat_ior =
strcmp(tex_name, AXF_SVBRDF_TEXTURE_NAME_CLEARCOAT_IOR) == 0;
#if 0
const bool is_clearcoat_color =
strcmp(tex_name, AXF_SVBRDF_TEXTURE_NAME_CLEARCOAT_COLOR) == 0;
#else
const bool is_clearcoat_color = false;
#endif
const bool is_transmission_color =
strcmp(tex_name, AXF_SVBRDF_TEXTURE_NAME_TRANSMISSION_COLOR) == 0;
const int mip_level = 0;
int width, height, depth, channels, datatype;
tex_decoder->getTextureSize(i, mip_level, width, height, depth, channels, datatype);
assert(depth == 1);
const bool is_displacement = !strcmp(tex_name, AXF_SVBRDF_TEXTURE_NAME_HEIGHT);
if (is_displacement && (rep_version_major < 2) && (rep_version_minor < 4))
continue;
const bool is_alpha = !strcmp(tex_name, AXF_SVBRDF_TEXTURE_NAME_ALPHA);
if (is_alpha && (rep_version_major < 2) && (rep_version_minor < 4))
continue;
const bool is_specular_lobe = !strcmp(tex_name,AXF_SVBRDF_TEXTURE_NAME_SPECULAR_LOBE);
const bool needs_separation = (is_specular_lobe && channels == 2);
const bool is_fresnel = !strcmp(tex_name, AXF_SVBRDF_TEXTURE_NAME_FRESNEL);
const bool is_specular_color = !strcmp(tex_name, AXF_SVBRDF_TEXTURE_NAME_SPECULAR_COLOR);
const bool is_diffuse_color = !strcmp(tex_name,AXF_SVBRDF_TEXTURE_NAME_DIFFUSE_COLOR);
const bool is_aniso_rotation = !strcmp(tex_name,AXF_SVBRDF_TEXTURE_NAME_ANISO_ROTATION);
const bool is_sheen_color = !strcmp(tex_name, AXF_SVBRDF_TEXTURE_NAME_SHEEN_COLOR);
const bool is_sheen_roughness = !strcmp(tex_name, AXF_SVBRDF_TEXTURE_NAME_SHEEN_LOBE);
Input_texture_type expected_type = INPUT_TEXTURE_FLOAT;
if (is_diffuse_color || is_specular_color || is_clearcoat_color || is_transmission_color || is_sheen_color)
expected_type = INPUT_TEXTURE_COLOR;
else if (is_clearcoat_normal || is_normal)
expected_type = INPUT_TEXTURE_NORMAL;
else if (is_alpha || is_displacement || is_aniso_rotation || is_clearcoat_ior ||
is_sheen_roughness ||
is_fresnel)
expected_type = INPUT_TEXTURE_FLOAT;
else if (is_specular_lobe)
expected_type = INPUT_TEXTURE_FLOAT12;
else
assert(!"unhandled texture");
if (!check_texture_type(channels, expected_type, tex_name, impexp_state))
return false;
std::vector<float> tex_buffer(width * height * depth * channels);
tex_decoder->getTextureData(i, mip_level, AXF::TYPE_FLOAT, tex_buffer.data());
if (m_fresnel_type == FRESNEL_SCHLICK && (is_fresnel || is_specular_color))
{
if (is_fresnel) {
fresnel_tex_rx = width;
fresnel_tex_ry = height;
fresnel_tex.swap(tex_buffer);
fresnel_tex_name = tex_name;
} else {
specular_color_tex_rx = width;
specular_color_tex_ry = height;
specular_color_tex.swap(tex_buffer);
specular_color_tex_name = tex_name;
}
continue;
}
if (is_transmission_color)
{
trans_color_tex_rx = width;
trans_color_tex_ry = height;
trans_color_tex.swap(tex_buffer);
continue;
}
bool texture_error = false;
if (!needs_separation)
{
Texture_type texture_type = TEXTURE_SCALAR;
if (is_diffuse_color || is_specular_color || is_clearcoat_color || is_sheen_color) {
texture_type = m_wavelengths.empty() ? TEXTURE_RGB : TEXTURE_SPECTRAL;
}
if (is_aniso_rotation) {
for (size_t i = 0; i < tex_buffer.size(); ++i) {
const float angle = tex_buffer[i] >= 0.0f
? tex_buffer[i]
: (float)(2.0 * M_PI) + tex_buffer[i];
tex_buffer[i] = angle * (float)(0.5 / M_PI);
}
}
if (is_normal || is_clearcoat_normal)
{
if (is_unmodified_normal(tex_buffer))
continue;
for (size_t i = 0; i < tex_buffer.size(); ++i)
tex_buffer[i] = tex_buffer[i] * 0.5f + 0.5f;
texture_type = TEXTURE_NORMAL;
}
const string texture_name = write_texture(
impexp_state,
tex_name,
tex_buffer,
width,
height,
channels,
texture_type);
texture_error = texture_name.empty();
if (is_normal)
tex_to_param.insert(make_pair(texture_name, "normal_texture"));
else if (is_diffuse_color)
tex_to_param.insert(make_pair(texture_name, "diffuse_texture"));
else if (is_specular_color)
tex_to_param.insert(make_pair(texture_name, "specular_texture"));
else if (is_aniso_rotation)
tex_to_param.insert(make_pair(texture_name, "specular_brdf_texture_rotation"));
else if (is_specular_lobe)
tex_to_param.insert(make_pair(texture_name, "specular_brdf_texture_u"));
else if (is_fresnel)
tex_to_param.insert(make_pair(texture_name, "specular_brdf_texture_fresnel"));
else if (is_clearcoat_normal)
tex_to_param.insert(make_pair(texture_name, "clearcoat_normal_texture"));
else if (is_clearcoat_ior)
tex_to_param.insert(make_pair(texture_name, "clearcoat_ior_texture"));
else if (is_clearcoat_color)
tex_to_param.insert(make_pair(texture_name, "clearcoat_color_texture"));
else if (is_displacement)
tex_to_param.insert(make_pair(texture_name, "height_texture"));
else if (is_alpha)
tex_to_param.insert(make_pair(texture_name, "alpha_texture"));
else if (is_sheen_color)
tex_to_param.insert(make_pair(texture_name, "sheen_color_texture"));
else if (is_sheen_roughness)
tex_to_param.insert(make_pair(texture_name, "sheen_roughness_texture"));
else {
ostringstream str;
str << "Ignoring unknown texture " << tex_name
<< " in AxF material " << m_material_name;
Axf_importer::report_message(6020,
str.str(), impexp_state);
}
}
else
{
assert(channels == 2);
std::vector<float> tex_buffer_a(width * height);
std::vector<float> tex_buffer_b(width * height);
const char* tex_input_a = "specular_brdf_texture_u";
const char* const tex_input_b = "specular_brdf_texture_v";
switch (m_glossy_brdf_type) {
case BRDF_COOKTORRANCE:
split_texture(tex_buffer_a,tex_buffer_b,tex_buffer);
tex_input_a = "specular_brdf_texture_f0";
break;
case BRDF_WARD_GEISLERMORODER:
case BRDF_GGX:
split_texture(tex_buffer_a,tex_buffer_b,tex_buffer);
break;
default: {
ostringstream str;
str << "Ignoring texture " << tex_name
<< " for unsupported specular BRDF in material " << m_material_name;
Axf_importer::report_message(6022,
str.str(), impexp_state);
}
continue;
}
const string texture_name_a = write_texture(
impexp_state,
string(tex_name) + string("a"), tex_buffer_a, width, height, 1,
TEXTURE_SCALAR);
const string texture_name_b = write_texture(
impexp_state,
string(tex_name) + string("b"), tex_buffer_b, width, height, 1,
TEXTURE_SCALAR);
texture_error = texture_name_a.empty() || texture_name_b.empty();
if (!texture_error) {
tex_to_param.insert(make_pair(texture_name_a,tex_input_a));
tex_to_param.insert(make_pair(texture_name_b,tex_input_b));
}
}
if (m_fresnel_type == FRESNEL_SCHLICK && is_diffuse_color) {
diffuse_tex.swap(tex_buffer);
diffuse_tex_rx = width;
diffuse_tex_ry = height;
}
if (texture_error) {
const string msg =
string("Error while creating textures from AxF material ") + m_material_name;
Axf_importer::report_message(
msg, impexp_state);
return false;
}
}
const unsigned int max_rx = std::max(
std::max(fresnel_tex_rx, trans_color_tex_rx),
std::max(diffuse_tex_rx, specular_color_tex_rx));
const unsigned int max_ry = std::max(
std::max(fresnel_tex_ry, trans_color_tex_ry),
std::max(diffuse_tex_ry, specular_color_tex_ry));
const size_t num_color_channels = m_wavelengths.empty() ? 3 : m_wavelengths.size();
const size_t num_pixels = max_rx * max_ry;
if (m_fresnel_type == FRESNEL_SCHLICK) {
upscale_tex_buffer(
diffuse_tex, diffuse_tex_rx, diffuse_tex_ry, max_rx, max_ry, num_color_channels);
upscale_tex_buffer(
specular_color_tex, specular_color_tex_rx, specular_color_tex_ry, max_rx, max_ry,
num_color_channels);
bool energy_violation = false;
std::vector<float> scale_buf(num_pixels, 1.0f);
for (size_t p = 0; p < num_pixels; ++p) {
const size_t idx = num_color_channels * p;
float d = diffuse_tex[idx];
float g = specular_color_tex[idx];
for (size_t c = 1; c < num_color_channels; ++c) {
g = std::max(g, specular_color_tex[idx + c]);
d = std::max(d, diffuse_tex[idx + c]);
}
if (d + g > 1.0f && d < 1.0f && g > 0.0f) {
const float scale = (1.0f - d) / g;
for (size_t c = 0; c < num_color_channels; ++c)
specular_color_tex[idx + c] *= scale;
scale_buf[p] = scale;
energy_violation = true;
}
}
if (energy_violation) {
upscale_tex_buffer(
fresnel_tex, fresnel_tex_rx, fresnel_tex_ry, max_rx, max_ry, 1);
for (unsigned int p = 0; p < max_rx * max_ry; ++p) {
fresnel_tex[p] = std::min(1.0f, fresnel_tex[p] / scale_buf[p]);
}
}
for (unsigned int i = 0; i < 2; ++i) {
std::vector<float> *tex_buffer;
unsigned int width, height;
unsigned int channels;
const char *tex_name;
const char *target_slot;
Texture_type tex_type;
if (i == 0) {
tex_buffer = &fresnel_tex;
width = fresnel_tex_rx;
height = fresnel_tex_ry;
channels = 1;
tex_name = fresnel_tex_name.c_str();
target_slot = "specular_brdf_texture_fresnel";
tex_type = m_wavelengths.empty() ? TEXTURE_SCALAR : TEXTURE_SCALAR_SPECTRAL;
} else {
tex_buffer = &specular_color_tex;
width = specular_color_tex_rx;
height = specular_color_tex_ry;
channels = num_color_channels;
tex_name = specular_color_tex_name.c_str();
target_slot = "specular_texture";
tex_type = m_wavelengths.empty() ? TEXTURE_RGB : TEXTURE_SPECTRAL;
}
const string texture_name = write_texture(
impexp_state,
tex_name, *tex_buffer,
width, height, channels, tex_type);
if (texture_name.empty()) {
const string msg =
string("Error while creating textures from AxF material ") + m_material_name;
Axf_importer::report_message(
msg, impexp_state);
return false;
}
tex_to_param.insert(make_pair(texture_name, target_slot));
}
}
if (!trans_color_tex.empty())
{
assert(m_fresnel_type == FRESNEL_SCHLICK);
upscale_tex_buffer(
specular_color_tex, specular_color_tex_rx, specular_color_tex_ry,
max_rx, max_ry, num_color_channels);
upscale_tex_buffer(
trans_color_tex, trans_color_tex_rx, trans_color_tex_ry,
max_rx, max_ry, num_color_channels);
upscale_tex_buffer(
fresnel_tex, fresnel_tex_rx, fresnel_tex_ry, max_rx, max_ry, 1);
std::vector<float> transmission_s(num_pixels);
std::vector<float> transmission_rho(num_pixels * num_color_channels);
for (size_t i = 0; i < num_pixels; ++i)
{
const size_t idx = i * num_color_channels;
float max_rho_s = specular_color_tex[idx];
float max_rho_t0 = trans_color_tex[idx];
for (size_t c = 1; c < num_color_channels; ++c) {
max_rho_s = std::max(max_rho_s, specular_color_tex[idx + c]);
max_rho_t0 = std::max(max_rho_t0, trans_color_tex[idx + c]);
}
const float F0 = fresnel_tex[i];
transmission_s[i] = std::min(max_rho_s, (1.0f - max_rho_t0) / F0);
for (size_t c = 0; c < num_color_channels; ++c)
{
transmission_rho[idx + c] =
trans_color_tex[idx + c] / (1.0f - transmission_s[i] * F0);
}
}
const std::string texture_name_s = write_texture(
impexp_state,
"transmission_s", transmission_s,
max_rx, max_ry, 1,
m_wavelengths.empty() ? TEXTURE_SCALAR : TEXTURE_SCALAR_SPECTRAL);
const std::string texture_name_rho = write_texture(
impexp_state,
"transmission_rho", transmission_rho,
max_rx, max_ry, num_color_channels,
m_wavelengths.empty() ? TEXTURE_RGB : TEXTURE_SPECTRAL);
if (texture_name_s.empty() || texture_name_rho.empty()) {
const string msg =
string("Error while creating textures from AxF material ") + m_material_name;
Axf_importer::report_message(
msg, impexp_state);
return false;
}
tex_to_param.insert(make_pair(texture_name_s, "specular_amount_texture"));
tex_to_param.insert(make_pair(texture_name_rho, "transmission_color_texture"));
}
create_variant(
impexp_state, "svbrdf", tex_decoder->getWidthMM(), tex_decoder->getHeightMM(),
tex_to_param);
return true;
}
string Axf_reader::write_texture(
Axf_impexp_state* impexp_state,
const string& tex_name,
const vector<float>& tex_buffer,
const int width,
const int height,
const int channels,
Texture_type type)
{
const string error_str("");
string img_name = get_axf_image_prefix() +
impexp_state->get_module_prefix() + string("_") +
m_material_name + string("_") + string(tex_name);
string texture_name = get_axf_texture_prefix() +
impexp_state->get_module_prefix() + string("_") +
m_material_name + string("_") + string(tex_name);
if (type == TEXTURE_SPECTRAL || type == TEXTURE_SCALAR_SPECTRAL) {
img_name += "_spectral";
texture_name += "_spectral";
}
if (m_skip_non_color_maps &&
(type != TEXTURE_SPECTRAL) && (type != TEXTURE_SCALAR_SPECTRAL)) {
if (tex)
return texture_name;
else {
assert(!"texture should have been created already");
}
}
if (type == TEXTURE_SCALAR_SPECTRAL)
type = TEXTURE_SCALAR;
const char* input_pixel_type = 0;
if (type == TEXTURE_NORMAL || type == TEXTURE_RGB)
input_pixel_type = "Rgb_fp";
else
input_pixel_type = "Float32";
assert(image_api);
const char *pixel_type;
unsigned int layers = 1;
unsigned int meta_layers = 0;
if (type == TEXTURE_SPECTRAL) {
pixel_type = "Float32";
layers = channels;
size_t spectral_offset0;
meta_layers = compute_num_spectral_meta_layers(
spectral_offset0, width * height * sizeof(float), channels,
m_spectral_tex_meta_data.size());
assert(spectral_offset0 == 0);
} else if (type == TEXTURE_NORMAL) {
pixel_type = "Rgb_16";
} else {
assert(channels == 3 || channels == 1);
pixel_type = (channels == 3) ? "Rgbe" : "Float32";
}
image_api->create_canvas(pixel_type, width, height, layers + meta_layers));
if (!canvas) {
string msg = string("Failed to create canvas for AxF material \"") + m_material_name;
msg += string("\" of texture ") + string(tex_name);
msg, impexp_state);
return error_str;
}
std::vector<float> tmp_layer_buffer;
if (layers != 1)
tmp_layer_buffer.resize((size_t)width * (size_t)height);
for (unsigned int l = 0; l < layers; ++l) {
if (layers != 1) {
size_t o = 0;
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x,++o)
tmp_layer_buffer[o] = tex_buffer[o * layers + l];
}
image_api->write_raw_pixels(
width,
height,
canvas.get(),
0,
0,
l,
(layers == 1) ? tex_buffer.data() : tmp_layer_buffer.data(),
true,
input_pixel_type);
}
if (type == TEXTURE_SPECTRAL) {
size_t copied = 0;
size_t uncopied = m_spectral_tex_meta_data.size();
for (size_t l = layers; l < layers + meta_layers; ++l) {
const size_t to_copy =
std::min(uncopied, (size_t)width * (size_t)height * sizeof(float));
memcpy(tile->get_data(), m_spectral_tex_meta_data.data() + copied, to_copy);
copied += to_copy;
uncopied -= to_copy;
}
assert(uncopied == 0);
}
#ifdef DUMP_TEXTURES
m_plugin_api->get_api_component<mi::neuraylib::IExport_api>());
assert(export_api);
std::string filename = m_material_name + tex_name;
bool can_export = true;
if (type == TEXTURE_NORMAL)
filename += ".png";
else if (type == TEXTURE_RGB)
filename += ".hdr";
else {
filename += ".aix";
can_export = false;
}
if (can_export)
export_api->export_canvas(filename.c_str(), canvas.get());
#endif
image->set_from_canvas(canvas.get());
m_transaction->store(image.get(), img_name.c_str(), privacy);
image = 0;
tex->set_image(img_name.c_str());
tex->set_gamma(1.0f);
m_transaction->store(tex.get(), texture_name.c_str(), privacy);
tex = 0;
return texture_name;
}
static bool get_int_expr(
int &result,
const char *name)
{
if (!expr)
return false;
if (!exprc)
return false;
if (!value_int)
return false;
result = value_int->get_value();
return true;
}
bool Axf_reader::access_mdl_material_definitions(
Axf_impexp_state* impexp_state)
{
mdl_factory->create_execution_context());
check_success(mdl_impexp_api->load_module(
m_transaction, "::nvidia::axf_importer::axf_importer", context.get()) >= 0);
print_messages(context.get());
check_success(mdl_module.is_valid_interface());
bool got_version = false;
int major = -1, minor = -1, patch = -1;
if (mdl_module) {
assert(mdl_module);
mdl_module->get_annotations());
if (annotation_block) {
for (
mi::Size i = 0; i < annotation_block->get_size(); ++i) {
annotation_block->get_annotation(i));
if (annotation) {
annotation->get_definition());
if (def && def->get_semantic() ==
annotation->get_arguments());
if (expr_list) {
got_version = get_int_expr(major, expr_list.get(), "major");
got_version |= get_int_expr(minor, expr_list.get(), "minor");
got_version |= get_int_expr(patch, expr_list.get(), "patch");
}
}
}
}
}
}
if (!got_version) {
Axf_importer::report_message(
"Failed to retrieve version of nvidia::axf_importer::axf_importer, "
"the installed version may be out of date",
impexp_state);
return false;
}
if (major < 1 || (major == 1 && minor < 9) || (major == 1 && minor == 9 && patch < 0)) {
ostringstream str;
str << "Insufficient version (" << major << '.' << minor << '.' << patch << ") of "
"nvidia::axf_importer::axf_importer, required version is (1.9.0)";
Axf_importer::report_message(
str.str(), impexp_state);
return false;
}
m_svbrdf_material =
m_carpaint_material =
m_volumetric_material =
if (!m_svbrdf_material) {
std::string msg = "Cannot access the definition of \"";
msg += s_prototype_names[0];
msg += "\". Has MDL module \"nvidia::axf_importer::axf_importer\" been properly imported?";
msg, impexp_state);
return false;
}
if (!m_carpaint_material) {
std::string msg = "Cannot access the definition of \"";
msg += s_prototype_names[1];
msg += "\". Has MDL module \"nvidia::axf_importer::axf_importer\" been properly imported?";
msg, impexp_state);
return false;
}
if (!m_volumetric_material) {
std::string msg = "Cannot access the definition of \"";
msg += s_prototype_names[2];
msg += "\". Has MDL module \"nvidia::axf_importer::axf_importer\" been properly imported?";
msg, impexp_state);
return false;
}
return true;
}
namespace {
template<class T>
T* get_parameter_type(
const char* param_name)
{
if (!type)
return nullptr;
if (!requested_type)
return nullptr;
requested_type->retain();
return requested_type.get();
}
void set_float_param(
Axf_impexp_state* impexp_state,
const char* param_name,
float value)
{
get_parameter_type<const mi::neuraylib::IType_float>(material, param_name));
if (!type)
{
string("Failed to set parameter \"") + param_name
+ string("\" for current AxF material."), impexp_state);
return;
}
}
void set_float3_param(
Axf_impexp_state* impexp_state,
const char* param_name,
const float* value)
{
get_parameter_type<const mi::neuraylib::IType_vector>(material, param_name));
if (!type || type->get_size() != size)
{
string("Failed to set parameter \"") + param_name
+ string("\" for current AxF material."), impexp_state);
return;
}
{
string("Failed to set parameter \"") + param_name
+ string("\" for current AxF material."), impexp_state);
return;
}
{
vec->set_value(i, val.get());
}
}
void set_color_param(
Axf_impexp_state* impexp_state,
const char* param_name,
const float* rgb)
{
get_parameter_type<const mi::neuraylib::IType_color>(material, param_name));
if (!type)
{
string("Failed to set parameter \"") + param_name
+ string("\" for current AxF material."), impexp_state);
return;
}
}
#ifdef UNUSED_CODE
void set_color_array_param(
Axf_impexp_state* impexp_state,
const char* param_name,
const std::vector<float> &values)
{
const mi::Size size = values.size() / 3;
get_parameter_type<const mi::neuraylib::IType_array>(material, param_name));
if (!type)
{
string("Failed to set parameter \"") + param_name
+ string("\" for current AxF material."), impexp_state);
return;
}
{
string("Failed to set parameter \"") + param_name
+ string("\" for current AxF material."), impexp_state);
return;
}
{
values[i * 3 + 0], values[i * 3 + 1], values[i * 3 + 2]));
ar->set_value(i, val.get());
}
}
#endif
void set_int_array_param(
Axf_impexp_state* impexp_state,
const char* param_name,
const std::vector<unsigned int> &values)
{
get_parameter_type<const mi::neuraylib::IType_array>(material, param_name));
if (!type)
{
string("Failed to set parameter \"") + param_name
+ string("\" for current AxF material."), impexp_state);
return;
}
{
string("Failed to set parameter \"") + param_name
+ string("\" for current AxF material."), impexp_state);
return;
}
{
ar->set_value(i, val.get());
}
}
void set_float_array_param(
Axf_impexp_state* impexp_state,
const char* param_name,
const std::vector<float> &values)
{
get_parameter_type<const mi::neuraylib::IType_array>(material, param_name));
if (!type)
{
string("Failed to set parameter \"") + param_name
+ string("\" for current AxF material."), impexp_state);
return;
}
{
string("Failed to set parameter \"") + param_name
+ string("\" for current AxF material."), impexp_state);
return;
}
{
ar->set_value(i, val.get());
}
}
void set_bool_param(
Axf_impexp_state* impexp_state,
const char* param_name,
bool value)
{
get_parameter_type<const mi::neuraylib::IType_bool>(material, param_name));
if(!type)
{
string("Failed to set parameter \"") + param_name
+ string("\" for current AxF material."), impexp_state);
return;
}
}
void set_brdf_param(
Axf_impexp_state* impexp_state,
const char* param_name,
int value)
{
get_parameter_type<const mi::neuraylib::IType_enum>(material, param_name));
if (!enum_type
|| strcmp(enum_type->get_symbol(), "::nvidia::axf_importer::axf_importer::brdf_type") != 0)
{
string("Failed to set parameter \"") + param_name
+ string("\" for current AxF material."), impexp_state);
return;
}
}
void set_fresnel_param(
Axf_impexp_state* impexp_state,
const char* param_name,
int value)
{
get_parameter_type<const mi::neuraylib::IType_enum>(material, param_name));
if (!enum_type ||
strcmp(enum_type->get_symbol(), "::nvidia::axf_importer::axf_importer::fresnel_type") != 0)
{
string("Failed to set parameter \"") + param_name
+ string("\" for current AxF material."), impexp_state);
return;
}
}
bool set_texture_param(
Axf_impexp_state* impexp_state,
const char* param_name,
const char* value)
{
get_parameter_type<const mi::neuraylib::IType_texture>(material, param_name));
return false;
return true;
}
bool set_bsdf_param(
Axf_impexp_state* impexp_state,
const char* param_name,
const char* value)
{
get_parameter_type<const mi::neuraylib::IType_bsdf_measurement>(material, param_name));
if (!type)
return false;
return true;
}
void set_spectral_param(
Axf_impexp_state* impexp_state,
const char* material_name,
const char* param_name,
const std::vector<float> &wavelengths,
const std::vector<float> &values)
{
get_parameter_type<const mi::neuraylib::IType_color>(material, param_name));
if (!type)
{
string("Failed to set parameter \"") + param_name
+ string("\" for current AxF material."), impexp_state);
return;
}
assert(wavelengths.size() == values.size());
assert(dw.is_valid());
assert(result == 0);
string color_constructor_name
= get_axf_spectrum_prefix()
+ impexp_state->get_module_prefix() + string("_")
+ material_name + string("_")
+ param_name;
transaction->
store(fc.get(), color_constructor_name.c_str());
result = ae.set_value("wavelengths", wavelengths.data(), wavelengths.size());
assert(result == 0);
result = ae.set_value("amplitudes", values.data(), values.size());
assert(result == 0);
expr_factory->
create_call(color_constructor_name.c_str()));
}
string make_valid_mdl_id(
{
if (id.empty())
return string();
string result;
result.reserve(id.size());
size_t index = 0;
result.push_back(isalpha(id[index])? id[index] : 'X');
for (index=1; index < id.size(); ++index) {
if (isalnum(id[index]) || id[index] == '_')
result.push_back(id[index]);
else
result.push_back('_');
}
return result;
else
return string("X") + result;
}
string make_valid_mdl_module_path(
{
std::string result;
size_t start = 0;
for (start = 0; start < path.size(); ++start) {
if (path[start] != ':')
break;
}
bool prev_colon = false;
for (size_t pos = start; pos < path.size(); ++pos) {
bool colon = (path[pos] == ':');
if (colon && prev_colon) {
result += "::" + make_valid_mdl_id(
mdl_factory, path.substr(start, pos - start - 1));
for (start = pos + 1; start < path.size(); ++start) {
if (path[start] != ':') {
break;
}
}
pos = start - 1;
colon = false;
}
prev_colon = colon;
}
if (start < path.size()) {
result += "::" + make_valid_mdl_id(mdl_factory, path.substr(start, path.size() - start));
}
return result + "::";
}
}
void Axf_reader::create_variant(
Axf_impexp_state* impexp_state,
const string& representation,
const float widthMM,
const float heightMM,
const map<string, string>& tex_to_param)
{
map<string, string>::const_iterator it, end=tex_to_param.end();
for (it=tex_to_param.begin(); it != end; ++it) {
const string& value = it->first;
const string& param_name = it->second;
switch (m_type) {
case REP_VOLUMETRIC:
mat_def = m_volumetric_material.get();
break;
case REP_SVBRDF:
mat_def = m_svbrdf_material.get();
break;
case REP_CARPAINT:
mat_def = m_carpaint_material.get();
break;
};
if (!set_texture_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
mat_def, param_name.c_str(), value.c_str()))
{
string msg = string("Failed to appropriate texture parameter \"") + param_name
+ string("\" for current AxF material.");
msg, impexp_state);
continue;
}
}
string material_name = make_valid_mdl_id(
mdl_factory.get(), m_material_name + string("_") + representation);
string display_name = m_material_display_name;
if (!m_wavelengths.empty()) {
material_name += "_spectral";
display_name += " (" + representation + ", spectral)";
} else {
display_name += " (" + representation + ')';
}
const char* param_name;
if (m_type != REP_VOLUMETRIC)
{
param_name = "sample_size_u";
set_float_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_svbrdf_material.get(), param_name, widthMM / 1000.0f);
param_name = "sample_size_v";
set_float_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_svbrdf_material.get(), param_name, heightMM / 1000.0f);
}
if (m_type == REP_SVBRDF)
{
param_name = "isotropic";
set_bool_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_svbrdf_material.get(), param_name, m_isotropic);
param_name = "brdf_type";
set_brdf_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_svbrdf_material.get(), param_name, static_cast<int>(m_glossy_brdf_type));
param_name = "fresnel_type";
set_fresnel_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_svbrdf_material.get(), param_name, static_cast<int>(m_fresnel_type));
param_name = "has_clearcoat";
set_bool_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_svbrdf_material.get(), param_name, m_has_clearcoat);
m_variants.push_back(
Variant_data(REP_SVBRDF, material_name, display_name, default_parameters));
}
else if (m_type == REP_VOLUMETRIC)
{
param_name = "phasefunc_g";
set_float_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_volumetric_material.get(), param_name, m_phasefunc_g);
param_name = "ior";
set_float_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_volumetric_material.get(), param_name, m_ior);
if (m_wavelengths.empty()) {
param_name = "sigma_s";
set_color_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_volumetric_material.get(), param_name, m_sigma_s.data());
param_name = "sigma_a";
set_color_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_volumetric_material.get(), param_name, m_sigma_a.data());
} else {
param_name = "sigma_s";
set_spectral_param(
impexp_state,
default_parameters.get(), mdl_factory.get(),
expr_factory.get(), m_volumetric_material.get(), material_name.c_str(),
m_transaction, param_name, m_wavelengths, m_sigma_s);
param_name = "sigma_a";
set_spectral_param(
impexp_state,
default_parameters.get(), mdl_factory.get(),
expr_factory.get(), m_volumetric_material.get(), material_name.c_str(),
m_transaction, param_name, m_wavelengths, m_sigma_a);
}
m_variants.push_back(
Variant_data(REP_VOLUMETRIC, material_name, display_name, default_parameters));
}
else
{
assert(m_type == REP_CARPAINT);
const bool bake_brdf_colors = !m_brdf_colors_2d.empty();
{
const unsigned int res_theta = 45;
const unsigned int res_phi = 90;
res_theta, res_phi,
float *data = bsdf_data_buffer->get_data();
Brdf_params params;
params.diffuse = m_ct_diffuse;
for (int i = 0; i < 3; ++i) {
params.ct_weight[i] = m_ct_coeffs[i];
params.ct_f0[i] = m_ct_f0s[i];
params.ct_roughness[i] = std::max(m_ct_spreads[i], 1e-5f);
}
params.ior = m_ior;
params.refr = m_refractive_clearcoat;
if (bake_brdf_colors) {
params.brdf_colors = m_brdf_colors_2d.data();
params.brdf_colors_rx = m_brdf_colors_2d_rx;
params.brdf_colors_ry = m_brdf_colors_2d_ry;
} else {
params.diffuse *= m_brdf_colors_scale;
params.ct_weight[0] *= m_brdf_colors_scale;
params.ct_weight[1] *= m_brdf_colors_scale;
params.ct_weight[2] *= m_brdf_colors_scale;
params.brdf_colors = nullptr;
params.brdf_colors_rx = 0;
params.brdf_colors_ry = 0;
}
create_measured_subclearcoat(data, res_theta, res_phi, params);
bsdf_measurement->set_reflection(bsdf_data.get());
string bsdf_measurement_name =
get_axf_mbsdf_prefix() +
impexp_state->get_module_prefix() + string("_") +
m_material_name + string("_sub_clearcoat_measurement");
if (bake_brdf_colors)
bsdf_measurement_name += "_color";
m_transaction->store(
bsdf_measurement.get(), bsdf_measurement_name.c_str(),
const char* param_name = "sub_clearcoat_measurement";
if (!set_bsdf_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_carpaint_material.get(), param_name, bsdf_measurement_name.c_str()))
{
string msg =
string("Failed to appropriate bsdf measurement parameter \"") + param_name
+ string("\" for current AxF material.");
Axf_importer::report_message(
msg, impexp_state);
}
}
if (m_refractive_clearcoat) {
const float tmp = m_ior * m_ior;
for (int i = 0; i < 3; ++i) {
m_ct_spreads[i] *= m_ior;
m_ct_coeffs[i] *= tmp;
}
}
m_ct_diffuse *= m_brdf_colors_scale;
m_ct_coeffs[0] *= m_brdf_colors_scale;
m_ct_coeffs[1] *= m_brdf_colors_scale;
m_ct_coeffs[2] *= m_brdf_colors_scale;
param_name = "precise_sub_clearcoat_component";
set_bool_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_carpaint_material.get(), param_name, true);
param_name = "ior";
set_float_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_carpaint_material.get(), param_name, m_ior);
param_name = "ct_diffuse";
set_float_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_carpaint_material.get(), param_name, m_ct_diffuse);
param_name = "ct_coeffs";
set_float3_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_carpaint_material.get(), param_name, m_ct_coeffs);
param_name = "ct_f0s";
set_float3_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_carpaint_material.get(), param_name, m_ct_f0s);
param_name = "ct_spreads";
set_float3_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_carpaint_material.get(), param_name, m_ct_spreads);
param_name = "enable_flakes";
set_bool_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_carpaint_material.get(), param_name, m_flake_intensity_scale > 0.0f);
param_name = "flake_importance_data";
set_int_array_param(
impexp_state,
default_parameters.get(), type_factory.get(), val_factory.get(), expr_factory.get(),
m_carpaint_material.get(), param_name, m_flake_importance_data);
param_name = "flake_peak_intensity_scale";
set_float_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_carpaint_material.get(), param_name, m_flake_intensity_scale);
param_name = "flake_uvw_scale";
set_float3_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_carpaint_material.get(), param_name, m_flake_uvw_scale);
param_name = "flake_orientation_falloff";
set_float_array_param(
impexp_state,
default_parameters.get(), type_factory.get(), val_factory.get(), expr_factory.get(),
m_carpaint_material.get(), param_name, m_flake_orientation_falloff);
param_name = "brdf_colors_2d_included_in_measurement";
set_bool_param(
impexp_state,
default_parameters.get(), val_factory.get(), expr_factory.get(),
m_carpaint_material.get(), param_name, bake_brdf_colors);
m_variants.push_back(
Variant_data(REP_CARPAINT, material_name, display_name, default_parameters));
}
}
void Axf_reader::handle_preview_images(
AXF::AXF_REPRESENTATION_HANDLE rep_h,
Axf_impexp_state* impexp_state
) const
{
int num = AXF::axfGetNumPreviewImages(rep_h);
for (int i=0; i<num; ++i) {
int width, height, channels;
float widthMM, heightMM;
if (!AXF::axfGetPreviewImageInfo(rep_h, i, width, height, channels, widthMM, heightMM)) {
const string msg =
string("Failed to retrieve preview image info for material \"") +
m_material_name + '\"';
msg, impexp_state);
continue;
}
string pixel_type;
if (channels == 3)
pixel_type = "Rgb_fp";
else if (channels == 1)
pixel_type = "Float32";
else
continue;
vector<float> img(width * height * channels);
if (!AXF::axfGetPreviewImage(
rep_h,i,m_target_color_space,img.data(),width,height,channels))
{
const string msg =
string("Failed to retrieve preview image info for material \"") +
m_material_name + '\"';
msg, impexp_state);
continue;
}
assert(image_api);
image_api->create_canvas(pixel_type.c_str(), width, height)
);
if (!canvas) {
const string msg = string("Failed to create preview canvas of AxF material \"")
+ m_material_name + string("\".");
msg, impexp_state);
continue;
}
bool topdown = true;
image_api->write_raw_pixels(
width,
height,
canvas.get(),
0,
0,
0,
img.data(),
topdown,
canvas->get_type());
#ifdef DUMP_TEXTURES
m_plugin_api->get_api_component<mi::neuraylib::IExport_api>());
assert(export_api);
std::string filename = m_material_name + "_preview.hdr";
export_api->export_canvas(filename.c_str(), canvas.get());
#endif
const string img_name = get_axf_pimage_prefix() +
impexp_state->get_module_prefix() + string("_") +
m_material_name + string("_")
+ std::to_string(width) + string("x") + std::to_string(height);
image->set_from_canvas(canvas.get());
m_transaction->store(
}
}
const char* prototype_name,
const char* display_name)
{
if (!annos) {
return nullptr;
}
for (
mi::Size i = 0, n = annos->get_size(); i < n; ++i) {
if (anno_def &&(anno_def->get_semantic() ==
{
continue;
}
if (anno_def && (anno_def->get_semantic() ==
{
new_expr_list->add_expression("name", new_expr_constant.get());
new_annos->add_annotation(new_anno.get());
continue;
}
anno_args ? expr_factory->
clone(anno_args.get()) :
nullptr);
new_annos->add_annotation(new_anno.get());
}
new_annos->retain();
return new_annos.get();
}
unsigned int Axf_reader::handle_collected_variants(
Axf_impexp_state* impexp_state)
{
string axf_name = Ospath::basename(m_filename);
string mat_name(axf_name), dummy;
Ospath::splitext(mat_name, axf_name, dummy);
string module_name
= make_valid_mdl_module_path(mdl_factory.get(), impexp_state->get_module_prefix())
+ make_valid_mdl_id(mdl_factory.get(), axf_name);
m_transaction,
("mdl" + module_name).c_str(),
context.get()));
if (!module_builder) {
"Failed to create module builder for \"" + module_name + "\".", impexp_state);
return false;
}
unsigned int num_variants = 0;
std::vector<bool> success(m_variants.size(), false);
for (size_t i=0; i<m_variants.size(); ++i) {
const char *prototype_name;
switch (m_variants[i].m_type) {
case REP_SVBRDF:
prototype_name = s_prototype_names[0];
break;
case REP_CARPAINT:
prototype_name = s_prototype_names[1];
break;
case REP_VOLUMETRIC:
prototype_name = s_prototype_names[2];
break;
default:
assert(false);
continue;
}
copy_annotations(m_transaction, expr_factory.get(), value_factory.get(),
prototype_name, m_variants[i].m_display_name.c_str()));
m_variants[i].m_material_name.c_str(),
prototype_name,
m_variants[i].m_default_values.get(),
annos.get(),
nullptr,
true,
false,
context.get());
if (result < 0) {
"Failed to create variant \"" + m_variants[i].m_material_name + "\" for \"" +
module_name + "\".",
impexp_state);
for (
mi::Size i = 0; i < context->get_messages_count(); ++i) {
Axf_importer::report_message(6019, msg->get_severity(),
msg->get_string(), impexp_state);
}
}
else {
check_success(mdl_impexp_api->export_module(
m_transaction,
("mdl" + module_name).c_str(),
impexp_state->get_mdl_output_filename()) == 0);
++num_variants;
success[i] = true;
}
}
for (
mi::Size i = 0; i < context->get_messages_count(); ++i) {
Axf_importer::report_message(6019, msg->get_severity(),
msg->get_string(), impexp_state);
}
return num_variants;
}
}
}
}
A wrapper around the interface for MDL material instances and function calls.
Definition: argument_editor.h:57
Example implementation of the abstract interface mi::neuraylib::IBsdf_buffer.
Definition: bsdf_isotropic_data.h:30
Example implementation of the abstract interface mi::neuraylib::IBsdf_isotropic_data.
Definition: bsdf_isotropic_data.h:60
A wrapper around the interface for MDL function definitions.
Definition: definition_wrapper.h:44
An annotation block is an array of annotations.
Definition: iexpression.h:575
@ AS_VERSION_ANNOTATION
This is the version() annotation.
Definition: iexpression.h:439
@ AS_DISPLAY_NAME_ANNOTATION
This is the display_name() annotation.
Definition: iexpression.h:445
@ AS_HIDDEN_ANNOTATION
This is the hidden() annotation.
Definition: iexpression.h:436
A scene element that stores measured BSDF data.
Definition: ibsdf_measurement.h:39
A constant expression.
Definition: iexpression.h:96
The interface for creating expressions.
Definition: iexpression.h:650
virtual IExpression_call * create_call(const char *name) const =0
Creates a call.
virtual IExpression_list * create_expression_list() const =0
Creates a new expression list.
virtual IExpression * clone(const IExpression *expr) const =0
Clones the given expression.
virtual IAnnotation * create_annotation(const char *name, const IExpression_list *arguments) const =0
Creates a new annotation.
virtual IAnnotation_block * create_annotation_block() const =0
Creates a new annotation block.
virtual IExpression_constant * create_constant(IValue *value) const =0
Creates a constant (mutable).
An ordered collection of expressions identified by name or index.
Definition: iexpression.h:317
virtual Sint32 add_expression(const char *name, const IExpression *expression)=0
Adds an expression at the end of the list.
virtual const IExpression * get_expression(Size index) const =0
Returns the expression for index, or NULL if there is no such expression.
This interface represents a function definition.
Definition: ifunction_definition.h:44
virtual const IType_list * get_parameter_types() const =0
Returns the types of all parameters.
virtual const IAnnotation_block * get_annotations() const =0
Returns the annotations of the function definition itself, or NULL if there are no such annotations.
This interface provides various utilities related to canvases and buffers.
Definition: iimage_api.h:72
This interface represents a pixel image file.
Definition: iimage.h:66
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 IMdl_module_builder * create_module_builder(ITransaction *transaction, const char *module_name, Mdl_version min_module_version, Mdl_version max_module_version, IMdl_execution_context *context)=0
Creates a module builder for a given module.
virtual bool is_valid_mdl_identifier(const char *name) const =0
Indicates whether the given string is a valid MDL identifier.
virtual IType_factory * create_type_factory(ITransaction *transaction)=0
Returns an MDL type factory for the given transaction.
virtual IExpression_factory * create_expression_factory(ITransaction *transaction)=0
Returns an MDL expression factory for the given transaction.
virtual IValue_factory * create_value_factory(ITransaction *transaction)=0
Returns an MDL value factory for the given transaction.
API component for MDL related import and export operations.
Definition: imdl_impexp_api.h:43
This interface represents an MDL module.
Definition: imodule.h:634
This is an object representing the MDL SDK library.
Definition: ineuray.h:44
Textures add image processing options to images.
Definition: itexture.h:68
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.
static const mi::Uint8 LOCAL_SCOPE
Symbolic privacy level for the privacy level of the scope of this transaction.
Definition: itransaction.h:253
virtual Sint32 store(base::IInterface *db_element, const char *name, Uint8 privacy=LOCAL_SCOPE)=0
Stores the element db_element in the database under the name name and with the privacy level privacy.
The interface for creating types.
Definition: itype.h:716
virtual const IType_array * create_immediate_sized_array(const IType *element_type, Size size) const =0
Creates a new instance of an immediate-sized array type.
@ TS_2D
Two-dimensional texture.
Definition: itype.h:559
@ TK_COLOR
The color type. See mi::neuraylib::IType_color.
Definition: itype.h:174
@ TK_INT
The integer type. See mi::neuraylib::IType_int.
Definition: itype.h:160
@ TK_FLOAT
The float type. See mi::neuraylib::IType_float.
Definition: itype.h:164
The interface for creating values.
Definition: ivalue.h:660
virtual IValue_texture * create_texture(const IType_texture *type, const char *value) const =0
Creates a new texture value, or returns NULL in case of errors.
virtual IValue_string * create_string(const char *value="") const =0
Creates a new value of type string.
virtual IValue_bool * create_bool(bool value=false) const =0
Creates a new value of type boolean.
virtual IValue_enum * create_enum(const IType_enum *type, Size index=0) const =0
Creates a new value of type enum, or returns NULL in case of errors.
virtual IValue_bsdf_measurement * create_bsdf_measurement(const char *value) const =0
Creates a new BSDF measurement value, or returns NULL in case of errors.
virtual IValue_vector * create_vector(const IType_vector *type) const =0
Creates a new value of type vector, or returns NULL in case of errors.
virtual IValue_array * create_array(const IType_array *type) const =0
Creates a new value of type array, or returns NULL in case of errors.
virtual IValue_int * create_int(Sint32 value=0) const =0
Creates a new value of type integer.
virtual IValue_float * create_float(Float32 value=0.0f) const =0
Creates a new value of type float.
virtual IValue_color * create_color(Float32 red=0.0f, Float32 green=0.0f, Float32 blue=0.0f) const =0
Creates a new value of type color.
A value of type integer.
Definition: ivalue.h:125
Handle<Interface> make_handle(Interface *iptr)
Returns a handle that holds the interface pointer passed in as argument.
Definition: handle.h:428
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
@ 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_ERROR
An error has occurred.
Definition: enums.h:35
unsigned char Uint8
8-bit unsigned integer.
Definition: types.h:47
Uint64 Size
Unsigned integral type that is large enough to hold the size of all types.
Definition: types.h:112
@ MDL_VERSION_1_0
MDL version 1.0.
Definition: iexpression.h:29
@ MDL_VERSION_LATEST
Latest MDL version.
Definition: iexpression.h:40
@ BSDF_SCALAR
One scalar per grid value.
Definition: ibsdf_isotropic_data.h:24
@ BSDF_RGB
Three scalars (RGB) per grid value.
Definition: ibsdf_isotropic_data.h:25
Common namespace for APIs of NVIDIA Advanced Rendering Center GmbH.
Definition: example_derivatives.dox:5