bugfix/usd_material_color_space #113374

Merged
Michael Kowalski merged 12 commits from CharlesWardlaw/blender:bugfix/usd_material_color_space into main 2023-12-06 18:18:07 +01:00

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.

Testing: I used the USDZ file available here: https://www.metmuseum.org/-/media/ar-files/mma-ar_1979_206_380_wooddiety_audio_v1_final_max.usdz?la=en&hash=586A61E96C9C5237A4751584BAFC32A8

Before the patch:
image

After the patch:
image

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. Testing: I used the USDZ file available here: https://www.metmuseum.org/-/media/ar-files/mma-ar_1979_206_380_wooddiety_audio_v1_final_max.usdz?la=en&hash=586A61E96C9C5237A4751584BAFC32A8 Before the patch: ![image](/attachments/184f769a-0dbd-4ce2-a45d-81893f60a6d8) After the patch: ![image](/attachments/5fee42f9-3571-41ba-9ff0-f6e54d885abf)
497 KiB
788 KiB
Charles Wardlaw added 6 commits 2023-10-07 00:27:10 +02:00
Charles Wardlaw requested review from Michael Kowalski 2023-10-07 00:27:28 +02:00
Charles Wardlaw added this to the USD project 2023-10-07 00:27:34 +02:00
Charles Wardlaw requested review from Hans Goudey 2023-10-11 15:42:33 +02:00
Charles Wardlaw added 1 commit 2023-10-11 15:43:45 +02:00
Member

I pulled this PR and built locally, can confirm this is working well for me. I also confirmed that my asset round-tripped OK.

I pulled this PR and built locally, can confirm this is working well for me. I also confirmed that my asset round-tripped OK.
Contributor

Many assets [...] do not have authored color space settings.

Which is a feature, with the default value of UsdUVTexture:sourceColorSpace being specified as 'auto'.

This patch fixes the color space choices for these textures based on connections to the PBR shader [...]

I'm afraid this violates the UsdPreviewSurface specification which states:

auto : Check for gamma/color space metadata in the texture file itself; if metadata is indicative of sRGB, mark texture as sRGB . If no relevant metadata is found, mark texture as sRGB if it is either 8-bit and has 3 channels or if it is 8-bit and has 4 channels. Otherwise, do not mark texture as sRGB and use texture data as it was read from the texture.

I think that the above behaviour is caused by two issues that do not get addressed by this PR.

  1. We do not implement 'auto', as Michael's comment states.
  2. The asset is just faulty. It should have 'sourceColorSpace:raw' authored on its normal maps, which is not the case.
> Many assets [...] do not have authored color space settings. Which is a feature, with the default value of UsdUVTexture:sourceColorSpace being specified as 'auto'. > This patch fixes the color space choices for these textures based on connections to the PBR shader [...] I'm afraid this violates the [UsdPreviewSurface specification](https://openusd.org/release/spec_usdpreviewsurface.html#texture-reader) which states: > auto : Check for gamma/color space metadata in the texture file itself; if metadata is indicative of sRGB, mark texture as sRGB . If no relevant metadata is found, mark texture as sRGB if it is either 8-bit and has 3 channels or if it is 8-bit and has 4 channels. Otherwise, do not mark texture as sRGB and use texture data as it was read from the texture. I think that the above behaviour is caused by two issues that do not get addressed by this PR. 1. We do not implement 'auto', as [Michael's comment](https://projects.blender.org/blender/blender/src/commit/92a19747f024882f21b6c9eee2edc6ff35b3494d/source/blender/io/usd/intern/usd_reader_material.cc#L788-L791) states. 2. The asset is just faulty. It should have 'sourceColorSpace:raw' authored on its normal maps, which is not the case.

This patch fixes the color space choices for these textures based on connections to the PBR shader [...]

I'm afraid this violates the UsdPreviewSurface specification which states:

auto : Check for gamma/color space metadata in the texture file itself; if metadata is indicative of sRGB, mark texture as sRGB . If no relevant metadata is found, mark texture as sRGB if it is either 8-bit and has 3 channels or if it is 8-bit and has 4 channels. Otherwise, do not mark texture as sRGB and use texture data as it was read from the texture.

I think that the above behaviour is caused by two issues that do not get addressed by this PR.

  1. We do not implement 'auto', as Michael's comment states.
  2. The asset is just faulty. It should have 'sourceColorSpace:raw' authored on its normal maps, which is not the case.

This occurred to me as well. It would be straightforward enough to check for sRGB color space with the following API:

#include <pxr/imaging/hio/image.h>

pxr::HioImageSharedPtr image_ptr = pxr::HioImage::OpenForReading(im_file);
bool isSRGB = image_ptr->IsColorSpaceSRGB();

However, the example asset would still be displayed incorrectly based on this test. Consequently, as you point out, the normal map should be authored with color space "raw".

To be honest, I'm a little on the fence about this, as it appears some DCCs do try to infer the color space, even if the asset does not strictly adhere to the standard.

@Matt-McLin @wave Do you have an opinion about this? Should we strictly adhere to the standard in this case and not try to infer the color space?

> > This patch fixes the color space choices for these textures based on connections to the PBR shader [...] > > I'm afraid this violates the [UsdPreviewSurface specification](https://openusd.org/release/spec_usdpreviewsurface.html#texture-reader) which states: > > auto : Check for gamma/color space metadata in the texture file itself; if metadata is indicative of sRGB, mark texture as sRGB . If no relevant metadata is found, mark texture as sRGB if it is either 8-bit and has 3 channels or if it is 8-bit and has 4 channels. Otherwise, do not mark texture as sRGB and use texture data as it was read from the texture. > > I think that the above behaviour is caused by two issues that do not get addressed by this PR. > 1. We do not implement 'auto', as [Michael's comment](https://projects.blender.org/blender/blender/src/commit/92a19747f024882f21b6c9eee2edc6ff35b3494d/source/blender/io/usd/intern/usd_reader_material.cc#L788-L791) states. > 2. The asset is just faulty. It should have 'sourceColorSpace:raw' authored on its normal maps, which is not the case. This occurred to me as well. It would be straightforward enough to check for sRGB color space with the following API: ``` #include <pxr/imaging/hio/image.h> pxr::HioImageSharedPtr image_ptr = pxr::HioImage::OpenForReading(im_file); bool isSRGB = image_ptr->IsColorSpaceSRGB(); ``` However, the example asset would still be displayed incorrectly based on this test. Consequently, as you point out, the normal map should be authored with color space "raw". To be honest, I'm a little on the fence about this, as it appears some DCCs do try to infer the color space, even if the asset does not strictly adhere to the standard. @Matt-McLin @wave Do you have an opinion about this? Should we strictly adhere to the standard in this case and not try to infer the color space?

I wonder if "Emission Color" should also be considered a color input and default to sRGB.

I wonder if "Emission Color" should also be considered a color input and default to sRGB.
Contributor

Yes, both emissiveColor and specularColor should be handled the same way as they are of type color3f.

Yes, both `emissiveColor` and `specularColor` should be handled the same way as they are of type color3f.
Michael Kowalski added the
Interest
USD
label 2023-11-16 19:17:14 +01:00

I just wanted to resume the discussion. In my opinion, it's acceptable to infer the color space, as is being done in this pull request, even if that doesn't strictly adhere to the specification.

Are there objections to accepting this approach?

I just wanted to resume the discussion. In my opinion, it's acceptable to infer the color space, as is being done in this pull request, even if that doesn't strictly adhere to the specification. Are there objections to accepting this approach?

@deadpin @Matt-McLin Please let me know if you have an opinion about this. Thanks!

@deadpin @Matt-McLin Please let me know if you have an opinion about this. Thanks!

Given that usdview is also "broken" for this asset I'm not sure. Part of why USD exists is to remove the ambiguity of older formats and robustly interchange scenes. Going out of our way to perpetuate a broken ecosystem won't help that goal even if a, probably under staffed, museum got caught up in the mess.

If the spec isn't helping make a decision here I'd at least want an issue filed on USDPreviewSurface so we can reference it in a comment as part of any checkin we do.

It's a slippery slope to follow even if it's an easy fix on our side.

Similarly, the use of, yet another, 3rd form of the "raw" token should be removed from the PR at least. As a reviewer I'm now left wondering why we don't do this for every other token we have or if we need even more combinations etc. These fixups have a cost and, if we do add them, they should be done separately so they're easily reverted if necessary.

Given that `usdview` is also "broken" for this asset I'm not sure. Part of why USD exists is to remove the ambiguity of older formats and robustly interchange scenes. Going out of our way to perpetuate a broken ecosystem won't help that goal even if a, probably under staffed, museum got caught up in the mess. If the spec isn't helping make a decision here I'd at least want an issue filed on USDPreviewSurface so we can reference it in a comment as part of any checkin we do. It's a slippery slope to follow even if it's an easy fix on our side. Similarly, the use of, yet another, 3rd form of the "raw" token should be removed from the PR at least. As a reviewer I'm now left wondering why we don't do this for every other token we have or if we need even more combinations etc. These fixups have a cost and, if we do add them, they should be done separately so they're easily reverted if necessary.
Member

@makowalski Sorry for the late replies here. @wave, Dhruv, and I discussed this PR several weeks ago and all agreed that it should move forward, specifically regarding treating the auto/non-specified colorspaces for normal inputs as non-color. We did not discuss this 3rd form of "raw", I don't have an opinion on this. We also did not specifically discuss metallic/roughness inputs, but I believe it makes sense there as well.

Note that I disagree that this violates the UsdPreviewSurface specification. In spite of this phrasing:

auto : Check for gamma/color space metadata in the texture file itself; if metadata is indicative of sRGB, mark texture as sRGB . If no relevant metadata is found, mark texture as sRGB if it is either 8-bit and has 3 channels or if it is 8-bit and has 4 channels. Otherwise, do not mark texture as sRGB and use texture data as it was read from the texture.

There is also this:

            Normal map data is commonly expected to be linearly encoded.
            However, many image-writing tools automatically set the profile
            of three-channel, 8-bit images to SRGB. To prevent an unwanted
            transformation, the sourceColorSpace must also be set to "raw".

The above is acknowledging that it is never correct for the normal inputs to be anything other than "raw", regardless of whether the source is 8-bit or seems to be SRGB. Thus it is always a mistake on the part of the asset author or authoring tool if this is anything other than "raw", and I believe this means we are doing a great service to the community by working around these mistakes on import, of which we have seen many examples in the wild.

@makowalski Sorry for the late replies here. @wave, Dhruv, and I discussed this PR several weeks ago and all agreed that it should move forward, specifically regarding treating the auto/non-specified colorspaces for normal inputs as non-color. We did not discuss this 3rd form of "raw", I don't have an opinion on this. We also did not specifically discuss metallic/roughness inputs, but I believe it makes sense there as well. Note that I disagree that this violates the UsdPreviewSurface specification. In spite of this phrasing: ``` auto : Check for gamma/color space metadata in the texture file itself; if metadata is indicative of sRGB, mark texture as sRGB . If no relevant metadata is found, mark texture as sRGB if it is either 8-bit and has 3 channels or if it is 8-bit and has 4 channels. Otherwise, do not mark texture as sRGB and use texture data as it was read from the texture. ``` There is also this: ``` Normal map data is commonly expected to be linearly encoded. However, many image-writing tools automatically set the profile of three-channel, 8-bit images to SRGB. To prevent an unwanted transformation, the sourceColorSpace must also be set to "raw". ``` The above is acknowledging that it is _never_ correct for the normal inputs to be anything other than "raw", regardless of whether the source is 8-bit or seems to be SRGB. Thus it is always a mistake on the part of the asset author or authoring tool if this is anything other than "raw", and I believe this means we are doing a great service to the community by working around these mistakes on import, of which we have seen many examples in the wild.
Member

@deadpin While comparing to usdview is a very reasonable thing in general, I have imagined the aim for Blender's importer functionality is different than for usdview. Probably we don't want Blender to be a reference tool to check the correctness of assets authored elsewhere? I think a focus on "it just works" is likely more beneficial to the broader Blender community here.

@deadpin While comparing to usdview is a very reasonable thing in general, I have imagined the aim for Blender's importer functionality is different than for usdview. Probably we don't want Blender to be a reference tool to check the correctness of assets authored elsewhere? I think a focus on "it just works" is likely more beneficial to the broader Blender community here.
Charles Wardlaw added 1 commit 2023-12-01 00:00:07 +01:00
Jesse Yurkovich requested changes 2023-12-01 06:44:41 +01:00
Jesse Yurkovich left a comment
Member

Alright, based on the meeting this morning, let's do this :) Can you merge in main as I think there's conflicts with your other recent change that was just checked in.

Alright, based on the meeting this morning, let's do this :) Can you merge in main as I think there's conflicts with your other recent change that was just checked in.
@ -801,0 +820,4 @@
color_space = usdtokens::auto_;
}
if (ELEM(color_space, usdtokens::auto_)) {

When comparing to just 1 item, you don't need to use the ELEM macro. Here and 1 other place just below this.

When comparing to just 1 item, you don't need to use the ELEM macro. Here and 1 other place just below this.
CharlesWardlaw marked this conversation as resolved
@ -102,2 +102,3 @@
int column,
NodePlacementContext *r_ctx) const;
NodePlacementContext *r_ctx,
bool is_color_corrected = false) const;

