Skip to content

Align channel promotion of image nodes with specification - #3073

Merged
jstone-lucasfilm merged 1 commit into
AcademySoftwareFoundation:mainfrom
jstone-lucasfilm:dev_image_channel_fix
Sep 19, 2026
Merged

jstone-lucasfilm merged 1 commit into
AcademySoftwareFoundation:mainfrom
jstone-lucasfilm:dev_image_channel_fix

Conversation

@jstone-lucasfilm

Copy link
Copy Markdown
Member

This changelist fixes the channel promotion of image nodes in hardware shading languages when sampling a file with fewer channels than the node type, following up on the OSL alpha alignment in #2985. The specification states that channels beyond those in the image file should be populated with zero, aside from the fourth channel which should be populated with one, so a color3 image reading a grayscale file should return its value in the red channel alone. Previously, the GLSL and MSL backends replicated the red channel of a single-channel image across RGB, so the same image node returned a gray result rather than a red one.

The following specific changes are included:

  • Remove the channel swizzles from GLTextureHandler and MetalTextureHandler. The default sampling of one and two-channel textures in OpenGL and Metal, the default sampling of three-channel textures in OpenGL, and the existing RGBA expansion of three-channel images in Metal all follow the promotion rule of the specification, matching the behavior of the OSL texture function. This also removes an inconsistency in Metal, where the swizzle was applied only when mipmaps were generated.
  • Update the brass_wire_mesh test material to read its single-channel albedo texture as a float and convert it to color3, preserving its appearance under the specified promotion rule.
  • Add an image_channels example to the texture test suite, reading a single-channel image through each output type, so that the promoted channels can be compared across shader generators in the render tests.

Note that content reading a single-channel file through a color3 image node will now render with its value in the red channel alone in GLSL and MSL, as it already did in OSL. Content that intends a gray result should read the file as a float image and promote it with a convert node, as shown in the updated brass_wire_mesh material.

This changelist fixes the channel promotion of `image` nodes in hardware shading languages when sampling a file with fewer channels than the node type, following up on the OSL alpha alignment in AcademySoftwareFoundation#2985.  The specification states that channels beyond those in the image file should be populated with zero, aside from the fourth channel which should be populated with one, so a `color3` `image` reading a grayscale file should return its value in the red channel alone.  Previously, the GLSL and MSL backends replicated the red channel of a single-channel image across RGB, so the same `image` node returned a gray result rather than a red one.

The following specific changes are included:

- Remove the channel swizzles from `GLTextureHandler` and `MetalTextureHandler`.  The default sampling of one and two-channel textures in OpenGL and Metal, the default sampling of three-channel textures in OpenGL, and the existing RGBA expansion of three-channel images in Metal all follow the promotion rule of the specification, matching the behavior of the OSL `texture` function.  This also removes an inconsistency in Metal, where the swizzle was applied only when mipmaps were generated.
- Update the `brass_wire_mesh` test material to read its single-channel albedo texture as a `float` and convert it to `color3`, preserving its appearance under the specified promotion rule.
- Add an `image_channels` example to the texture test suite, reading a single-channel image through each output type, so that the promoted channels can be compared across shader generators in the render tests.

Note that content reading a single-channel file through a `color3` `image` node will now render with its value in the red channel alone in GLSL and MSL, as it already did in OSL.  Content that intends a gray result should read the file as a `float` `image` and promote it with a `convert` node, as shown in the updated `brass_wire_mesh` material.

@meshula meshula left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From an OpenUSD perspective, this should not create differences in existing assets. Although Hio (Hyrda's image loader) potentially does channel propagating swizzles, that swizzle will occur before the texture is consumed by a shader. It is good to conform to a specification - whether a single channel is meant to be "red" or "gray" when occupying several channels is a question addressable by an intervening swizzle node in the shading graph, if need be.

@jstone-lucasfilm

Copy link
Copy Markdown
Member Author

Thanks @meshula, and I'll go ahead and merge this for inclusion in MaterialX v1.39.6.

@jstone-lucasfilm
jstone-lucasfilm merged commit 697d014 into AcademySoftwareFoundation:main Sep 19, 2026
36 checks passed
@jstone-lucasfilm
jstone-lucasfilm deleted the dev_image_channel_fix branch September 19, 2026 17:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants