Fix: USD import: Improve texture color space choice
Many assets with UsdPreviewSurface materials exist in which the textures do not have authored color space settings. Because of this, assets with normal maps and other non-color data look incorrect on import because these textures are marked as being sRGB instead of Non-Color. This patch fixes the color space choices for these textures based on connections to the PBR shader; if no color space is specified, non-Albedo maps get an automatic Non-Color assignment. Co-authored-by: Charles Wardlaw <kattkieru@users.noreply.github.com> Pull Request: https://projects.blender.org/blender/blender/pulls/113374
This commit is contained in:
committed by
Michael Kowalski
parent
d24a49da84
commit
b7fa45b68d
@@ -62,6 +62,8 @@ static const pxr::TfToken st("st", pxr::TfToken::Immortal);
|
||||
static const pxr::TfToken varname("varname", pxr::TfToken::Immortal);
|
||||
|
||||
/* Color space names. */
|
||||
static const pxr::TfToken auto_("auto", pxr::TfToken::Immortal);
|
||||
static const pxr::TfToken sRGB("sRGB", pxr::TfToken::Immortal);
|
||||
static const pxr::TfToken raw("raw", pxr::TfToken::Immortal);
|
||||
static const pxr::TfToken RAW("RAW", pxr::TfToken::Immortal);
|
||||
|
||||
@@ -548,12 +550,13 @@ void USDMaterialReader::set_principled_node_inputs(bNode *principled,
|
||||
/* Recursively set the principled shader inputs. */
|
||||
|
||||
if (pxr::UsdShadeInput diffuse_input = usd_shader.GetInput(usdtokens::diffuseColor)) {
|
||||
set_node_input(diffuse_input, principled, "Base Color", ntree, column, &context);
|
||||
set_node_input(diffuse_input, principled, "Base Color", ntree, column, &context, true);
|
||||
}
|
||||
|
||||
float emission_strength = 0.0f;
|
||||
if (pxr::UsdShadeInput emissive_input = usd_shader.GetInput(usdtokens::emissiveColor)) {
|
||||
if (set_node_input(emissive_input, principled, "Emission Color", ntree, column, &context)) {
|
||||
if (set_node_input(
|
||||
emissive_input, principled, "Emission Color", ntree, column, &context, true)) {
|
||||
emission_strength = 1.0f;
|
||||
}
|
||||
}
|
||||
@@ -562,37 +565,38 @@ void USDMaterialReader::set_principled_node_inputs(bNode *principled,
|
||||
((bNodeSocketValueFloat *)emission_strength_sock->default_value)->value = emission_strength;
|
||||
|
||||
if (pxr::UsdShadeInput specular_input = usd_shader.GetInput(usdtokens::specularColor)) {
|
||||
set_node_input(specular_input, principled, "Specular Tint", ntree, column, &context);
|
||||
set_node_input(specular_input, principled, "Specular Tint", ntree, column, &context, false);
|
||||
}
|
||||
|
||||
if (pxr::UsdShadeInput metallic_input = usd_shader.GetInput(usdtokens::metallic)) {
|
||||
;
|
||||
set_node_input(metallic_input, principled, "Metallic", ntree, column, &context);
|
||||
set_node_input(metallic_input, principled, "Metallic", ntree, column, &context, false);
|
||||
}
|
||||
|
||||
if (pxr::UsdShadeInput roughness_input = usd_shader.GetInput(usdtokens::roughness)) {
|
||||
set_node_input(roughness_input, principled, "Roughness", ntree, column, &context);
|
||||
set_node_input(roughness_input, principled, "Roughness", ntree, column, &context, false);
|
||||
}
|
||||
|
||||
if (pxr::UsdShadeInput coat_input = usd_shader.GetInput(usdtokens::clearcoat)) {
|
||||
set_node_input(coat_input, principled, "Coat Weight", ntree, column, &context);
|
||||
set_node_input(coat_input, principled, "Coat Weight", ntree, column, &context, false);
|
||||
}
|
||||
|
||||
if (pxr::UsdShadeInput coat_roughness_input = usd_shader.GetInput(usdtokens::clearcoatRoughness))
|
||||
{
|
||||
set_node_input(coat_roughness_input, principled, "Coat Roughness", ntree, column, &context);
|
||||
set_node_input(
|
||||
coat_roughness_input, principled, "Coat Roughness", ntree, column, &context, false);
|
||||
}
|
||||
|
||||
if (pxr::UsdShadeInput opacity_input = usd_shader.GetInput(usdtokens::opacity)) {
|
||||
set_node_input(opacity_input, principled, "Alpha", ntree, column, &context);
|
||||
set_node_input(opacity_input, principled, "Alpha", ntree, column, &context, false);
|
||||
}
|
||||
|
||||
if (pxr::UsdShadeInput ior_input = usd_shader.GetInput(usdtokens::ior)) {
|
||||
set_node_input(ior_input, principled, "IOR", ntree, column, &context);
|
||||
set_node_input(ior_input, principled, "IOR", ntree, column, &context, false);
|
||||
}
|
||||
|
||||
if (pxr::UsdShadeInput normal_input = usd_shader.GetInput(usdtokens::normal)) {
|
||||
set_node_input(normal_input, principled, "Normal", ntree, column, &context);
|
||||
set_node_input(normal_input, principled, "Normal", ntree, column, &context, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,7 +605,8 @@ bool USDMaterialReader::set_node_input(const pxr::UsdShadeInput &usd_input,
|
||||
const char *dest_socket_name,
|
||||
bNodeTree *ntree,
|
||||
const int column,
|
||||
NodePlacementContext *r_ctx) const
|
||||
NodePlacementContext *r_ctx,
|
||||
bool is_color_corrected) const
|
||||
{
|
||||
if (!(usd_input && dest_node && r_ctx)) {
|
||||
return false;
|
||||
@@ -610,7 +615,8 @@ bool USDMaterialReader::set_node_input(const pxr::UsdShadeInput &usd_input,
|
||||
if (usd_input.HasConnectedSource()) {
|
||||
/* The USD shader input has a connected source shader. Follow the connection
|
||||
* and attempt to convert the connected USD shader to a Blender node. */
|
||||
return follow_connection(usd_input, dest_node, dest_socket_name, ntree, column, r_ctx);
|
||||
return follow_connection(
|
||||
usd_input, dest_node, dest_socket_name, ntree, column, r_ctx, is_color_corrected);
|
||||
}
|
||||
else {
|
||||
/* Set the destination node socket value from the USD shader input value. */
|
||||
@@ -675,7 +681,8 @@ bool USDMaterialReader::follow_connection(const pxr::UsdShadeInput &usd_input,
|
||||
const char *dest_socket_name,
|
||||
bNodeTree *ntree,
|
||||
int column,
|
||||
NodePlacementContext *r_ctx) const
|
||||
NodePlacementContext *r_ctx,
|
||||
bool is_color_corrected) const
|
||||
{
|
||||
if (!(usd_input && dest_node && dest_socket_name && ntree && r_ctx)) {
|
||||
return false;
|
||||
@@ -721,12 +728,24 @@ bool USDMaterialReader::follow_connection(const pxr::UsdShadeInput &usd_input,
|
||||
link_nodes(ntree, normal_map, "Normal", dest_node, "Normal");
|
||||
|
||||
/* Now, create the Texture Image node input to the Normal Map "Color" input. */
|
||||
convert_usd_uv_texture(
|
||||
source_shader, source_name, normal_map, "Color", ntree, column + 2, r_ctx);
|
||||
convert_usd_uv_texture(source_shader,
|
||||
source_name,
|
||||
normal_map,
|
||||
"Color",
|
||||
ntree,
|
||||
column + 2,
|
||||
r_ctx,
|
||||
is_color_corrected);
|
||||
}
|
||||
else {
|
||||
convert_usd_uv_texture(
|
||||
source_shader, source_name, dest_node, dest_socket_name, ntree, column + 1, r_ctx);
|
||||
convert_usd_uv_texture(source_shader,
|
||||
source_name,
|
||||
dest_node,
|
||||
dest_socket_name,
|
||||
ntree,
|
||||
column + 1,
|
||||
r_ctx,
|
||||
is_color_corrected);
|
||||
}
|
||||
}
|
||||
else if (shader_id == usdtokens::UsdPrimvarReader_float2) {
|
||||
@@ -746,7 +765,8 @@ void USDMaterialReader::convert_usd_uv_texture(const pxr::UsdShadeShader &usd_sh
|
||||
const char *dest_socket_name,
|
||||
bNodeTree *ntree,
|
||||
const int column,
|
||||
NodePlacementContext *r_ctx) const
|
||||
NodePlacementContext *r_ctx,
|
||||
bool is_color_corrected) const
|
||||
{
|
||||
if (!usd_shader || !dest_node || !ntree || !dest_socket_name || !bmain_ || !r_ctx) {
|
||||
return;
|
||||
@@ -772,7 +792,7 @@ void USDMaterialReader::convert_usd_uv_texture(const pxr::UsdShadeShader &usd_sh
|
||||
cache_node(r_ctx->node_cache, usd_shader, tex_image);
|
||||
|
||||
/* Load the texture image. */
|
||||
load_tex_image(usd_shader, tex_image);
|
||||
load_tex_image(usd_shader, tex_image, is_color_corrected);
|
||||
}
|
||||
|
||||
/* Connect to destination node input. */
|
||||
@@ -784,7 +804,7 @@ void USDMaterialReader::convert_usd_uv_texture(const pxr::UsdShadeShader &usd_sh
|
||||
|
||||
/* Connect the texture image node "Vector" input. */
|
||||
if (pxr::UsdShadeInput st_input = usd_shader.GetInput(usdtokens::st)) {
|
||||
set_node_input(st_input, tex_image, "Vector", ntree, column, r_ctx);
|
||||
set_node_input(st_input, tex_image, "Vector", ntree, column, r_ctx, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -862,12 +882,13 @@ void USDMaterialReader::convert_usd_transform_2d(const pxr::UsdShadeShader &usd_
|
||||
|
||||
/* Connect the mapping node "Vector" input. */
|
||||
if (pxr::UsdShadeInput in_input = usd_shader.GetInput(usdtokens::in)) {
|
||||
set_node_input(in_input, mapping, "Vector", ntree, column, r_ctx);
|
||||
set_node_input(in_input, mapping, "Vector", ntree, column, r_ctx, false);
|
||||
}
|
||||
}
|
||||
|
||||
void USDMaterialReader::load_tex_image(const pxr::UsdShadeShader &usd_shader,
|
||||
bNode *tex_image) const
|
||||
bNode *tex_image,
|
||||
bool is_color_corrected) const
|
||||
{
|
||||
if (!(usd_shader && tex_image && tex_image->type == SH_NODE_TEX_IMAGE)) {
|
||||
return;
|
||||
@@ -962,8 +983,28 @@ void USDMaterialReader::load_tex_image(const pxr::UsdShadeShader &usd_shader,
|
||||
color_space = file_input.GetAttr().GetColorSpace();
|
||||
}
|
||||
|
||||
if (ELEM(color_space, usdtokens::RAW, usdtokens::raw)) {
|
||||
STRNCPY(image->colorspace_settings.name, "Raw");
|
||||
if (color_space.IsEmpty()) {
|
||||
/* At this point, assume the "auto" space and translate accordingly. */
|
||||
color_space = usdtokens::auto_;
|
||||
}
|
||||
|
||||
if (color_space == usdtokens::auto_) {
|
||||
/* If it's auto, determine whether to apply color correction based
|
||||
* on incoming connection (passed in from outer functions). */
|
||||
STRNCPY(image->colorspace_settings.name, is_color_corrected ? "sRGB" : "Non-Color");
|
||||
}
|
||||
|
||||
else if (color_space == usdtokens::sRGB) {
|
||||
STRNCPY(image->colorspace_settings.name, "sRGB");
|
||||
}
|
||||
|
||||
/*
|
||||
* Due to there being a lot of non-compliant USD assets out there, this is
|
||||
* a special case where we need to check for different spellings here.
|
||||
* On write, we are *only* using the correct, lower-case "raw" token.
|
||||
*/
|
||||
else if (ELEM(color_space, usdtokens::RAW, usdtokens::raw)) {
|
||||
STRNCPY(image->colorspace_settings.name, "Non-Color");
|
||||
}
|
||||
|
||||
NodeTexImage *storage = static_cast<NodeTexImage *>(tex_image->storage);
|
||||
|
||||
@@ -108,7 +108,8 @@ class USDMaterialReader {
|
||||
const char *dest_socket_name,
|
||||
bNodeTree *ntree,
|
||||
int column,
|
||||
NodePlacementContext *r_ctx) const;
|
||||
NodePlacementContext *r_ctx,
|
||||
bool is_color_corrected) const;
|
||||
|
||||
/**
|
||||
* Follow the connected source of the USD input to create corresponding inputs
|
||||
@@ -119,7 +120,8 @@ class USDMaterialReader {
|
||||
const char *dest_socket_name,
|
||||
bNodeTree *ntree,
|
||||
int column,
|
||||
NodePlacementContext *r_ctx) const;
|
||||
NodePlacementContext *r_ctx,
|
||||
bool is_color_corrected = false) const;
|
||||
|
||||
void convert_usd_uv_texture(const pxr::UsdShadeShader &usd_shader,
|
||||
const pxr::TfToken &usd_source_name,
|
||||
@@ -127,7 +129,8 @@ class USDMaterialReader {
|
||||
const char *dest_socket_name,
|
||||
bNodeTree *ntree,
|
||||
int column,
|
||||
NodePlacementContext *r_ctx) const;
|
||||
NodePlacementContext *r_ctx,
|
||||
bool is_color_corrected = false) const;
|
||||
|
||||
void convert_usd_transform_2d(const pxr::UsdShadeShader &usd_shader,
|
||||
bNode *dest_node,
|
||||
@@ -140,7 +143,9 @@ class USDMaterialReader {
|
||||
* Load the texture image node's texture from the path given by the USD shader's
|
||||
* file input value.
|
||||
*/
|
||||
void load_tex_image(const pxr::UsdShadeShader &usd_shader, bNode *tex_image) const;
|
||||
void load_tex_image(const pxr::UsdShadeShader &usd_shader,
|
||||
bNode *tex_image,
|
||||
bool is_color_corrected = false) const;
|
||||
|
||||
/**
|
||||
* This function creates a Blender UV Map node, under the simplifying assumption that
|
||||
|
||||
Reference in New Issue
Block a user