The blender style guide says to keep the r_ parameters grouped last but that will obviously conflict with the optional param. I think I'm fine with just making this a required parameter all-up even if that causes the set_node_input calls to be a bit more verbose. set_node_input is really the only func that makes use of the optional-ness anyhow as the other functions will always provide the param in some form.

The blender style guide says to keep the `r_` parameters grouped last but that will obviously conflict with the optional param. I think I'm fine with just making this a required parameter all-up even if that causes the `set_node_input` calls to be a bit more verbose. `set_node_input` is really the only func that makes use of the optional-ness anyhow as the other functions will always provide the param in some form.
CharlesWardlaw marked this conversation as resolved
Charles Wardlaw added 1 commit 2023-12-05 19:21:35 +01:00
Charles Wardlaw added 1 commit 2023-12-05 19:26:01 +01:00
Charles Wardlaw added 1 commit 2023-12-05 19:48:49 +01:00
Merge fixes
All checks were successful
buildbot/vexp-code-patch-coordinator Build done.
72fd523518
Jesse Yurkovich approved these changes 2023-12-05 20:39:54 +01:00
Michael Kowalski approved these changes 2023-12-06 15:37:47 +01:00

@blender-bot build

@blender-bot build

@CharlesWardlaw Would you mind running make format on the code, please?

Otherwise, the changes look good to me. Thank you!

@CharlesWardlaw Would you mind running `make format` on the code, please? Otherwise, the changes look good to me. Thank you!
Charles Wardlaw added 1 commit 2023-12-06 17:50:57 +01:00
Michael Kowalski merged commit b7fa45b68d into main 2023-12-06 18:18:07 +01:00
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset System
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Asset Browser Project
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
5 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#113374
No description provided.