USD IO: texture wrap and vertex color fixes.

Added logic to convert between tex image node extension enum
and UsdUVTexture wrapS and wrapT inputs on import and export.

Fixed bug where loop color data was incorrectly cast to MCol
rather than MLoopCol, causing the wrong vertex colors to be
exported.

The 'displayColor' primvar was being incorrectly imported as
'displayColors' (plural), causing this attribute to be
incorrectly named when exporting back to USD in round trips.
This commit is contained in:
Michael Kowalski 2022-03-20 16:33:20 -04:00
parent 1e13fc105a
commit 2b6306c1ea
4 changed files with 92 additions and 7 deletions

View File

@ -74,6 +74,13 @@ static const pxr::TfToken varname("varname", pxr::TfToken::Immortal);
static const pxr::TfToken raw("raw", pxr::TfToken::Immortal);
static const pxr::TfToken RAW("RAW", pxr::TfToken::Immortal);
/* Wrap mode names. */
static const pxr::TfToken black("black", pxr::TfToken::Immortal);
static const pxr::TfToken clamp("clamp", pxr::TfToken::Immortal);
static const pxr::TfToken repeat("repeat", pxr::TfToken::Immortal);
static const pxr::TfToken wrapS("wrapS", pxr::TfToken::Immortal);
static const pxr::TfToken wrapT("wrapT", pxr::TfToken::Immortal);
/* USD shader names. */
static const pxr::TfToken UsdPreviewSurface("UsdPreviewSurface", pxr::TfToken::Immortal);
static const pxr::TfToken UsdPrimvarReader_float2("UsdPrimvarReader_float2",
@ -313,6 +320,40 @@ static pxr::TfToken get_source_color_space(const pxr::UsdShadeShader &usd_shader
return pxr::TfToken();
}
static int get_image_extension(const pxr::UsdShadeShader &usd_shader, const int default_value)
{
pxr::UsdShadeInput wrap_input = usd_shader.GetInput(usdtokens::wrapS);
if (!wrap_input) {
wrap_input = usd_shader.GetInput(usdtokens::wrapT);
}
if (!wrap_input) {
return default_value;
}
pxr::VtValue wrap_input_val;
if (!(wrap_input.Get(&wrap_input_val) && wrap_input_val.IsHolding<pxr::TfToken>())) {
return default_value;
}
pxr::TfToken wrap_val = wrap_input_val.Get<pxr::TfToken>();
if (wrap_val == usdtokens::repeat) {
return SHD_IMAGE_EXTENSION_REPEAT;
}
if (wrap_val == usdtokens::clamp) {
return SHD_IMAGE_EXTENSION_EXTEND;
}
if (wrap_val == usdtokens::black) {
return SHD_IMAGE_EXTENSION_CLIP;
}
return default_value;
}
/* Attempts to return in r_preview_surface the UsdPreviewSurface shader source
* of the given material. Returns true if a UsdPreviewSurface source was found
* and returns false otherwise. */
@ -843,6 +884,9 @@ void USDMaterialReader::load_tex_image(const pxr::UsdShadeShader &usd_shader,
if (ELEM(color_space, usdtokens::RAW, usdtokens::raw)) {
STRNCPY(image->colorspace_settings.name, "Raw");
}
NodeTexImage *storage = static_cast<NodeTexImage *>(tex_image->storage);
storage->extension = get_image_extension(usd_shader, storage->extension);
}
/* This function creates a Blender UV Map node, under the simplifying assumption that

View File

@ -494,10 +494,10 @@ void USDMeshReader::read_colors(Mesh *mesh, const double motionSampleTime)
return;
}
void *cd_ptr = add_customdata_cb(mesh, "displayColors", CD_MLOOPCOL);
void *cd_ptr = add_customdata_cb(mesh, "displayColor", CD_MLOOPCOL);
if (!cd_ptr) {
std::cerr << "WARNING: Couldn't add displayColors custom data.\n";
std::cerr << "WARNING: Couldn't add displayColor custom data.\n";
return;
}

View File

@ -78,6 +78,11 @@ static const pxr::TfToken raw("raw", pxr::TfToken::Immortal);
static const pxr::TfToken sRGB("sRGB", pxr::TfToken::Immortal);
static const pxr::TfToken sourceColorSpace("sourceColorSpace", pxr::TfToken::Immortal);
static const pxr::TfToken Shader("Shader", pxr::TfToken::Immortal);
static const pxr::TfToken black("black", pxr::TfToken::Immortal);
static const pxr::TfToken clamp("clamp", pxr::TfToken::Immortal);
static const pxr::TfToken repeat("repeat", pxr::TfToken::Immortal);
static const pxr::TfToken wrapS("wrapS", pxr::TfToken::Immortal);
static const pxr::TfToken wrapT("wrapT", pxr::TfToken::Immortal);
} // namespace usdtokens
/* Cycles specific tokens (Blender Importer and HdCycles) */
@ -711,6 +716,36 @@ static pxr::TfToken get_node_tex_image_color_space(bNode *node)
return color_space;
}
static pxr::TfToken get_node_tex_image_wrap(bNode *node)
{
if (node->type != SH_NODE_TEX_IMAGE) {
std::cout << "get_node_tex_image_wrap() called with unexpected type.\n";
return pxr::TfToken();
}
if (node->storage == nullptr) {
return pxr::TfToken();
}
NodeTexImage *tex_image = static_cast<NodeTexImage *>(node->storage);
pxr::TfToken wrap;
switch (tex_image->extension) {
case SHD_IMAGE_EXTENSION_REPEAT:
wrap = usdtokens::repeat;
break;
case SHD_IMAGE_EXTENSION_EXTEND:
wrap = usdtokens::clamp;
break;
case SHD_IMAGE_EXTENSION_CLIP:
wrap = usdtokens::black;
break;
}
return wrap;
}
static const int HD_CYCLES_CURVE_EXPORT_RES = 256;
/**
@ -1189,6 +1224,12 @@ pxr::UsdShadeShader create_usd_preview_shader_node(const USDExporterContext &usd
.Set(colorSpace);
}
pxr::TfToken wrap = get_node_tex_image_wrap(node);
if (!wrap.IsEmpty()) {
shader.CreateInput(usdtokens::wrapS, pxr::SdfValueTypeNames->Token).Set(wrap);
shader.CreateInput(usdtokens::wrapT, pxr::SdfValueTypeNames->Token).Set(wrap);
}
if (usd_export_context.export_params.export_textures) {
export_texture(node, usd_export_context.stage);
}

View File

@ -283,13 +283,13 @@ void USDGenericMeshWriter::write_vertex_colors(const Mesh *mesh,
pxr::UsdGeomPrimvar vertex_colors_pv = pvApi.CreatePrimvar(
primvar_name, pxr::SdfValueTypeNames->Color3fArray, pxr::UsdGeomTokens->faceVarying);
MCol *vertCol = static_cast<MCol *>(layer->data);
MLoopCol *vertCol = static_cast<MLoopCol *>(layer->data);
pxr::VtArray<pxr::GfVec3f> vertex_colors;
for (int loop_idx = 0; loop_idx < mesh->totloop; loop_idx++) {
pxr::GfVec3f col = pxr::GfVec3f((int)vertCol[loop_idx].b * cscale,
(int)vertCol[loop_idx].g * cscale,
(int)vertCol[loop_idx].r * cscale);
for (int loop_idx = 0; loop_idx < mesh->totloop; ++loop_idx) {
pxr::GfVec3f col = pxr::GfVec3f(vertCol[loop_idx].r * cscale,
vertCol[loop_idx].g * cscale,
vertCol[loop_idx].b * cscale);
vertex_colors.push_back(col);
}