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 clearcoat per the Filament and the KHR_materials_clearcoat specifications. #13031

Merged
merged 30 commits into from
May 5, 2024

Conversation

pcwalton
Copy link
Contributor

@pcwalton pcwalton commented Apr 19, 2024

Clearcoat is a separate material layer that represents a thin translucent layer of a material. Examples include (from the Filament spec) car paint, soda cans, and lacquered wood. This commit implements support for clearcoat following the Filament and Khronos specifications, marking the beginnings of support for multiple PBR layers in Bevy.

The KHR_materials_clearcoat specification describes the clearcoat support in glTF. In Blender, applying a clearcoat to the Principled BSDF node causes the clearcoat settings to be exported via this extension. As of this commit, Bevy parses and reads the extension data when present in glTF. Note that the gltf crate has no support for KHR_materials_clearcoat; this patch therefore implements the JSON semantics manually.

Clearcoat is integrated with StandardMaterial, but the code is behind a series of #ifdefs that only activate when clearcoat is present. Additionally, the pbr_feature_layer_material_textures Cargo feature must be active in order to enable support for clearcoat factor maps, clearcoat roughness maps, and clearcoat normal maps. This approach mirrors the same pattern used by the existing transmission feature and exists to avoid running out of texture bindings on platforms like WebGL and WebGPU. Note that constant clearcoat factors and roughness values are supported in the browser; only the relatively-less-common maps are disabled on those platforms.

This patch refactors the lighting code in StandardMaterial significantly in order to better support multiple layers in a natural way. That code was due for a refactor in any case, so this is a nice improvement.

A new demo, clearcoat, has been added. It's based on the corresponding three.js demo, but all the assets (aside from the skybox and environment map) are my original work.

Screenshot 2024-04-19 101143

Screenshot 2024-04-19 102054

Changelog

Added

  • StandardMaterial now supports a clearcoat layer, which represents a thin translucent layer over an underlying material.
  • The glTF loader now supports the KHR_materials_clearcoat extension, representing materials with clearcoat layers.

Migration Guide

  • The lighting functions in the pbr_lighting WGSL module now have clearcoat parameters, if STANDARD_MATERIAL_CLEARCOAT is defined.

  • The R reflection vector parameter has been removed from some lighting functions, as it was unused.

@pcwalton pcwalton added C-Enhancement A new feature A-Rendering Drawing game state to the screen labels Apr 19, 2024
@pcwalton pcwalton added this to the 0.14 milestone Apr 19, 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.

Copy link
Contributor

You added a new feature but didn't update the readme. Please run cargo run -p build-templated-pages -- update features to update it, and commit the file change.

specifications.

Clearcoat is a separate material layer that represents a thin
translucent layer of a material. Examples include (from the [Filament
spec]) car paint, soda cans, and lacquered wood. This commit implements
support for clearcoat following the Filament and Khronos specifications,
marking the beginnings of support for multiple PBR layers in Bevy.

The [`KHR_materials_clearcoat`] specification describes the clearcoat
support in glTF. In Blender, applying a clearcoat to the Principled BSDF
node causes the clearcoat settings to be exported via this extension.
As of this commit, Bevy parses and reads the extension data when present
in glTF. Note that the `gltf` crate has no support for
`KHR_materials_clearcoat`; this patch therefore implements the JSON
semantics manually.

Clearcoat is integrated with `StandardMaterial`, but the code is behind
a series of `#ifdef`s that only activate when clearcoat is present.
Additionally, the `pbr_feature_layer_material_textures` Cargo feature
must be active in order to enable support for clearcoat factor maps,
clearcoat roughness maps, and clearcoat normal maps. This approach
mirrors the same pattern used by the existing transmission feature and
exists to avoid running out of texture bindings on platforms like WebGL
and WebGPU. Note that constant clearcoat factors and roughness values
*are* supported in the browser; only the relatively-less-common maps are
disabled on those platforms.

This patch refactors the lighting code in `StandardMaterial`
significantly in order to better support multiple layers in a natural
way. That code was due for a refactor in any case, so this is a nice
improvement.

A new demo, `clearcoat`, has been added. It's based on [the
corresponding three.js demo], but all the assets are my original work.

[Filament spec]: https://google.github.io/filament/Filament.html#materialsystem/clearcoatmodel

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

[the corresponding three.js demo]: https://threejs.org/examples/webgl_materials_physical_clearcoat.html
Copy link
Contributor

@robtfm robtfm left a comment

Choose a reason for hiding this comment

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

just a first pass. the changes to the core lighting functions are pretty extensive, @mockersf could we please run a demo comparison?

i think we need to make proper efforts to stop the lighting code becoming more write-only than it already is. not saying this makes it much worse than it already was, but it's honestly very hard to follow.

it would also be nice to improve the example a bit (the three.js one is nicer, and i don't think their implementation is better) but that can certainly be done later.

Cargo.toml Outdated Show resolved Hide resolved

impl ClearcoatExtension {
#[allow(unused_variables)]
fn parse(
Copy link
Contributor

Choose a reason for hiding this comment

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

could this be upstreamed?

Copy link
Contributor Author

@pcwalton pcwalton Apr 22, 2024

Choose a reason for hiding this comment

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

There is a PR: gltf-rs/gltf#362

And it's been sitting since 2022. :( gltf doesn't seem to be well maintained. I pinged the maintainer, but I don't think we can realistically block this PR on that...

crates/bevy_pbr/src/render/pbr_fragment.wgsl Outdated Show resolved Hide resolved
crates/bevy_pbr/src/render/pbr_functions.wgsl Show resolved Hide resolved
crates/bevy_pbr/src/render/pbr_functions.wgsl Outdated Show resolved Hide resolved
crates/bevy_pbr/src/render/pbr_functions.wgsl Outdated Show resolved Hide resolved
Comment on lines +825 to +829
#[cfg(feature = "pbr_multi_layer_material_textures")]
{
if self.clearcoat_texture.is_some() {
flags |= StandardMaterialFlags::CLEARCOAT_TEXTURE;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

nitpick - these flags should probably be added in the prepass as well in case anybody wants to use them

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't know what this means. The prepass doesn't care about any of these flags, and we don't do this anywhere else (grepping for e.g. BASE_COLOR brings up nothing related to prepasses, except for alpha discard, which isn't relevant here).

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah I wouldn't add them. Sometime soon we should revisit how pipeline keys are managed however.

@pcwalton
Copy link
Contributor Author

@robtfm How would you like me to improve the example? I wanted to include a transparent one because @JMS55 asked me how clearcoat looked with transparency. Should I add more of a noise pattern to the car paint? Redo the golf ball texture?

@pcwalton
Copy link
Contributor Author

@robtfm I tried to improve the lighting code as I went and make it as easy to follow as possible. Sorry to hear that I didn't succeed :( Do you have any suggestions?

@robtfm
Copy link
Contributor

robtfm commented Apr 22, 2024

@robtfm How would you like me to improve the example? I wanted to include a transparent one because @JMS55 asked me how clearcoat looked with transparency. Should I add more of a noise pattern to the car paint? Redo the golf ball texture?

i think the main issue i have is the specular aliasing from the normal maps. it seems less "bitty" in the 3js version. perhaps just downres the normal map, or just use a smaller one maybe so the single pixel highlights are less frequent?
the texture on the carpaint is nicer in 3js as well (and the spinning spheres) but i'm not sure that's worth adding a new texture for.

@robtfm I tried to improve the lighting code as I went and make it as easy to follow as possible. Sorry to hear that I didn't succeed :( Do you have any suggestions?

yes sorry, i didn't mean to sound so critical. i think if you hadn't made such an effort it would be much worse, whereas now it's not much worse, and with more functionality. the 2 specific comments about a param struct and factoring the meshlet sample were the main things i thought would help. i guess if the lighting functions api is clean then at least the trickier stuff is more contained.

@pcwalton
Copy link
Contributor Author

@robtfm I believe every comment has been addressed. pbr_lighting.wgsl has been largely rewritten. I made the spheres rotate, added some blur and decreased the levels on the scratch normal map, added some subtle blue noise as a normal map to the car paint, and switched to ACES filmic tonemapping, as this is what makes the normal map on the car paint in three.js appear purple.

Screenshot 2024-04-22 160935

@mockersf
Copy link
Member

mockersf commented Apr 22, 2024

just a first pass. the changes to the core lighting functions are pretty extensive, @mockersf could we please run a demo comparison?

Mostly good, just a change in the transmission example:
https://pixel-eagle.vleue.com/project/B25A040A-A980-4602-B90C-D480AB84076D/run/852/compare/840?screenshot=3D%20Rendering/transmission.png

@pcwalton
Copy link
Contributor Author

How do I get rid of the GitHub typos check on Fo?

@pcwalton pcwalton requested review from robtfm and JMS55 April 30, 2024 03:59
Copy link
Contributor

@robtfm robtfm left a comment

Choose a reason for hiding this comment

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

looks good!

we should probably add something to the migration guide mentioning the changes required for custom prepasses/shaders that use apply_normal_mapping.

@superdump
Copy link
Contributor

I’ve read the discussion, has any GPU-profiling/benchmarking been done across vendors to see what impact the shader refactoring has on performance without clear coat?

@pcwalton
Copy link
Contributor Author

pcwalton commented May 1, 2024

On NVIDIA, warp occupancy and register count are identical both before and after this PR.

Screenshot 2024-05-01 150843

Screenshot 2024-05-01 151432

@Elabajaba
Copy link
Contributor

I did a quick test on my amd 6800xt, register pressure was identical and performance was the same according to radeon gpu profiler.

@NthTensor
Copy link
Contributor

No obvious performance differences for me testing vs main. What's blocking this moving forward? The more general changes seem like a marked improvement in standardization and code quality.

@pcwalton
Copy link
Contributor Author

pcwalton commented May 2, 2024

@NthTensor It only has one approval. Having a second approval would be very helpful.

@pcwalton pcwalton closed this May 3, 2024
@pcwalton
Copy link
Contributor Author

pcwalton commented May 3, 2024

Closing as I am burned out and have no motivation to get this landed anymore.

@pcwalton pcwalton reopened this May 4, 2024
@alice-i-cecile alice-i-cecile added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it X-Contentious There are nontrivial implications that should be thought through labels May 4, 2024
@alice-i-cecile
Copy link
Member

@pcwalton once merge conflicts are resolved this should be good to merge. Do reach out if you'd like a hand with that.

@pcwalton
Copy link
Contributor Author

pcwalton commented May 5, 2024

Updated.

@alice-i-cecile
Copy link
Member

I'm comfortable with the thoroughness and expertise of the reviews here, and this isn't a controversial addition. Merging.

@alice-i-cecile alice-i-cecile added this pull request to the merge queue May 5, 2024
Merged via the queue into bevyengine:main with commit 77ed72b May 5, 2024
31 checks passed
pcwalton added a commit to pcwalton/bevy that referenced this pull request May 6, 2024
github-merge-queue bot pushed a commit that referenced this pull request May 6, 2024
github-merge-queue bot pushed a commit that referenced this pull request May 16, 2024
…ng_input.F_ab (#13379)

# Objective

- The clearcoat PR #13031 had a small typo which broke transmission
- Fixes #13284

## Solution

- Set transmissive_lighting_input.F_ab to the correct value


![transmission_fix](https://github.com/bevyengine/bevy/assets/688816/92158117-de3a-4fa5-8af8-dcbd1d5eee04)
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 S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it X-Contentious There are nontrivial implications that should be thought through
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants