Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement PBR anisotropy per KHR_materials_anisotropy. #13450

Merged
merged 7 commits into from
Jun 4, 2024

Conversation

pcwalton
Copy link
Contributor

This commit implements support for physically-based anisotropy in Bevy's StandardMaterial, following the specification for the KHR_materials_anisotropy glTF extension.

Anisotropy (not to be confused with anisotropic filtering) is a PBR feature that allows roughness to vary along the tangent and bitangent directions of a mesh. In effect, this causes the specular light to stretch out into lines instead of a round lobe. This is useful for modeling brushed metal, hair, and similar surfaces. Support for anisotropy is a common feature in major game and graphics engines; Unity, Unreal, Godot, three.js, and Blender all support it to varying degrees.

Two new parameters have been added to StandardMaterial: anisotropy_strength and anisotropy_rotation. Anisotropy strength, which ranges from 0 to 1, represents how much the roughness differs between the tangent and the bitangent of the mesh. In effect, it controls how stretched the specular highlight is. Anisotropy rotation allows the roughness direction to differ from the tangent of the model.

In addition to these two fixed parameters, an anisotropy texture can be supplied. Such a texture should be a 3-channel RGB texture, where the red and green values specify a direction vector using the same conventions as a normal map ([0, 1] color values map to [-1, 1] vector values), and the the blue value represents the strength. This matches the format that the KHR_materials_anisotropy specification requires. Such textures should be loaded as linear and not sRGB. Note that this texture does consume one additional texture binding in the standard material shader.

The glTF loader has been updated to properly parse the KHR_materials_anisotropy extension.

A new example, anisotropy, has been added. This example loads and displays the barn lamp example from the glTF-Sample-Assets repository. Note that the textures were rather large, so I shrunk them down and converted them to a mixture of JPEG and KTX2 format, in the interests of saving space in the Bevy repository.

Changelog

Added

  • Physically-based anisotropy is now available for materials, which enhances the look of surfaces such as brushed metal or hair. glTF scenes can use the new feature with the KHR_materials_anisotropy extension.

Screenshots

With anisotropy:
Screenshot 2024-05-20 233414

Without anisotropy:
Screenshot 2024-05-20 233420

This commit implements support for physically-based anisotropy in Bevy's
`StandardMaterial`, following the specification for the
[`KHR_materials_anisotropy`] glTF extension.

[*Anisotropy*] (not to be confused with [anisotropic filtering]) is a
PBR feature that allows roughness to vary along the tangent and
bitangent directions of a mesh. In effect, this causes the specular
light to stretch out into lines instead of a round lobe. This is useful
for modeling brushed metal, hair, and similar surfaces. Support for
anisotropy is a common feature in major game and graphics engines;
Unity, Unreal, Godot, three.js, and Blender all support it to varying
degrees.

Two new parameters have been added to `StandardMaterial`:
`anisotropy_strength` and `anisotropy_rotation`. Anisotropy strength,
which ranges from 0 to 1, represents how much the roughness differs
between the tangent and the bitangent of the mesh. In effect, it
controls how stretched the specular highlight is. Anisotropy rotation
allows the roughness direction to differ from the tangent of the model.

In addition to these two fixed parameters, an *anisotropy texture* can
be supplied. Such a texture should be a 3-channel RGB texture, where the
red and green values specify a direction vector using the same
conventions as a normal map ([0, 1] color values map to [-1, 1] vector
values), and the the blue value represents the strength. This matches
the format that the [`KHR_materials_anisotropy`] specification requires.
Such textures should be loaded as linear and not sRGB. Note that this
texture does consume one additional texture binding in the standard
material shader.

The glTF loader has been updated to properly parse the
`KHR_materials_anisotropy` extension.

A new example, `anisotropy`, has been added. This example loads and
displays the barn lamp example from the [`glTF-Sample-Assets`]
repository. Note that the textures were rather large, so I shrunk them
down and converted them to a mixture of JPEG and KTX2 format, in the
interests of saving space in the Bevy repository.

[*Anisotropy*]: https://google.github.io/filament/Filament.md.html#materialsystem/anisotropicmodel

[anisotropic filtering]: https://en.wikipedia.org/wiki/Anisotropic_filtering

[`KHR_materials_anisotropy`]: https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_anisotropy/README.md

[`glTF-Sample-Assets`]: https://github.com/KhronosGroup/glTF-Sample-Assets/
@pcwalton pcwalton added this to the 0.15 milestone May 21, 2024
@pcwalton pcwalton added A-Rendering Drawing game state to the screen C-Enhancement A new feature S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels May 21, 2024
Copy link
Contributor

The generated examples/README.md is out of sync with the example metadata in Cargo.toml or the example readme template. Please run cargo run -p build-templated-pages -- update examples to update it, and commit the file change.

@IceSentry IceSentry added the X-Uncontroversial This work is generally agreed upon label May 21, 2024
Copy link
Contributor

Choose a reason for hiding this comment

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

Any particular reason to keep this as jpeg?

You likely know but: basisu -ktx2 -uastc -mipmap foo.jpeg has worked nicely for me to get mipmaps.

Copy link
Contributor Author

@pcwalton pcwalton May 21, 2024

Choose a reason for hiding this comment

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

I think JPEG results in the smallest possible file size, and there's been a lot of discussion about keeping example files small in the repo. The original size was several MB. Mipmaps would increase size, which I didn't think was worth it as the textures look pretty good and the performance is fine.

Copy link
Contributor

@atlv24 atlv24 left a comment

Choose a reason for hiding this comment

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

love the specular normal mixing trick, and the example is very good too. sweet beans

/// Returns the index (within the `textures` array) of the texture with the
/// given field name in the data for the material extension with the given name,
/// if there is one.
#[cfg(feature = "pbr_multi_layer_material_textures")]
Copy link
Contributor

Choose a reason for hiding this comment

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

why was this removed?

Copy link
Contributor Author

@pcwalton pcwalton May 22, 2024

Choose a reason for hiding this comment

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

Anisotropy needs to use this function. Unlike clearcoat (the previous user of this function), anisotropy's textures aren't gated behind the pbr_multi_layer_material_textures feature, as it's not technically a separate layer. So the feature gate needs to be removed.

crates/bevy_pbr/src/pbr_material.rs Outdated Show resolved Hide resolved
@alice-i-cecile alice-i-cecile added the D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes label May 22, 2024
@IceSentry
Copy link
Contributor

The volumetric_fog example crashes with this PR.

wgpu error: Validation Error

Caused by:
    In a RenderPass
      note: encoder = `<CommandBuffer-(4, 75, Vulkan)>`
    In a set_bind_group command
      note: bind group = `mesh_view_bind_group`
    Bind group 0 expects 5 dynamic offsets. However 4 dynamic offsets were provided.

let F_ab = (*input).F_ab;

var Fr = (specular_intensity * D * V) * F;
Fr *= 1.0 + F0 * (1.0 / F_ab.x - 1.0);
Copy link
Contributor

Choose a reason for hiding this comment

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

The linked Filament doc uses dfg.y instead F_ab.x. I assume F_ab is the same as dfg, but is the .x vs .y correct?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, I see you just copied that from somewhere else. I guess we shouldn't touch this in this PR then.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, we might want to check this later but I just copy and pasted this one.

examples/3d/anisotropy.rs Outdated Show resolved Hide resolved
@pcwalton
Copy link
Contributor Author

pcwalton commented Jun 2, 2024

@IceSentry volumetric_fog runs fine for me now that I've updated this PR to main. Pretty sure this was the unrelated problem with SSR from earlier.

@pcwalton pcwalton requested a review from IceSentry June 2, 2024 17:47
Copy link
Contributor

@IceSentry IceSentry left a comment

Choose a reason for hiding this comment

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

I ran a bunch of examples again and found no new regressions

LGTM

@IceSentry IceSentry added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it C-Needs-Release-Note Work that should be called out in the blog due to impact and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jun 3, 2024
@alice-i-cecile alice-i-cecile modified the milestones: 0.15, 0.14 Jun 3, 2024
@alice-i-cecile alice-i-cecile added this pull request to the merge queue Jun 3, 2024
Merged via the queue into bevyengine:main with commit df8ccb8 Jun 4, 2024
33 checks passed
@alice-i-cecile
Copy link
Member

Thank you to everyone involved with the authoring or reviewing of this PR! This work is relatively important and needs release notes! Head over to bevyengine/bevy-website#1346 if you'd like to help out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen C-Enhancement A new feature C-Needs-Release-Note Work that should be called out in the blog due to impact D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it X-Uncontroversial This work is generally agreed upon
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants