USD import: Alab v2 load errors.

Work in progress addressing issues loading the Alab v2 scene.

Load primvars of type Float2Array as texture coordinates.
Fixed type mismatch loading UsdPrimvarReader_float2 varname input.
For materials that have an authored opacity value, changed the blend
mode from Alpha Blend to Alpha Hashed, to mitigate object soring issue.
Added import option to specify loading materials by purpose to allow
explicitly loading full materials for debugging.
This commit is contained in:
Michael Kowalski 2022-08-16 22:15:13 -04:00
parent 659b63751d
commit 5649158db9
4 changed files with 116 additions and 23 deletions

View File

@ -71,6 +71,28 @@ const EnumPropertyItem rna_enum_usd_mtl_name_collision_mode_items[] = {
{0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_usd_mtl_purpose_items[] = {
{USD_MTL_PURPOSE_ALL,
"MTL_ALL_PURPOSE",
0,
"All Purpose",
"Attempt to import 'allPurpose' materials. "
"Load 'preview' and 'full' materials as a fallback, in that order"},
{USD_MTL_PURPOSE_PREVIEW,
"MTL_PREVIEW",
0,
"Preview",
"Attempt to import 'preview' materials. "
"Load 'allPurpose' and 'full' materials as a fallback, in that order"},
{USD_MTL_PURPOSE_FULL,
"MTL_FULL",
0,
"Full",
"Attempt to import 'full' materials. "
"Load 'allPurpose' and 'preview' materials as a fallback, in that order"},
{0, NULL, 0, NULL, NULL},
};
/* Stored in the wmOperator's customdata field to indicate it should run as a background job.
* This is set when the operator is invoked, and not set when it is only executed. */
enum { AS_BACKGROUND_JOB = 1 };
@ -388,6 +410,8 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
const eUSDMtlNameCollisionMode mtl_name_collision_mode = RNA_enum_get(op->ptr,
"mtl_name_collision_mode");
const eUSDMtlPurpose mtl_purpose = RNA_enum_get(op->ptr, "mtl_purpose");
/* TODO(makowalski): Add support for sequences. */
const bool is_sequence = false;
int offset = 0;
@ -427,7 +451,8 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
.import_usd_preview = import_usd_preview,
.set_material_blend = set_material_blend,
.light_intensity_scale = light_intensity_scale,
.mtl_name_collision_mode = mtl_name_collision_mode};
.mtl_name_collision_mode = mtl_name_collision_mode,
.mtl_purpose = mtl_purpose};
const bool ok = USD_import(C, filename, &params, as_background_job);
@ -479,6 +504,8 @@ static void wm_usd_import_draw(bContext *UNUSED(C), wmOperator *op)
uiLayout *row = uiLayoutRow(col, true);
uiItemR(row, ptr, "set_material_blend", 0, NULL, ICON_NONE);
uiLayoutSetEnabled(row, RNA_boolean_get(ptr, "import_usd_preview"));
row = uiLayoutRow(col, true);
uiItemR(row, ptr, "mtl_purpose", 0, NULL, ICON_NONE);
}
void WM_OT_usd_import(struct wmOperatorType *ot)
@ -585,6 +612,16 @@ void WM_OT_usd_import(struct wmOperatorType *ot)
"the material blend method will automatically be set based on the "
"shader's opacity and opacityThreshold inputs");
RNA_def_enum(
ot->srna,
"mtl_purpose",
rna_enum_usd_mtl_purpose_items,
USD_MTL_PURPOSE_ALL,
"Material Purpose",
"Attempt to import materials with the given purpose. "
"If no material with this purpose is bound to the primitive, "
"fall back on loading any other bound material");
RNA_def_float(ot->srna,
"light_intensity_scale",
1.0f,

View File

@ -393,7 +393,7 @@ void USDMaterialReader::import_usd_preview(Material *mtl,
mtl->alpha_threshold = opacity_threshold;
}
else {
mtl->blend_method = MA_BM_BLEND;
mtl->blend_method = MA_BM_HASHED;
}
}
}
@ -740,11 +740,18 @@ void USDMaterialReader::convert_usd_primvar_reader_float2(
}
/* Set the texmap name. */
pxr::UsdShadeInput varname_input = usd_shader.GetInput(usdtokens::varname);
if (varname_input) {
if (pxr::UsdShadeInput varname_input = usd_shader.GetInput(usdtokens::varname)) {
/* According to the current USD Preview Surface specification, the 'varname' input
* is a string. However, for backward compatibility with previous USD versions, we
* also handle TfToken values for this input. */
pxr::VtValue varname_val;
if (varname_input.Get(&varname_val) && varname_val.IsHolding<pxr::TfToken>()) {
std::string varname = varname_val.Get<pxr::TfToken>().GetString();
if (varname_input.Get(&varname_val)) {
std::string varname;
if (varname_val.IsHolding<std::string>()) {
varname = varname_val.Get<std::string>();
} else if (varname_val.IsHolding<pxr::TfToken>()) {
varname = varname_val.Get<pxr::TfToken>().GetString();
}
if (!varname.empty()) {
NodeShaderUVMap *storage = (NodeShaderUVMap *)uv_map->storage;
BLI_strncpy(storage->uv_map, varname.c_str(), sizeof(storage->uv_map));

View File

@ -62,21 +62,42 @@ static void build_mat_map(const Main *bmain, std::map<std::string, Material *> *
}
}
static pxr::UsdShadeMaterial compute_bound_material(const pxr::UsdPrim &prim)
static pxr::UsdShadeMaterial compute_bound_material(const pxr::UsdPrim &prim, eUSDMtlPurpose purpose)
{
pxr::UsdShadeMaterial mtl;
pxr::UsdShadeMaterialBindingAPI api = pxr::UsdShadeMaterialBindingAPI(prim);
/* Compute generically bound ('allPurpose') materials. */
pxr::UsdShadeMaterial mtl = api.ComputeBoundMaterial();
/* If no generic material could be resolved, also check for 'preview' and
* 'full' purpose materials as fallbacks. */
if (!mtl) {
mtl = api.ComputeBoundMaterial(pxr::UsdShadeTokens->preview);
}
if (!mtl) {
mtl = api.ComputeBoundMaterial(pxr::UsdShadeTokens->full);
switch (purpose) {
case USD_MTL_PURPOSE_ALL:
mtl = api.ComputeBoundMaterial(pxr::UsdShadeTokens->allPurpose);
if (!mtl) {
mtl = api.ComputeBoundMaterial(pxr::UsdShadeTokens->preview);
}
if (!mtl) {
mtl = api.ComputeBoundMaterial(pxr::UsdShadeTokens->full);
}
break;
case USD_MTL_PURPOSE_PREVIEW:
mtl = api.ComputeBoundMaterial(pxr::UsdShadeTokens->preview);
if (!mtl) {
mtl = api.ComputeBoundMaterial(pxr::UsdShadeTokens->allPurpose);
}
if (!mtl) {
mtl = api.ComputeBoundMaterial(pxr::UsdShadeTokens->full);
}
break;
case USD_MTL_PURPOSE_FULL:
mtl = api.ComputeBoundMaterial(pxr::UsdShadeTokens->full);
if (!mtl) {
mtl = api.ComputeBoundMaterial(pxr::UsdShadeTokens->allPurpose);
}
if (!mtl) {
mtl = api.ComputeBoundMaterial(pxr::UsdShadeTokens->preview);
}
break;
default:
break;
}
return mtl;
@ -351,6 +372,14 @@ void USDMeshReader::read_uvs(Mesh *mesh, const double motionSampleTime, const bo
struct UVSample {
pxr::VtVec2fArray uvs;
pxr::TfToken interpolation;
/* The following is mutable as it might
* be modified for error reporting even
* when other members are const. */
mutable bool invalid_index_found;
UVSample() : invalid_index_found(false)
{
}
};
std::vector<UVSample> uv_primvars(ldata->totlayer);
@ -396,6 +425,8 @@ void USDMeshReader::read_uvs(Mesh *mesh, const double motionSampleTime, const bo
}
}
std::vector<int> warned_invalid_index_for_layer(ldata->totlayer);
for (int i = 0; i < face_counts_.size(); i++) {
const int face_size = face_counts_[i];
@ -435,8 +466,12 @@ void USDMeshReader::read_uvs(Mesh *mesh, const double motionSampleTime, const bo
loop_index;
if (usd_uv_index >= sample.uvs.size()) {
std::cerr << "WARNING: out of bounds uv index " << usd_uv_index << " for uv "
<< layer->name << " of size " << sample.uvs.size() << std::endl;
/* Out of bounds index. */
if (!sample.invalid_index_found) {
sample.invalid_index_found = true;
std::cerr << "WARNING: out of bounds index detected for uv layer " << layer->name
<< std::endl;
}
continue;
}
@ -756,7 +791,8 @@ void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime,
if (!subsets.empty()) {
for (const pxr::UsdGeomSubset &subset : subsets) {
pxr::UsdShadeMaterial subset_mtl = utils::compute_bound_material(subset.GetPrim());
pxr::UsdShadeMaterial subset_mtl =
utils::compute_bound_material(subset.GetPrim(), import_params_.mtl_purpose);
if (!subset_mtl) {
continue;
}
@ -786,7 +822,8 @@ void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime,
if (r_mat_map->empty()) {
pxr::UsdShadeMaterial mtl = utils::compute_bound_material(prim_);
pxr::UsdShadeMaterial mtl =
utils::compute_bound_material(prim_, import_params_.mtl_purpose);
if (mtl) {
pxr::SdfPath mtl_path = mtl.GetPath();
@ -850,7 +887,8 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh,
if (ELEM(type,
pxr::SdfValueTypeNames->TexCoord2hArray,
pxr::SdfValueTypeNames->TexCoord2fArray,
pxr::SdfValueTypeNames->TexCoord2dArray)) {
pxr::SdfValueTypeNames->TexCoord2dArray,
pxr::SdfValueTypeNames->Float2Array)) {
is_uv = true;
}
/* In some cases, the st primvar is stored as float2 values. */

View File

@ -22,6 +22,16 @@ typedef enum eUSDMtlNameCollisionMode {
USD_MTL_NAME_COLLISION_REFERENCE_EXISTING = 1,
} eUSDMtlNameCollisionMode;
/* Enums specifying the USD material purpose,
* corresponding to pxr::UsdShadeTokens 'allPurpose',
* 'preview', and 'render', respectively. */
typedef enum eUSDMtlPurpose {
USD_MTL_PURPOSE_ALL = 0,
USD_MTL_PURPOSE_PREVIEW = 1,
USD_MTL_PURPOSE_FULL = 2
} eUSDMtlPurpose;
struct USDExportParams {
bool export_animation;
bool export_hair;
@ -65,6 +75,7 @@ struct USDImportParams {
bool set_material_blend;
float light_intensity_scale;
eUSDMtlNameCollisionMode mtl_name_collision_mode;
eUSDMtlPurpose mtl_purpose;
};
/* The USD_export takes a as_background_job parameter, and returns a boolean.