diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..9ad74710 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,35 @@ + +# OpenPBR Change Log +This file gives a high level overview of the changes introduced between versions, relative to version 1.0. + +How to read this document : ✨ new feature  |  🎨 look-changing  |  πŸ› bug fix + +## [[1.1.1]](https://github.com/AcademySoftwareFoundation/OpenPBR/tree/v1.1.1) - April 17, 2026 +- πŸ› [Implementation flexibility](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/248) **#248**: Adds a new section to the specification formally stating that implementers of the specification are free to use approximations, for example for low-power constraints. +- πŸ› [Thin-walled subsurface](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/258) **#258**: Clarifies the interaction of `geometry_thin_walled` and subsurface and how it affects `subsurface_radius` and `subsurface_scale`. +- πŸ› [HDR emission color](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/260) **#260**: Allows values above 1 for `emission_color`. +- πŸ› [More examples](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/257) **#257**: Adds more material examples. +- πŸ› [MaterialX hints](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/265) **#265**: Adds MaterialX code generation hints. +- πŸ› [Metal edge tint and ignored thin-walled](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/300) **#300**: Fixes two issues in the MaterialX implementation, the edge tint was incorrectly multiplied by the specular weight (backported from **#240**) and `geometry_thin_walled` was not connected to the shader (backported from **AcademySoftwareFoundation/MaterialX#2759**). +- πŸ› [New logo](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/235) **#235**: Uses the new logo in the specification. +- πŸ› [Broken links](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/230) **#230**: Fixes broken links in the specification. +- πŸ› [Improved wording](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/218) **#218**: Adds various clarifications and rewordings to the specification. +- πŸ› [Added Changelog](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/289) **#289**: Adds a changelog to the project. +- πŸ› [New images](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/236) **#236**: Updates images for the model schematic illustration, glossy diffuse wood, fuzz roughness and new images for anisotropy. +- πŸ› [Revised thin-film section](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/262) **#262**: Expands the thin-film specification and revises it to make it clearer. + +## [[1.1]](https://github.com/AcademySoftwareFoundation/OpenPBR/tree/v1.1) - Jun 28, 2024 +- ✨ [Enable Zeltner sheen](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/217) **#217**: This change enables Zeltner sheen in the reference implementation of OpenPBR, leveraging the new functionality in MaterialX. +- 🎨 [Change thin film IOR default](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/211) **#211**: This won't make much difference to the look in implementations that ignore the adjacent IORs of the film, but for those that take it into account, this will make the film visible rather than invisible by default (since `specular_ior` is 1.5 by default, and `coat_ior` 1.6). +- 🎨 [Update subsurface color types](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/220) **#220**: Changes `subsurface_radius_scale` from `vector3` to `color3`, aligning the type with its per-channel usage. +- πŸ› [Updated OpenPBR default example](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/216) **#216**: Updates the OpenPBR default example, matching its values to the latest default values of the shading model. +- πŸ› [Allow darkening in fuzz](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/207) **#207**: Allows fuzz to darken as well as lighten the reflection. +- πŸ› [Resource section](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/215) **#215**: Adds a resource section to the front page of the project. +- πŸ› [Clearer emission color formula](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/209) **#209**: Clarifies the formula for the emission color. +- πŸ› [Version update](https://github.com/AcademySoftwareFoundation/OpenPBR/pull/221) **#221**: Updates the specification and MaterialX node definition to 1.1. + +## [[1.0]](https://github.com/AcademySoftwareFoundation/OpenPBR/tree/v1.0) - Jun 4, 2024 + +- _First release._ + + diff --git a/README.md b/README.md index ca1f4d65..2bf4fdcd 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,14 @@ -# OpenPBR Surface + +
+

+homepage   +homepage +

+

- + +
Shader Playground, rendered in Arnold for Maya, using OpenPBR Surface. Artwork by Nikie Monteleone.


diff --git a/examples/open_pbr_aluminum_brushed.mtlx b/examples/open_pbr_aluminum_brushed.mtlx index faaf1cc4..99f5d810 100644 --- a/examples/open_pbr_aluminum_brushed.mtlx +++ b/examples/open_pbr_aluminum_brushed.mtlx @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_beryllium.mtlx b/examples/open_pbr_beryllium.mtlx new file mode 100644 index 00000000..de7c1cf4 --- /dev/null +++ b/examples/open_pbr_beryllium.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_blackboard.mtlx b/examples/open_pbr_blackboard.mtlx new file mode 100644 index 00000000..fc322b35 --- /dev/null +++ b/examples/open_pbr_blackboard.mtlx @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_blood.mtlx b/examples/open_pbr_blood.mtlx new file mode 100644 index 00000000..9a0d96a3 --- /dev/null +++ b/examples/open_pbr_blood.mtlx @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_brass.mtlx b/examples/open_pbr_brass.mtlx new file mode 100644 index 00000000..66b4359e --- /dev/null +++ b/examples/open_pbr_brass.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_brick.mtlx b/examples/open_pbr_brick.mtlx new file mode 100644 index 00000000..71967937 --- /dev/null +++ b/examples/open_pbr_brick.mtlx @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_carpaint.mtlx b/examples/open_pbr_carpaint.mtlx index d4b24bd6..29803cd7 100644 --- a/examples/open_pbr_carpaint.mtlx +++ b/examples/open_pbr_carpaint.mtlx @@ -1,14 +1,14 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_cesium.mtlx b/examples/open_pbr_cesium.mtlx new file mode 100644 index 00000000..4fba86ed --- /dev/null +++ b/examples/open_pbr_cesium.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_charcoal.mtlx b/examples/open_pbr_charcoal.mtlx new file mode 100644 index 00000000..f1b1a14a --- /dev/null +++ b/examples/open_pbr_charcoal.mtlx @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_chocolate.mtlx b/examples/open_pbr_chocolate.mtlx new file mode 100644 index 00000000..51be4c17 --- /dev/null +++ b/examples/open_pbr_chocolate.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_chromium.mtlx b/examples/open_pbr_chromium.mtlx new file mode 100644 index 00000000..8b313fe0 --- /dev/null +++ b/examples/open_pbr_chromium.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_cobalt.mtlx b/examples/open_pbr_cobalt.mtlx new file mode 100644 index 00000000..1f0b2a96 --- /dev/null +++ b/examples/open_pbr_cobalt.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_coffee.mtlx b/examples/open_pbr_coffee.mtlx new file mode 100644 index 00000000..5c522f9c --- /dev/null +++ b/examples/open_pbr_coffee.mtlx @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_concrete.mtlx b/examples/open_pbr_concrete.mtlx new file mode 100644 index 00000000..2b7b44b4 --- /dev/null +++ b/examples/open_pbr_concrete.mtlx @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_cooking_oil.mtlx b/examples/open_pbr_cooking_oil.mtlx new file mode 100644 index 00000000..818ca558 --- /dev/null +++ b/examples/open_pbr_cooking_oil.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_copper.mtlx b/examples/open_pbr_copper.mtlx new file mode 100644 index 00000000..eea505b1 --- /dev/null +++ b/examples/open_pbr_copper.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_default.mtlx b/examples/open_pbr_default.mtlx index 8125541a..cf1af1ca 100644 --- a/examples/open_pbr_default.mtlx +++ b/examples/open_pbr_default.mtlx @@ -1,5 +1,5 @@ - + diff --git a/examples/open_pbr_diamond.mtlx b/examples/open_pbr_diamond.mtlx new file mode 100644 index 00000000..2d088fb3 --- /dev/null +++ b/examples/open_pbr_diamond.mtlx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_egg_shell.mtlx b/examples/open_pbr_egg_shell.mtlx new file mode 100644 index 00000000..9e9a3aa1 --- /dev/null +++ b/examples/open_pbr_egg_shell.mtlx @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_eye_cornea.mtlx b/examples/open_pbr_eye_cornea.mtlx new file mode 100644 index 00000000..ab69360c --- /dev/null +++ b/examples/open_pbr_eye_cornea.mtlx @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_eye_lens.mtlx b/examples/open_pbr_eye_lens.mtlx new file mode 100644 index 00000000..da534cfd --- /dev/null +++ b/examples/open_pbr_eye_lens.mtlx @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_eye_sclera.mtlx b/examples/open_pbr_eye_sclera.mtlx new file mode 100644 index 00000000..50d5cdd3 --- /dev/null +++ b/examples/open_pbr_eye_sclera.mtlx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_gasoline.mtlx b/examples/open_pbr_gasoline.mtlx new file mode 100644 index 00000000..fc92408d --- /dev/null +++ b/examples/open_pbr_gasoline.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_germanium.mtlx b/examples/open_pbr_germanium.mtlx new file mode 100644 index 00000000..2b659097 --- /dev/null +++ b/examples/open_pbr_germanium.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_glass.mtlx b/examples/open_pbr_glass.mtlx index d4148800..95bccb64 100644 --- a/examples/open_pbr_glass.mtlx +++ b/examples/open_pbr_glass.mtlx @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_gold.mtlx b/examples/open_pbr_gold.mtlx new file mode 100644 index 00000000..3bdb43d2 --- /dev/null +++ b/examples/open_pbr_gold.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_gray_card.mtlx b/examples/open_pbr_gray_card.mtlx new file mode 100644 index 00000000..32367a82 --- /dev/null +++ b/examples/open_pbr_gray_card.mtlx @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_honey.mtlx b/examples/open_pbr_honey.mtlx deleted file mode 100644 index 4c689193..00000000 --- a/examples/open_pbr_honey.mtlx +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/examples/open_pbr_honey_crystallized.mtlx b/examples/open_pbr_honey_crystallized.mtlx new file mode 100644 index 00000000..9dcccb78 --- /dev/null +++ b/examples/open_pbr_honey_crystallized.mtlx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_honey_liquid.mtlx b/examples/open_pbr_honey_liquid.mtlx new file mode 100644 index 00000000..c806ecf8 --- /dev/null +++ b/examples/open_pbr_honey_liquid.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_ice.mtlx b/examples/open_pbr_ice.mtlx new file mode 100644 index 00000000..cbb31e14 --- /dev/null +++ b/examples/open_pbr_ice.mtlx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_iridium.mtlx b/examples/open_pbr_iridium.mtlx new file mode 100644 index 00000000..3c935e9c --- /dev/null +++ b/examples/open_pbr_iridium.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_iron.mtlx b/examples/open_pbr_iron.mtlx new file mode 100644 index 00000000..bcd3f338 --- /dev/null +++ b/examples/open_pbr_iron.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_ketchup.mtlx b/examples/open_pbr_ketchup.mtlx index c3f08a49..b808c5b2 100644 --- a/examples/open_pbr_ketchup.mtlx +++ b/examples/open_pbr_ketchup.mtlx @@ -1,14 +1,13 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_lcd_display_6500k.mtlx b/examples/open_pbr_lcd_display_6500k.mtlx new file mode 100644 index 00000000..5c527148 --- /dev/null +++ b/examples/open_pbr_lcd_display_6500k.mtlx @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_lead.mtlx b/examples/open_pbr_lead.mtlx new file mode 100644 index 00000000..4464e860 --- /dev/null +++ b/examples/open_pbr_lead.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_lightbulb.mtlx b/examples/open_pbr_light_bulb_2700k.mtlx similarity index 59% rename from examples/open_pbr_lightbulb.mtlx rename to examples/open_pbr_light_bulb_2700k.mtlx index 39fa490b..a84de620 100644 --- a/examples/open_pbr_lightbulb.mtlx +++ b/examples/open_pbr_light_bulb_2700k.mtlx @@ -1,10 +1,10 @@ - - + + - + - + \ No newline at end of file diff --git a/examples/open_pbr_light_bulb_5000k.mtlx b/examples/open_pbr_light_bulb_5000k.mtlx new file mode 100644 index 00000000..dde43156 --- /dev/null +++ b/examples/open_pbr_light_bulb_5000k.mtlx @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_lithium.mtlx b/examples/open_pbr_lithium.mtlx new file mode 100644 index 00000000..5887eb27 --- /dev/null +++ b/examples/open_pbr_lithium.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_magnesium.mtlx b/examples/open_pbr_magnesium.mtlx new file mode 100644 index 00000000..c80aa9d2 --- /dev/null +++ b/examples/open_pbr_magnesium.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_manganese.mtlx b/examples/open_pbr_manganese.mtlx new file mode 100644 index 00000000..ff3e719c --- /dev/null +++ b/examples/open_pbr_manganese.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_marble.mtlx b/examples/open_pbr_marble.mtlx new file mode 100644 index 00000000..1c7f1e5c --- /dev/null +++ b/examples/open_pbr_marble.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_mercury.mtlx b/examples/open_pbr_mercury.mtlx new file mode 100644 index 00000000..2c21d82a --- /dev/null +++ b/examples/open_pbr_mercury.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_milk.mtlx b/examples/open_pbr_milk.mtlx new file mode 100644 index 00000000..27b7932c --- /dev/null +++ b/examples/open_pbr_milk.mtlx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_molybdenum.mtlx b/examples/open_pbr_molybdenum.mtlx new file mode 100644 index 00000000..f92c5c0c --- /dev/null +++ b/examples/open_pbr_molybdenum.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_nickel.mtlx b/examples/open_pbr_nickel.mtlx new file mode 100644 index 00000000..6e67c363 --- /dev/null +++ b/examples/open_pbr_nickel.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_office_paper.mtlx b/examples/open_pbr_office_paper.mtlx new file mode 100644 index 00000000..d901b98c --- /dev/null +++ b/examples/open_pbr_office_paper.mtlx @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_palladium.mtlx b/examples/open_pbr_palladium.mtlx new file mode 100644 index 00000000..f46e2f62 --- /dev/null +++ b/examples/open_pbr_palladium.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_pearl.mtlx b/examples/open_pbr_pearl.mtlx index cfc69c58..79ef6d96 100644 --- a/examples/open_pbr_pearl.mtlx +++ b/examples/open_pbr_pearl.mtlx @@ -1,20 +1,19 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_petroleum.mtlx b/examples/open_pbr_petroleum.mtlx new file mode 100644 index 00000000..63b11d2a --- /dev/null +++ b/examples/open_pbr_petroleum.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_plastic_acrylic.mtlx b/examples/open_pbr_plastic_acrylic.mtlx new file mode 100644 index 00000000..bd9dd091 --- /dev/null +++ b/examples/open_pbr_plastic_acrylic.mtlx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_plastic_pc.mtlx b/examples/open_pbr_plastic_pc.mtlx new file mode 100644 index 00000000..bab55cc7 --- /dev/null +++ b/examples/open_pbr_plastic_pc.mtlx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_plastic_pet.mtlx b/examples/open_pbr_plastic_pet.mtlx new file mode 100644 index 00000000..14ccae41 --- /dev/null +++ b/examples/open_pbr_plastic_pet.mtlx @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_plastic_polyurethane.mtlx b/examples/open_pbr_plastic_polyurethane.mtlx new file mode 100644 index 00000000..d0939376 --- /dev/null +++ b/examples/open_pbr_plastic_polyurethane.mtlx @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_plastic_pp.mtlx b/examples/open_pbr_plastic_pp.mtlx new file mode 100644 index 00000000..d604e8c8 --- /dev/null +++ b/examples/open_pbr_plastic_pp.mtlx @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_plastic_pvc.mtlx b/examples/open_pbr_plastic_pvc.mtlx new file mode 100644 index 00000000..524b2e95 --- /dev/null +++ b/examples/open_pbr_plastic_pvc.mtlx @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_platinum.mtlx b/examples/open_pbr_platinum.mtlx new file mode 100644 index 00000000..693ccfbf --- /dev/null +++ b/examples/open_pbr_platinum.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_potassium.mtlx b/examples/open_pbr_potassium.mtlx new file mode 100644 index 00000000..d78fb58d --- /dev/null +++ b/examples/open_pbr_potassium.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_quartz.mtlx b/examples/open_pbr_quartz.mtlx new file mode 100644 index 00000000..2f309de0 --- /dev/null +++ b/examples/open_pbr_quartz.mtlx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_rubidium.mtlx b/examples/open_pbr_rubidium.mtlx new file mode 100644 index 00000000..c3f57296 --- /dev/null +++ b/examples/open_pbr_rubidium.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_salt.mtlx b/examples/open_pbr_salt.mtlx new file mode 100644 index 00000000..6cd52192 --- /dev/null +++ b/examples/open_pbr_salt.mtlx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_sand.mtlx b/examples/open_pbr_sand.mtlx new file mode 100644 index 00000000..228bfa6a --- /dev/null +++ b/examples/open_pbr_sand.mtlx @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_sapphire.mtlx b/examples/open_pbr_sapphire.mtlx new file mode 100644 index 00000000..d30c669a --- /dev/null +++ b/examples/open_pbr_sapphire.mtlx @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_silicon.mtlx b/examples/open_pbr_silicon.mtlx new file mode 100644 index 00000000..1dbe2356 --- /dev/null +++ b/examples/open_pbr_silicon.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_silver.mtlx b/examples/open_pbr_silver.mtlx new file mode 100644 index 00000000..b09d9211 --- /dev/null +++ b/examples/open_pbr_silver.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_skin_i.mtlx b/examples/open_pbr_skin_i.mtlx new file mode 100644 index 00000000..e8cb63ad --- /dev/null +++ b/examples/open_pbr_skin_i.mtlx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_skin_ii.mtlx b/examples/open_pbr_skin_ii.mtlx new file mode 100644 index 00000000..5496ba3b --- /dev/null +++ b/examples/open_pbr_skin_ii.mtlx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_skin_iii.mtlx b/examples/open_pbr_skin_iii.mtlx new file mode 100644 index 00000000..9add76aa --- /dev/null +++ b/examples/open_pbr_skin_iii.mtlx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_skin_iv.mtlx b/examples/open_pbr_skin_iv.mtlx new file mode 100644 index 00000000..f0efa2b1 --- /dev/null +++ b/examples/open_pbr_skin_iv.mtlx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_skin_v.mtlx b/examples/open_pbr_skin_v.mtlx new file mode 100644 index 00000000..450b2ec9 --- /dev/null +++ b/examples/open_pbr_skin_v.mtlx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_skin_vi.mtlx b/examples/open_pbr_skin_vi.mtlx new file mode 100644 index 00000000..22890100 --- /dev/null +++ b/examples/open_pbr_skin_vi.mtlx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_snow.mtlx b/examples/open_pbr_snow.mtlx new file mode 100644 index 00000000..d2e9ed08 --- /dev/null +++ b/examples/open_pbr_snow.mtlx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_soapbubble.mtlx b/examples/open_pbr_soapbubble.mtlx index 89245f00..f5ed6c32 100644 --- a/examples/open_pbr_soapbubble.mtlx +++ b/examples/open_pbr_soapbubble.mtlx @@ -1,15 +1,15 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_sodium.mtlx b/examples/open_pbr_sodium.mtlx new file mode 100644 index 00000000..2b6461c5 --- /dev/null +++ b/examples/open_pbr_sodium.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_stainless_steel.mtlx b/examples/open_pbr_stainless_steel.mtlx new file mode 100644 index 00000000..1e2364f0 --- /dev/null +++ b/examples/open_pbr_stainless_steel.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_tire.mtlx b/examples/open_pbr_tire.mtlx new file mode 100644 index 00000000..261908fe --- /dev/null +++ b/examples/open_pbr_tire.mtlx @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_titanium.mtlx b/examples/open_pbr_titanium.mtlx new file mode 100644 index 00000000..ff40817f --- /dev/null +++ b/examples/open_pbr_titanium.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_toner_black.mtlx b/examples/open_pbr_toner_black.mtlx new file mode 100644 index 00000000..0bc0e98f --- /dev/null +++ b/examples/open_pbr_toner_black.mtlx @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_tungsten.mtlx b/examples/open_pbr_tungsten.mtlx new file mode 100644 index 00000000..a769bf9a --- /dev/null +++ b/examples/open_pbr_tungsten.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_vanadium.mtlx b/examples/open_pbr_vanadium.mtlx new file mode 100644 index 00000000..f48b43f0 --- /dev/null +++ b/examples/open_pbr_vanadium.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_velvet.mtlx b/examples/open_pbr_velvet.mtlx index 2b2da96c..247ffffe 100644 --- a/examples/open_pbr_velvet.mtlx +++ b/examples/open_pbr_velvet.mtlx @@ -1,13 +1,14 @@ - + - - - - + + + + + diff --git a/examples/open_pbr_water.mtlx b/examples/open_pbr_water.mtlx new file mode 100644 index 00000000..07ecc50c --- /dev/null +++ b/examples/open_pbr_water.mtlx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_whiteboard.mtlx b/examples/open_pbr_whiteboard.mtlx new file mode 100644 index 00000000..3460792a --- /dev/null +++ b/examples/open_pbr_whiteboard.mtlx @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/examples/open_pbr_zinc.mtlx b/examples/open_pbr_zinc.mtlx new file mode 100644 index 00000000..2611836c --- /dev/null +++ b/examples/open_pbr_zinc.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/images/base-ior.png b/images/base-ior.png new file mode 100644 index 00000000..2b4263f3 Binary files /dev/null and b/images/base-ior.png differ diff --git a/images/carbon_fiber_a0.0.png b/images/carbon_fiber_a0.0.png new file mode 100644 index 00000000..a17acfaa Binary files /dev/null and b/images/carbon_fiber_a0.0.png differ diff --git a/images/carbon_fiber_a0.5.png b/images/carbon_fiber_a0.5.png new file mode 100644 index 00000000..0569d701 Binary files /dev/null and b/images/carbon_fiber_a0.5.png differ diff --git a/images/carbon_fiber_a0.9.png b/images/carbon_fiber_a0.9.png new file mode 100644 index 00000000..5730c612 Binary files /dev/null and b/images/carbon_fiber_a0.9.png differ diff --git a/images/coat_darkening_0.0.png b/images/coat_darkening_0.0.png new file mode 100644 index 00000000..69714087 Binary files /dev/null and b/images/coat_darkening_0.0.png differ diff --git a/images/coat_darkening_0.5.png b/images/coat_darkening_0.5.png new file mode 100644 index 00000000..32642eba Binary files /dev/null and b/images/coat_darkening_0.5.png differ diff --git a/images/coat_darkening_1.png b/images/coat_darkening_1.png new file mode 100644 index 00000000..88342d5d Binary files /dev/null and b/images/coat_darkening_1.png differ diff --git a/images/fuzz_dust_r0.25.png b/images/fuzz_dust_r0.25.png new file mode 100644 index 00000000..724212b3 Binary files /dev/null and b/images/fuzz_dust_r0.25.png differ diff --git a/images/fuzz_dust_r0.5.png b/images/fuzz_dust_r0.5.png new file mode 100644 index 00000000..eda86899 Binary files /dev/null and b/images/fuzz_dust_r0.5.png differ diff --git a/images/fuzz_dust_r0.75.png b/images/fuzz_dust_r0.75.png new file mode 100644 index 00000000..49d38d0d Binary files /dev/null and b/images/fuzz_dust_r0.75.png differ diff --git a/images/glossy-diffuse.png b/images/glossy-diffuse.png new file mode 100644 index 00000000..6ee60d39 Binary files /dev/null and b/images/glossy-diffuse.png differ diff --git a/images/logo/openpbr-logo-favicon.png b/images/logo/openpbr-logo-favicon.png new file mode 100644 index 00000000..557d6c0a Binary files /dev/null and b/images/logo/openpbr-logo-favicon.png differ diff --git a/images/logo/openpbr-logo-glyph.png b/images/logo/openpbr-logo-glyph.png new file mode 100644 index 00000000..b3cf3a23 Binary files /dev/null and b/images/logo/openpbr-logo-glyph.png differ diff --git a/images/logo/openpbr-logo-glyph.svg b/images/logo/openpbr-logo-glyph.svg new file mode 100644 index 00000000..3907200c --- /dev/null +++ b/images/logo/openpbr-logo-glyph.svg @@ -0,0 +1,38 @@ + + + + diff --git a/images/logo/openpbr-logo-icon-minimal.png b/images/logo/openpbr-logo-icon-minimal.png new file mode 100644 index 00000000..8452c516 Binary files /dev/null and b/images/logo/openpbr-logo-icon-minimal.png differ diff --git a/images/logo/openpbr-logo-icon-minimal.svg b/images/logo/openpbr-logo-icon-minimal.svg new file mode 100644 index 00000000..0bbe647a --- /dev/null +++ b/images/logo/openpbr-logo-icon-minimal.svg @@ -0,0 +1,28 @@ + + + + diff --git a/images/logo/openpbr-logo-icon.png b/images/logo/openpbr-logo-icon.png new file mode 100644 index 00000000..9b0238b0 Binary files /dev/null and b/images/logo/openpbr-logo-icon.png differ diff --git a/images/logo/openpbr-logo-icon.svg b/images/logo/openpbr-logo-icon.svg new file mode 100644 index 00000000..d6789926 --- /dev/null +++ b/images/logo/openpbr-logo-icon.svg @@ -0,0 +1,35 @@ + + + + diff --git a/images/logo/openpbr-logo-text.png b/images/logo/openpbr-logo-text.png new file mode 100644 index 00000000..e80433b8 Binary files /dev/null and b/images/logo/openpbr-logo-text.png differ diff --git a/images/logo/openpbr-logo-text.svg b/images/logo/openpbr-logo-text.svg new file mode 100644 index 00000000..a22d42d4 --- /dev/null +++ b/images/logo/openpbr-logo-text.svg @@ -0,0 +1,25 @@ + + + + diff --git a/images/logo/openpbr-logo.png b/images/logo/openpbr-logo.png new file mode 100644 index 00000000..6bc5ba95 Binary files /dev/null and b/images/logo/openpbr-logo.png differ diff --git a/images/logo/openpbr-logo.svg b/images/logo/openpbr-logo.svg new file mode 100644 index 00000000..c66798ce --- /dev/null +++ b/images/logo/openpbr-logo.svg @@ -0,0 +1,42 @@ + + + + diff --git a/images/model_schematic2.png b/images/model_schematic2.png new file mode 100644 index 00000000..349eef3e Binary files /dev/null and b/images/model_schematic2.png differ diff --git a/images/model_schematic2.svg b/images/model_schematic2.svg new file mode 100644 index 00000000..5d2a3dbb --- /dev/null +++ b/images/model_schematic2.svg @@ -0,0 +1,1106 @@ + + + +Expression 2Expression 2Expression 2Expression 2Expression 2Expression 2Expression 2Expression 2fuzzcoatmetalopaque basemetallic basebasedielectric basemetalsubsurfaceglossy-diffusetranslucentbaseExpression 2Expression 2Expression 2thin-film diff --git a/index.html b/index.html index c5d85792..1f8a8e73 100644 --- a/index.html +++ b/index.html @@ -1,10 +1,16 @@ + -**OpenPBR Surface** +
+ homepage +   + homepage +
-
*Specification v1.1, 2024-06-28.     homepage *
+ +
OpenPBR Surface specification v1.1.1, 2026-04-17.

This document is a specification of a surface shading model intended as a standard for computer graphics: the OpenPBR Surface model. Designed as an ΓΌber-shader, it aims to be capable of accurately modeling the vast majority of CG materials used in practical visual effects and feature animation productions. The model has been developed as a synthesis of the Autodesk Standard Surface and the Adobe Standard Material models. @@ -30,15 +36,15 @@ OpenPBR is intended to be a common interface between products, as well as something practical that works well and looks plausible for most day-to-day use cases. For the more specialized use cases it does not cover (for example very high-end skin, hair, cloth or volume shading), one may need to use a renderer-specific shader, or build a bespoke shading network. We aim for the overall behavior to be simple, logical, intuitive, and understandable, so that users can become comfortable and familiar with it, while also being grounded in physically-based rendering. We thus adopt a specific form of material structure that has proved useful as a general purpose model in media and entertainment (Figure [diagram_model]). In outline the structure consists of: - - A [base substrate](index.html#model/basesubstrate) made of a mixture of [metal](index.html#model/metal) or [dielectric](index.html#model/dielectricbase). The interface (dielectric or metal) of this base layer produces the primary specular reflection lobe. The dielectric base represents either of three components, that can be statistically mixed: - 1. [Glossy-diffuse](index.html#model/dielectricbase/glossy-diffuse): dielectric with opaque internal media, e.g. wood, granite, concrete, cardboard, and wall-paint. - 2. [Subsurface](index.html#model/dielectricbase/subsurface): dielectric with dense highly scattering internal media, e.g. plastic, marble, skin, vegetation, and food. - 3. [Translucent-base](index.html#model/dielectricbase/translucentbase): dielectric with translucent internal media, e.g. glass, crystals, and liquids. + - A [base substrate](index.html#model/basesubstrate) made of a mixture of [metal](index.html#model/basesubstrate/metal) or dielectric. The interface (dielectric or metal) of this base layer produces the primary specular reflection lobe. The dielectric base represents either of three components, that can be statistically mixed: + 1. [Glossy-diffuse](index.html#model/basesubstrate/glossy-diffuse): dielectric with opaque internal media, e.g. wood, granite, concrete, cardboard, and wall-paint. + 2. [Subsurface](index.html#model/basesubstrate/subsurface): dielectric with dense highly scattering internal media, e.g. plastic, marble, skin, vegetation, and food. + 3. [Translucent-base](index.html#model/basesubstrate/translucentbase): dielectric with translucent internal media, e.g. glass, crystals, and liquids. - [Coat](index.html#model/coat): An optional layer of dielectric, which may have an absorbing medium, acting as a coating on top of the base substrate. The dielectric interface of this coat layer provides a secondary specular lobe. - [Fuzz](index.html#model/fuzz): An optional layer representing the reflection from micro-fibers (such as fine hair, peach fuzz, textile strands, and dust grains) on top of everything else. - ![Figure [diagram_model]: Schematic illustration of the idealized physical material that our shader models. Horizontal stacking of slabs represents statistical mixture and vertical stacking represents layering.](images/model_schematic.svg width="100%") + ![Figure [diagram_model]: Schematic illustration of the idealized physical material that our shader models. Horizontal stacking of slabs represents statistical mixture and vertical stacking represents layering.](images/model_schematic2.svg width="100%") We define this physical material structure in detail using a simple [formalism](index.html#formalism) involving slabs of material composed via layering and mixing operations. This formalism is general enough to describe arbitrarily complex materials, but we restrict its usage here to defining the particular material structure illustrated above. @@ -190,13 +196,11 @@ It also ensures that if the substrate BSDF perfectly preserves energy, i.e. $E_\mathrm{sub}(\omega_o) = 1$, then the layer BSDF does also, ensuring that a "white furnace" test would pass. The Autodesk Standard Surface model [#Georgiev2019] uses this formulation for its layering. Note though that this albedo-scaling approximation does not correctly take into account the effect of multiple light bounces back and forth between the interfaces, or absorption and scattering in the volumetric medium of the coat $V_\mathrm{coat}$. In general the resulting BSDF lobe shape will not be a simple linear combination of the interface BSDFs. -To some extent these effects can be put back into the albedo-scaling model by making various approximations. For example the effect of the volumetric transmittance through the coat in the incident and output directions could be approximately modeled as +To some extent these effects can be put back into the albedo-scaling model by making various approximations. For example the effect of the volumetric absorption through the coat in the incident and output directions could be approximately modeled as \begin{equation} \label{non-reciprocal-albedo-scaling-with-T} -f_\mathrm{layer}(\omega_i, \omega_o) = f_\mathrm{coat}(\omega_i, \omega_o) + T_\mathrm{coat}(\omega_i, \omega_o) \bigl(1 - E_\mathrm{coat}(\omega_o)\bigr) \,f_\mathrm{sub}(\omega_i, \omega_o) +f_\mathrm{layer}(\omega_i, \omega_o) = f_\mathrm{coat}(\omega_i, \omega_o) + T_\mathrm{coat}(\omega_i, \omega_o) \bigl(1 - E_\mathrm{coat}(\omega_o)\bigr) \,f_\mathrm{sub}(\omega_i, \omega_o) \end{equation} -where $T_\mathrm{coat}(\omega_i, \omega_o)$ accounts for the total volumetric absorption of the coat along the input and output rays. Similarly if the coat is rough this will effectively roughen the substrate BSDF lobe also, which can be accounted for approximately via various heuristics. - -Complete conformance to the spec is defined as reproducing all the physical inter-layer light transport effects, though this is not typically practical. In practice, each implementation must decide what level of approximation to use for the light transport within layers, trading off accuracy for efficiency according to its own particular use case. +where $T_\mathrm{coat}(\omega_i, \omega_o)$ accounts for the total volumetric transmittance of the coat along the input and output rays. Similarly if the coat is rough this will effectively roughen the substrate BSDF lobe also, which can be accounted for approximately via various heuristics. Mixing @@ -261,7 +265,7 @@ \begin{equation} f_\mathrm{layer} = f_\mathrm{coat} + T_\mathrm{coat} \left(1 - E_\mathrm{coat}\right) \,f_\mathrm{sub} \end{equation} -where $f_\mathrm{coat}$ is the BSDF of the coat and $T_\mathrm{coat}$ is its transmittance. Thus combining these [^lerp], +where $f_\mathrm{coat}$ is the BSDF of the coat and $T_\mathrm{coat}$ is the volumetric transmittance along the path of the input and output rays. Thus combining these [^lerp], \begin{equation} \label{coat_layering_formula_with_albedo_scaling} f_\mathrm{weighted-layer} = w_\mathrm{coat} f_\mathrm{coat} + \mathrm{lerp}\bigl(1, T_\mathrm{coat} (1 - E_\mathrm{coat}), w_\mathrm{coat}\bigr) f_\mathrm{sub} \ , \end{equation} @@ -288,7 +292,7 @@ However the parameters of the physical model that we describe do not specify all of the assumptions that would be needed to obtain a good visual match. We recommend therefore, for the purposes of asset exchange, that the parameters be packaged with certain metadata that provides the following missing information: - The version of the specification implemented. - - The assumed color space of all the color parameters. If unspecified, following MaterialX [#Smythe2016], by default this color space is assumed to be [ACEScg](https://docs.acescentral.com/specifications/acescg/). + - The assumed color space of all the color parameters. If unspecified, following MaterialX [#Smythe2016], by default this color space is assumed to be [ACEScg](https://docs.acescentral.com/specifications/acescg/). [^ingamut] - The floating-point conversion factor from the parameters given in world space length units to meters. @@ -305,7 +309,7 @@ ============================================ Using the operator formalism and parametrization described, we now specify the structure of the OpenPBR surface model. -We describe first the non-thin-walled case (in the [thin-walled case](index.html#model/thin-walledcase) the structure differs), where the material structure looks informally like the following diagram: +We describe first the non-thin-walled mode (in the [thin-walled mode](index.html#model/thin-walledmode) the structure differs), where the material structure looks informally like the following diagram: ************************************************************************************************************ * emission * * ^ * @@ -363,9 +367,7 @@ In addition to the weight and opacity parameters explicit in the model structure above, the properties of each component slab are controlled via further parameters detailed below (see the Parameter reference section for the full set). -Since the model is simply a physical description of a material structure, in principle it would be amenable to solution via accurate methods such as those developed in [#Jakob2014], [#Belcour2018], and [#Zeltner2018], which attempt to compute all the various modes of reflection and transmission through the whole stack of layers, generating a final BSDF which is not necessarily a simple linear combination of the individual interface BSDFs. However we want this material model to be renderable on a wide range of platforms, from offline path tracers all the way to real-time game engines on mobile devices. Enforcing a particular implementation would make the use of the material model impractical for certain classes of renderers, and ultimately make the model less useful. For this reason we consider the choice of a specific implementation of the final BSDF to be outside the scope of this specification. - -For convenience and efficiency, at present it is most likely to be mapped to a model consisting of a mixture of BSDF lobes similar to the Autodesk Standard Surface shader [#Georgiev2019] and its representation in MaterialX. An example derivation of such a model is provided in the ["Reduction to a mixture of lobes"](index.html#model/reductiontoamixtureoflobes) section below. We also provide a [reference implementation](reference/open_pbr_surface.mtlx) in MaterialX based on this derivation. +Since the model is simply a physical description of a material structure, in principle it would be amenable to solution via accurate methods such as those developed in [#Jakob2014], [#Belcour2018], and [#Zeltner2018], which attempt to compute all the various modes of reflection and transmission through the whole stack of layers, generating a final BSDF which is not necessarily a simple linear combination of the individual interface BSDFs. At present however, for the reasons described in the Flexibility of implementation section, it is most likely to be mapped to a model consisting of a mixture of BSDF lobes similar to the Autodesk Standard Surface shader [#Georgiev2019] and its representation in MaterialX. An example derivation of such a model is provided in the ["Reduction to a mixture of lobes"](index.html#model/reductiontoamixtureoflobes) section below. We also provide a [reference implementation](reference/open_pbr_surface.mtlx) in MaterialX based on this derivation. We now discuss the detailed form of the BSDFs and media of the slabs in the structure. @@ -375,7 +377,7 @@ We give here some general assumptions about the form and parametrization of the BSDFs which describe the interfaces in the model outlined in the previous section. -The BSDFs $f_\mathrm{conductor}$, $f_\mathrm{dielectric}$, $f_\mathrm{coat}$ and $f_\mathrm{diffuse}$ of the [metal](index.html#model/metal), [dielectric](index.html#model/dielectricbase), [coat](index.html#model/coat) and [glossy-diffuse](index.html#model/dielectricbase/glossy-diffuse) slabs respectively, are each assumed to be described by a standard _microfacet model_. This is a widely used approximation ([#Pharr2023]) in which the surface is assumed to be composed of a heightfield consisting of smooth microfacets of either metal, dielectric or Lambertian material, where the statistical distribution of the normal of these facets, termed the _micronormal_, determines the surface roughness characteristics at the macroscopic scale. (The [fuzz](index.html#model/fuzz) model is distinct and based on a volumetric "microflake" model [#Heitz2015]). +The BSDFs $f_\mathrm{conductor}$, $f_\mathrm{dielectric}$, $f_\mathrm{coat}$ and $f_\mathrm{diffuse}$ of the [metal](index.html#model/basesubstrate/metal), [dielectric](index.html#model/basesubstrate), [coat](index.html#model/coat) and [glossy-diffuse](index.html#model/basesubstrate/glossy-diffuse) slabs respectively, are each assumed to be described by a standard _microfacet model_. This is a widely used approximation ([#Pharr2023]) in which the surface is assumed to be composed of a heightfield consisting of smooth microfacets of either metal, dielectric or Lambertian material, where the statistical distribution of the normal of these facets, termed the _micronormal_, determines the surface roughness characteristics at the macroscopic scale. (The [fuzz](index.html#model/fuzz) model is distinct and based on a volumetric "microflake" model [#Heitz2015]). A microfacet BRDF has the standard form [^Jacobian] ([#Walter2007], [#Pharr2023]) in the single-scattering approximation: \begin{equation} @@ -388,8 +390,7 @@ The _masking-shadowing function_ $G(\omega_i, \omega_o)$ accounts for the probability that the input and output directions are occluded by the microsurface. It is usually derived using the Smith model which determines $G$ given the NDF, and for the GGX NDF equation [GGX] the masking-shadowing function then has a well-known form [#Heitz2014]. -The _Normal Distribution Function_ (NDF) $D(m)$ describes the relative probability of occurrence of micronormal $m$ on the surface, and thus the roughness characteristics. -A popular form of NDF which well-approximates the roughness of real materials is the so-called GGX distribution (this name derives from "ground glass", but the formula was originally due to Trowbridge and Reitz [#Walter2007], [#Burley2012], [#Heitz2014], [#Pharr2023]), which has the basic [^normalization] form: +The _Normal Distribution Function_ (NDF) $D(m)$ describes the relative probability of occurrence of micronormal $m$ on the surface, and thus the roughness characteristics. We assume that the NDF is the so-called GGX distribution which well-approximates the roughness of real materials (the name GGX derives from "ground glass", but the formula was originally due to Trowbridge and Reitz [#Walter2007], [#Burley2012], [#Heitz2014], [#Pharr2023]), which has the basic [^normalization] form: \begin{equation} \label{GGX} D_\mathrm{GGX}(m) \propto \left( 1 + \frac{\tan^2\theta_m}{\alpha^2} \right)^{-2} \end{equation} @@ -408,14 +409,12 @@ which reduces to the isotropic form when $\alpha_t = \alpha_b = \alpha$. Efficient techniques for sampling BSDFs employing the anisotropic GGX microfacet model are presented in [#Heitz2018], [#Dupuy2023]. -The NDF terms $\alpha_t$ and $\alpha_b$ are more conveniently parametrized as the total roughness $r$ and an anisotropy $a \in [0, 1]$. We suggest the following mapping from $r, a$ to $\alpha_t, \alpha_b$: +The NDF terms $\alpha_t$ and $\alpha_b$ are more conveniently parametrized as the total roughness $r$ and an anisotropy $a \in [0, 1]$. We specify the following mapping from $r, a$ to $\alpha_t, \alpha_b$: \begin{equation} \label{openpbr-anisotropy-formula} \alpha_t = r^2 \sqrt{\frac{2}{1 + (1 - a)^2}} \;\ , \quad \alpha_b = (1 - a) \, \alpha_t \ . \end{equation} -This formulation satisfies $\alpha_t^2 + \alpha_b^2 = 2\alpha^2$, to preserve the average roughness regardless of the anisotropy. A rationale is that if a renderer doesn't support anisotropy (or if the feature is turned off for performance considerations, such as level of detail), using only the roughness parameter should result in an isotropic specular highlight perceptually close to the original anisotropic one. Figure [ndf_anisotropy] shows the resulting shape of the highlight (technically, these are contour lines of the NDF $D_\mathrm{GGX}(m)$ in the 2D slope space). - -![Figure [ndf_anisotropy]: NDF shapes as a function of roughness $r$ and anisotropy $a$.](images/anisotropy.png width=60%) - +![Figure [ndf_anisotropy]: Highlight for varying roughness and anisotropy](images/anisotropy.png width="50%") +This formulation satisfies $\alpha_t^2 + \alpha_b^2 = 2\alpha^2$, to preserve the average roughness regardless of the anisotropy. A rationale is that if a renderer doesn't support anisotropy (or if the feature is turned off for performance considerations, such as level of detail), using only the roughness parameter should result in an isotropic specular highlight perceptually close to the original anisotropic one. Figure [ndf_anisotropy] shows the resulting shape of the highlight as a function of roughness $r$ and anisotropy $a$ (technically, these are contour lines of the NDF $D_\mathrm{GGX}(m)$ in the 2D slope space). To summarize the NDF parameterization, the dielectric-base BSDF $f_\mathrm{dielectric}$ and metal-base BRDF $f_\mathrm{conductor}$ share the same parameters, while the coat BSDF $f_\mathrm{coat}$ uses an independent set: @@ -426,6 +425,12 @@ The single-scattering microfacet BRDF of equation [microfacet_brdf_ss] does not conserve energy, as it neglects to account for multiple scattering between the microfacets. An implementation should ideally account for this, via one of a number of schemes, otherwise the reflection from rough metals and dielectrics is dimmer and less saturated than it should be. A fully accurate approach is described in [#Heitz2016a], where the multiple bounces are explicitly modeled via Monte Carlo. Simpler approximate models are presented in [#Kulla2017] (which functions by adding compensation lobes to account for the missing energy), and [#Turquin2019] (which scales the albedo of the lobe to maintain energy preservation at the expense of reciprocity). +![](images/carbon_fiber_a0.0.png width=99%) ![](images/carbon_fiber_a0.5.png width=99%) ![](images/carbon_fiber_a0.9.png width=99%) +
+ ![Figure [anisotropy]: Textured **`geometry_tangent`**, with **`specular_roughness_anisotropy`** varying over 0 (default), 0.5, 0.9.](dummy) +
+ + Base Substrate ------------------------------------- @@ -465,7 +470,7 @@ This mirrors the usual workflow of artists where they are typically either modelling an opaque surface potentially with some specularity and dense subsurface scattering (such as rock, plastic, skin etc.), or a translucent material with some limited amount of volumetric absorption and scattering (such as glass, liquids, organic matter etc.). These use cases require different parametrizations to effectively control, so are convenient to split into separate slabs. -The translucent-base is described in the Translucent base section, while the opaque-base is further broken down below (into [Glossy-diffuse](index.html#model/dielectricbase/glossy-diffuse) and [Subsurface](index.html#model/dielectricbase/subsurface)). The **`transmission_weight`** parameter selects between these models. Note that technically a mix weight between 0 and 1 produces a physically ambiguous state (since there are then superimposed bulk media with different properties), so we expect that normally this weight acts as a Boolean selector. +The translucent-base is described in the Translucent base section, while the opaque-base is further broken down below (into [Glossy-diffuse](index.html#model/basesubstrate/glossy-diffuse) and [Subsurface](index.html#model/basesubstrate/subsurface)). The **`transmission_weight`** parameter selects between these models. Note that technically a mix weight between 0 and 1 produces a physically ambiguous state (since there are then superimposed bulk media with different properties), so we expect that normally this weight acts as a Boolean selector. The opaque-base substrate is assumed to be a dielectric with dense subsurface volumetric absorption and scattering, which tends to an idealized "glossy-diffuse" BSDF in the limit of infinite density medium. In some cases a blend of subsurface and completely opaque glossy-diffuse scattering is desired, for example in skin rendering where the diffuse component provides the surface details of the skin (freckles, blemishes, makeup, etc.) and the subsurface component provides the color detail of the underlying veins and tissue. To support this, we make the opaque-base substrate be a statistical mix of glossy-diffuse and subsurface models (described in the Glossy-diffuse section and the Subsurface section respectively): \begin{eqnarray} @@ -517,7 +522,6 @@ ![Figure [specular]: Varying the **`specular_ior`** from (left to right): 1.1, 1.3, 1.5 (default)](dummy) - ### Metal Metals are completely opaque and have a characteristic and familiar form of specularity due to the Fresnel factor for conductors differing from that for dielectrics. @@ -610,7 +614,7 @@ \begin{eqnarray} \label{EON_brdf} f_\mathrm{diffuse}(\omega_i, \omega_o) = f_\mathrm{ON}(\omega_i, \omega_o) + f^\mathrm{comp}_\mathrm{ON}(\omega_i, \omega_o) \ . \end{eqnarray} -This form of the Oren-Nayar model is termed "energy-preserving Oren-Nayar" or $\textbf{EON}$. +This form of the Oren-Nayar model is termed "energy-preserving Oren-Nayar" or $\textbf{EON}$ [#Portsmouth2024]. The Oren-Nayar term $f_\mathrm{ON}$ is given by the [#Fujii2012] form [^Oren_Nayar_formula] \begin{eqnarray} \label{FON_brdf} f_\mathrm{ON}(\omega_i, \omega_o) = \frac{w_\mathrm{d} \boldsymbol{\rho}}{\pi} \Bigl( A(\sigma) + B(\sigma) \frac{s}{t} @@ -622,7 +626,7 @@ The directional albedo $E_\mathrm{ON}(\omega) = w_\mathrm{d} \boldsymbol{\rho}\,\hat{E}_\mathrm{ON}(\omega)$, and corresponding _average albedo_ $\langle\hat{E}_\mathrm{ON}\rangle$, of the Oren-Nayar term can be determined -analytically [^Oren_Nayar_albedo]. The energy compensation term $f^{\mathrm{comp}}_\mathrm{ON}$ is given in terms of the +analytically [#Portsmouth2024]. The energy compensation term $f^{\mathrm{comp}}_\mathrm{ON}$ is given in terms of the albedo $\langle\hat{E}_\mathrm{ON}\rangle$ by \begin{equation} \label{EON_comp} f^\mathrm{comp}_\mathrm{ON}(\omega_i, \omega_o) = \frac{w_\mathrm{d} \boldsymbol{\rho}_\mathrm{ms}}{\pi} @@ -689,9 +693,9 @@ **`base_diffuse_roughness`** | Diffuse Roughness | `float` | $ [0, 1] $ | $ 0 $ | Roughness of the diffuse lobe $f_\mathrm{diffuse}$ -![](images/glossy_diffuse_diffuseonly.png width=99%) ![](images/glossy_diffuse_speconly.png width=99%) ![](images/glossy_diffuse_sum.png width=99%) +![](images/glossy-diffuse.png width=99%)
- ![Figure [fuzz]: Wood rendered as glossy-diffuse, composed of diffuse lobe (left), specular lobe (middle), and their normalized sum. Near the specular highlight the diffuse lobe is automatically reduced since energy is conserved.](dummy) + ![Figure [glossy-diffuse]: Wood rendered as glossy-diffuse, composed of diffuse lobe (left), specular lobe (middle), and their normalized sum. Near the specular highlight the diffuse lobe is automatically reduced since energy is conserved.](dummy)
@@ -703,7 +707,7 @@ S_\mathrm{subsurface} = \mathrm{Slab}(f_\mathrm{dielectric}, V^\infty_\mathrm{subsurface}) \ . \end{equation} -As in the cases of the [glossy-diffuse](index.html#model/dielectricbase/glossy-diffuse) slab and the [translucent-base](index.html#model/dielectricbase/translucentbase), the subsurface is bounded by a dielectric interface with BSDF $f_\mathrm{dielectric}$, which generates the primary specular reflection lobe parametrized via the "specular" parameters as described in the Dielectric base section. Combined with this is the reflection generated by light which is transmitted through the dielectric interface into the underlying embedded subsurface medium, where it scatters around and eventually transmits back out. In this case the subsurface medium $V^\infty_\mathrm{subsurface}$ is given a parametrization which is particularly convenient for controlling the volumetric effect of dense subsurface scattering: +As in the cases of the [glossy-diffuse](index.html#model/basesubstrate/glossy-diffuse) slab and the [translucent-base](index.html#model/basesubstrate/translucentbase), the subsurface is bounded by a dielectric interface with BSDF $f_\mathrm{dielectric}$, which generates the primary specular reflection lobe parametrized via the "specular" parameters as described in the Dielectric base section. Combined with this is the reflection generated by light which is transmitted through the dielectric interface into the underlying embedded subsurface medium, where it scatters around and eventually transmits back out. In this case the subsurface medium $V^\infty_\mathrm{subsurface}$ is given a parametrization which is particularly convenient for controlling the volumetric effect of dense subsurface scattering: - **`subsurface_radius`** * **`subsurface_radius_scale`**: the _mean free path_ (MFP) per RGB channel, $\mathbf{r}$, i.e. the average distance that a ray of light travels through the medium before being absorbed or scattered. This thus controls the apparent density of the medium. In the limit of zero MFP, the medium tends towards infinite density, and approaches the look of an opaque diffuse surface. Being a length, **`subsurface_radius`** can be any value greater than or equal to zero. For convenience, we make the soft range $[0, 1]$, thus covering common cases such as skin where the MFP is lower than the scene length units. The **`subsurface_radius_scale`** controls the color channel dependence of the MFP, and thus this color is visible in the light transmitted through thinner regions of the subsurface volume. - **`subsurface_color`**: the observed RGB reflection albedo color taking into account all orders of multiple scattering, $\mathbf{C}$ (where the sense in which this parametrizes the observed color is discussed in detail below). @@ -740,7 +744,7 @@ The phase function anisotropy $g$ of the medium is taken to be given directly by the **`subsurface_scatter_anisotropy`** parameter [^anisotropy_g]. It is assumed that the phase function has the standard Henyey--Greenstein form. -Once the underlying volumetric medium properties $\boldsymbol{\mu}_t$, $\boldsymbol{\alpha}$ and $g$ are determined, implementations are free to choose how to compute the light transport in the subsurface medium according to their use case, for example accurately via volumetric path tracing ([#Novak2018], [#Pharr2023]), or approximately via a bidirectional scattering surface reflectance distribution (BSSRDF) model using e.g. the dipole approximation [#Jensen2001].``` +Once the underlying volumetric medium properties $\boldsymbol{\mu}_t$, $\boldsymbol{\alpha}$ and $g$ are determined, implementations are free to choose how to compute the light transport in the subsurface medium according to their use case, for example accurately via volumetric path tracing ([#Novak2018], [#Pharr2023]), or approximately via a bidirectional scattering surface reflectance distribution (BSSRDF) model using e.g. the dipole approximation [#Jensen2001]. Note that the default value of **`subsurface_radius_scale`** is set at $(1, 0.5, 0.25)$ to approximate the effect of Rayleigh scattering. If we roughly approximate the wavelength corresponding to each of the RGB channels as $\lambda/\mathrm{nm} \approx 650, 550, 450$ and assume the radii scale like the reciprocal of the extinction, then since in Rayleigh scattering the extinction scales like $\lambda^{-4}$ for light of wavelength $\lambda$ the expected relative magnitudes of the radii are $(1, (550/650)^4, (450/650)^4) \approx (1, 0.5, 0.25)$, hence the chosen default. This provides a slightly more realistic default look for the subsurface than resulting from gray radii. @@ -826,7 +830,7 @@ ![](images/dispersion_0percent.png width=99%) ![](images/dispersion_25percent.png width=99%) ![](images/dispersion_50percent.png width=99%) ![](images/dispersion_75percent.png width=99%) ![](images/dispersion_100percent.png width=99%)
- ![Figure [fuzz]: Increasing the **`transmission_dispersion_scale`** of glass from 0 to 1](dummy) + ![Figure [dispersion]: Increasing the **`transmission_dispersion_scale`** of glass from 0 to 1](dummy)
@@ -844,23 +848,31 @@ Thin-film iridescence ------------------------------------- -_Iridescence_ is the occurrence of rainbow-like color fringes in the reflection when a thin dielectric film with thickness on the order of the wavelength of light is placed on top of a material, due to wave interference between the various electromagnetic reflection modes within the film. To model this, there is assumed to be such a thin-film sitting on top of the base substrate (whether metal or dielectric), parametrized only by: +_Iridescence_ is the occurrence of rainbow-like color fringes in the reflection when a thin dielectric film with thickness on the order of the wavelength of light is placed on top of a material, due to interference between light reflected from the film's top and bottom surfaces, including internal reflections. To model this, we assume such a thin film sits atop the base substrate (whether metal or dielectric), parametrized by: - **`thin_film_weight`**: the coverage (presence) weight of the film, - - **`thin_film_thickness`**: the thickness of the film in micrometers ($\mathrm{\mu m}$), mostly affecting the spacing of the fringes, - - **`thin_film_ior`**: the index of refraction (IOR) of the film, mostly affecting the hue of the fringes + - **`thin_film_thickness`**: the thickness of the film in micrometers ($\mathrm{\mu m}$), + - **`thin_film_ior`**: the index of refraction (IOR) of the film. - The coverage weight functions as a blend between the BSDF with and without the presence of the film, and thus allows one to dial the effect without altering the shape and saturation of the color fringes. +The thickness and IOR together affect the intensity, spacing, and hue of the color fringes. The coverage weight acts as a blend between the BSDF with and without the presence of the film, allowing the overall strength of the effect to be adjusted without altering its structure or color. - The currently recommended thin-film model is that of Belcour and Barla [#Belcour2017]. The shape and color of the fringe patterns in the reflection from the film will be affected (as described by Belcour and Barla) by the complex IOR of the adjacent media above and below the film, which in general are a statistical mix of metal and dielectric below and coat and ambient medium above (which the fuzz is index-matched to). Figure [ior_configs] illustrates the eight possible different structures depending on the presence of both the film and coat, each of which leads to different Fresnel effects due to the differing IORs at the interfaces. +The currently recommended thin-film model is that of Belcour and Barla [#Belcour2017]. This model provides an efficient, high-quality approximation of thin-film interference suitable for typical RGB-based production rendering. -![Figure [ior_configs]: Schematic of all 8 possible IOR configurations, including those involving the thin-film.](images/IOR_configs.svg width="95%" align="center") +Implementations that operate in a spectral rendering context (or that otherwise wish to account for wavelength-dependent IOR and extinction) may alternatively compute the thin-film Fresnel effect directly from first principles by evaluating Fresnel and thin-film interference at one or more wavelengths and integrating the result according to the renderer's spectral pipeline. In such implementations, the thin-film effect is typically evaluated using an Airy-style multi-bounce formulation (e.g., Equation 3 in [#Belcour2017]) together with wavelength-dependent Fresnel amplitude and phase at the film interfaces. Results should be validated against the recommended Belcour and Barla model in the parameter regimes where that model applies. + +Regardless of which approach is used, several considerations apply: + + - The shape and color of the fringe patterns in the reflection from the film are affected by the complex IOR of the adjacent media above and below the film, which in general are a statistical mix of metal and dielectric below, and of coat and ambient medium above (to which the fuzz is index-matched). Figure [ior_configs] illustrates the eight possible different structures depending on the presence of both the film and coat, each of which leads to different Fresnel effects due to the differing IORs at the interfaces. In principle the implementation should account for all of these configurations accurately, though the precise modeling of these effects is implementation-dependent. -In principle the implementation should deal with all these physical configurations correctly, though modeling of the precise effect is implementation-dependent. In practice, this wave-optics effect is most easily incorporated directly into the Fresnel factor of the microfacet BSDFs of both the metal and dielectric-base layers. (For this reason, this effect is not represented by incorporating an explicit thin-film Slab into the model). + - The thin-film thickness is assumed to be smaller than the scale of the microfacets and the film is assumed to be smooth. With this assumption, in practice the effect is most easily incorporated directly into the Fresnel factor of the microfacet BSDFs of both the metal and dielectric-base layers (thus it is *not* represented by incorporating an explicit thin-film Slab into the model). -Note that in the case of the dielectric base, the thin-film should also generate color fringes in the transmission lobe. This is important for example when rendering soap bubbles (see [#Belcour2017]). + - In the case of a dielectric base, the thin film should also generate color fringes in the transmission lobe. This is important, for example, when rendering soap bubbles (see [#Belcour2017]). -In the case of the metallic base the physics is somewhat ambiguous since, as described in the Metal section, the Fresnel factor for metal is defined according to the Schlick-based "F82-tint" parametrization which does not specify the underlying physical complex IOR. We suggest here that some reasonable approximation is employed to map the Fresnel factor to the best matching effective complex IOR, for example that described by [#Gulbrandsen2014]. + - In the case of a metallic base the physics is somewhat ambiguous since, as described in the Metal section, the Fresnel factor for metal is defined according to the Schlick-based "F82-tint" parametrization, which does not specify the underlying physical complex IOR. We suggest that some reasonable approximation is employed to map the Fresnel factor to a best-matching effective complex IOR, for example that described by [#Gulbrandsen2014]. + + - Because the thin film is non-absorbing and interference-based, it only redistributes the probabilities of reflection and transmission; therefore, it should not violate energy conservation. + +![Figure [ior_configs]: Schematic of all 8 possible IOR configurations, including those involving the thin-film.](images/IOR_configs.svg width="95%" align="center")
@@ -898,8 +910,6 @@ * +-------------------------------------------------+ * ******************************************************* -The absorption of the medium $V_\mathrm{coat}$ is parametrized by **`coat_color`**, which is assumed to specify the _square_ of the transmittance $T_\mathrm{coat}$ of the coat at normal incidence (i.e. $T^2_\mathrm{coat}$ = **`coat_color`**). Thus at normal incidence, the observed tint color of the underlying base due to absorption in the coat is approximately given by **`coat_color`** due to the absorption along the incident and outgoing rays (note that the specular reflection from the coat itself is _not_ tinted). - The IOR $n_c = \mathtt{coat\_ior}$ of the coat medium $V_\mathrm{coat}$ will alter the Fresnel factor of both the coat top interface and the underlying metal or dielectric. If there is a fractional $\mathtt{coat\_weight}$ $\mathtt{C}$, then the surrounding IOR of the base dielectric or metal varies statistically across the surface depending on whether the coat is locally present (and the fuzz layer can be assumed to have the ambient IOR $n_a$). The ratio between the specular IOR $n_b = \mathtt{specular\_ior}$ and the surrounding medium can thus reasonably be approximated as \begin{equation} \label{specular_ior_ratio} \eta_s = \mathrm{lerp}(n_b/n_a, n_b/n_c, \mathtt{C}) \ . @@ -907,6 +917,19 @@ This ratio then determines the specular Fresnel factor, as in equation [modulated_ior]. (Note that as discussed in the coat [TIR](index.html#model/coat/totalinternalreflection) section, evaluation of the specular Fresnel factor may need to be further modified to model the refraction of the ray inside the coat). +The absorption of the medium $V_\mathrm{coat}$ is parametrized by **`coat_color`**, which is assumed to specify the _square_ of the transmittance of the coat at normal incidence (i.e. $T_\mathrm{coat}$ = **`coat_color`** in the notation of equation [non-reciprocal-albedo-scaling-with-T]). Thus the observed tint color of the underlying base due to absorption in the coat is approximately given by **`coat_color`** due to the absorption along the incident and outgoing rays (note that the specular reflection from the coat itself is _not_ tinted). + +In the full light transport within the coat, various physical effects [^porosity] occur which we assume are accounted for in the ground truth appearance. + + - The observed color of the coated base is darkened and saturated due to multiple internal reflections from the inside of the coat, which causes light to strike the underlying material multiple times and undergo more absorption. This effect is controlled via the **`coat_darkening`** parameter, as described in the coat Darkening section. + + - The observed **`coat_color`** tint also darkens as the incidence angle changes due to the change in path length in the medium, as described in the View-dependent absorption section. + + - The presence of a rough coat will increase the apparent roughness of the BSDF lobes of the underlying base. A recommendation for implementation of this effect is given in the coat Roughening section. + + - Care needs to be taken in the implementation to account for the refraction of the ray direction inside the coat. This is discussed in the Total internal reflection section. + +
Coat params | Label | Type | Range | Norm | Default | Description --------------------------------|------------|----------|:---------------:|:----------:|:-------------:|---------------------------------------------- @@ -922,22 +945,6 @@ ![Figure [coat]: Coat adds a secondary specular highlight and optional absorption tint](dummy) -In the full light transport, the observed color of the coated base is darkened and saturated due to multiple internal reflections from the inside of the coat, which causes light to strike the underlying material multiple times and undergo more absorption, and the observed **`coat_color`** tint also darkens as the incidence angle changes due to the change in path length in the medium. Also, the presence of a rough coat will increase the apparent roughness of the BSDF lobes of the underlying base. - -We assume that in the ground truth appearance, all these physical effects are accounted for [^porosity]. In the following sub-sections, we detail recommendations for implementation of them. - - -### Roughening - -If the coat is rough, the microfacet BSDF lobes of the underlying base substrate (metal and dielectric) are also effectively roughened. If this is not otherwise accounted for by the light transport, it can instead be reasonably approximated by directly altering the NDF of the base BSDFs. - -A formula we recommend for this is obtained by identifying the NDF of each microfacet lobe as corresponding approximately to a Gaussian in slope-space with variance given by $\alpha_t^2 + \alpha_b^2 = r^4$ (in the notation of the [Microfacet model](index.html#model/microfacetmodel) section). Modeling the effect of the roughening as the convolution of these Gaussian NDFs (and double counting the coat variance since the reflection passes through the coat boundary twice), the resulting modified roughness of the base, $r'_\mathrm{B}$, (taking into account the presence weight of the coat, $\mathtt{C}=$ **`coat_weight`**) is given by -\begin{equation} -r'_\mathrm{B} = \mathrm{lerp}\Bigl( r_\mathrm{B}, \mathrm{min} \bigl(1, r^4_\mathrm{B} + 2 r^4_\mathrm{C} \bigr)^\frac{1}{4}, \mathtt{C} \Bigr) -\end{equation} -where $r_\mathrm{B}=$ **`specular_roughness`** and $r_\mathrm{C}=$ **`coat_roughness`**. - - ### Darkening Figure [coat_darkening_grid] shows the physically-correct change in appearance (at normal incidence) of a textured diffuse base with a wood texture and smooth clear-coat as the IOR of the clear-coat is varied, exhibiting darkening of the base -- due to the internal reflections in the coat -- which increases as IOR increases. @@ -990,7 +997,7 @@ \begin{equation} \label{dielectric_roughness_estimate} r_d = \mathrm{lerp}(1, r, \xi_s F_s) \end{equation} -while the metallic roughness can be taken to be $r_m = r$. +while the metallic roughness can be taken to be $r_m = r$. (Note that in this formula for $r_d$, a clamp must be applied to ensure that $\xi_s F_s \in [0, 1]$). Given the general formula equation [general_darkening_formula] for the darkening, a reasonable approximate scheme -- assuming no other compensation is made to approximate the effect -- is to multiply the base BSDF by the uniform _modulated darkening factor_ (taking into account the presence weight $\mathtt{C}$ = **`coat_weight`** and the darkening parameter $\delta$ = **`coat_darkening`**): \begin{equation} \label{modulated_darkening_factor} @@ -1016,6 +1023,18 @@ ![Figure [coat_view_dependent_absorption_color]: The color of an absorbing coat becomes darker and more saturated at grazing angles.](images/coat_view_dependent_absorption_color.png width="75%") +### Roughening + +If the coat is rough, the microfacet BSDF lobes of the underlying base substrate (metal and dielectric) are also effectively roughened. If this is not otherwise accounted for by the light transport, it can instead be reasonably approximated by directly altering the NDF of the base BSDFs. + +A formula we recommend for this is obtained by identifying the NDF of each microfacet lobe as corresponding approximately to a Gaussian in slope-space with variance given by $\alpha_t^2 + \alpha_b^2 = r^4$ (in the notation of the [Microfacet model](index.html#model/microfacetmodel) section). Modeling the effect of the roughening as the convolution of these Gaussian NDFs (and double counting the coat variance since the reflection passes through the coat boundary twice), the resulting modified roughness of the base, $r'_\mathrm{B}$, (taking into account the presence weight of the coat, $\mathtt{C}=$ **`coat_weight`**) is given by +\begin{equation} +r'_\mathrm{B} = \mathrm{lerp}\Bigl( r_\mathrm{B}, \mathrm{min} \bigl(1, r^4_\mathrm{B} + 2 r^4_\mathrm{C} \bigr)^\frac{1}{4}, \mathtt{C} \Bigr) +\end{equation} +where $r_\mathrm{B}=$ **`specular_roughness`** and $r_\mathrm{C}=$ **`coat_roughness`**. + + + ### Total internal reflection A technical issue which can cause difficulties in the implementation of the BRDF of the coated dielectric base should also be mentioned. @@ -1091,7 +1110,7 @@ where the albedo-scaling is explicitly modified to not tint the base since the tint $\mathbf{F}$ appears only in the first term via $f_\mathrm{fuzz}$. Then accounting for the coverage weight of the fuzz layer, $\mathtt{F}$ = **`fuzz_weight`**, gives: \begin{eqnarray} -\mathrm{\mathbf{layer}}(M_\textrm{coated-base}, S_\mathrm{fuzz}, \mathtt{F}) &\rightarrow& \mathtt{F} \,f_\mathrm{fuzz} + \mathrm{lerp}\bigl(1, 1 - E_\mathrm{fuzz}, \mathtt{F}\bigr) \,f_\textrm{coated-base} \ . \label{fuzz-layering-approx} +\mathrm{\mathbf{layer}}(M_\textrm{coated-base}, S_\mathrm{fuzz}, \mathtt{F}) &\rightarrow& \mathtt{F} \,f_\mathrm{fuzz} + \bigl(1 - \mathtt{F}\,E_\mathrm{fuzz}\bigr) \,f_\textrm{coated-base} \ . \label{fuzz-layering-approx} \end{eqnarray} The fuzz shading normal is assumed to inherit from that of the substrate layer, the physical picture being that the fuzz volume settles and conforms to the geometry of the substrate. The substrate is generally a mixture of coat and uncoated base. Thus physically the fuzz model should be evaluated with each of the **`geometry_coat_normal`** and **`geometry_normal`** separately (if they differ), and the final result blended according to the **`coat_weight`**. As a practical approximation, it may be more convenient and efficient to instead approximate the fuzz normal by interpolating the coat and base normal according to **`coat_weight`**. @@ -1103,9 +1122,9 @@ **`fuzz_color`** | Color | `color3` | $ [0, 1]^3 $ | $ (1, 1, 1) $ | Reflection albedo color of $f_\mathrm{fuzz}$ **`fuzz_roughness`** | Roughness | `float` | $ [0, 1] $ | $ 0.5 $ | Reflection roughness of $f_\mathrm{fuzz}$ -![](images/fuzz1.jpg width=99%) ![](images/fuzz2.jpg width=99%) ![](images/fuzz3.jpg width=99%) +![](images/fuzz_dust_r0.25.png width=99%) ![](images/fuzz_dust_r0.5.png width=99%) ![](images/fuzz_dust_r0.75.png width=99%)
- ![Figure [fuzz]: Various textiles rendered using fuzz.](dummy) + ![Figure [fuzz]: Varying the **`fuzz_roughness`** over 0.25, 0.5 (default), 0.75.](dummy)
@@ -1128,7 +1147,7 @@ * +-------------------------------------------------+ * ******************************************************* -The intensity of the EDF is controlled by a luminance and a color multiplier. The **`emission_luminance`** parameter controls the luminance the emissive layer would have when **`emission_color`** is set to (1, 1, 1) and in the absence of coat and fuzz. The **`emission_color`** acts as a multiplier, i.e. the HDR emission in the model color space is defined to have a color given by **`emission_color`** * **`emission_luminance`**, thus the resulting luminance may be less than the input parameter, or even zero if the **`emission_color`** is set to (0, 0, 0). +The intensity of the EDF is controlled by a luminance and a color multiplier. The **`emission_luminance`** parameter controls the luminance the emissive layer would have when **`emission_color`** is set to (1, 1, 1) and in the absence of coat and fuzz. The **`emission_color`** acts as a multiplier, i.e. the HDR emission in the model color space is defined to have a color given by **`emission_color`** * **`emission_luminance`**, thus the resulting luminance may be less than the input parameter, or even zero if the **`emission_color`** is set to (0, 0, 0). Note that the **`emission_color`** components may exceed 1, in order to be able to plug in an HDR texture. [^ingamut] Moreover, the overall material luminance may be further reduced in the presence of coat or fuzz, as they can absorb light coming from the emissive layer before it exits the surface. The emission from the top surface should in principle gain a directional dependence due to the combined effects of absorption, total internal reflection (TIR) and multiple bounces in the coat layer, and absorption in the fuzz layer. The combined effect should result mostly in darkening and saturation at grazing angles. @@ -1137,8 +1156,8 @@ Emission params | Label | Type | Range | Norm | Default | Description -------------------------|-----------|----------|:---------------:|:-------------:|:-------------:|---------------------------------------------- -**`emission_luminance`** | Luminance | `float` | $ [0, \infty) $ | $ [0, 1000] $ | $ 0 $ | Emission luminance, in cd/m^2 (aka. nits) -**`emission_color`** | Color | `color3` | $ [0, 1]^3 $ | | $ (1, 1, 1) $ | Emission color multiplier +**`emission_luminance`** | Luminance | `float` | $[0, \infty)$ | $ [0, 1000] $ | $ 0 $ | Emission luminance, in cd/m^2 (aka. nits) +**`emission_color`** | Color | `color3` | $[0, \infty)^3$ | | $ (1, 1, 1) $ | Emission color multiplier ![](images/emitting_lava.png width=90% align=left) ![](images/emission_under_coat.png width=90% align=right)
@@ -1164,7 +1183,7 @@ * +- - - - - - - - - - - - - - - - - -+ +- - - - - - - - - - - - + - - - - - - - - - - - -+ * **************************************************************************************************** -Note that in the case of a non-thin-walled material, $\mathtt{\alpha} < 1$ doesn't make strict physical sense unless the entire surface is removed, whereas in the [thin-walled case](index.html#thin-walledcase) the opacity has a clear physical interpretation as the presence weight of the wall (or "cutout" areas where $\mathtt{\alpha} = 0$) like in the leaf render below. +Note that in the case of a non-thin-walled material, $\mathtt{\alpha} < 1$ doesn't make strict physical sense unless the entire surface is removed, whereas in the [thin-walled mode](index.html#thin-walledmode) the opacity has a clear physical interpretation as the presence weight of the wall (or "cutout" areas where $\mathtt{\alpha} = 0$) like in the leaf render below. We generally leave it as an implementation detail for a renderer to determine how connections to light sources be made through the surface. However a very common approximation used by many renderers is "transparent shadows", where a straight-line connection is made to lights and the contribution of the light determined by the total transmittance along the ray, ignoring any refraction events. We give here a suggested form for this shadow ray transmittance. @@ -1202,7 +1221,7 @@ The normal and tangent are assumed to be unit vectors. Reconstruction filtering techniques such as texture filtering may cause the interpolated value to not be normalized, which can be corrected with a renormalization to reduce visible artifacts caused by this filtering. -Thin-walled case +Thin-walled mode ------------------------------------- If the **`geometry_thin_walled`** Boolean is enabled, then the surface is assumed to be in a "thin-walled" mode. @@ -1249,7 +1268,9 @@ E_R[f^R_\mathrm{diffuse}] + E_T[f^T_\mathrm{diffuse}] = S \le 1 \ . \end{equation} At the default of zero anisotropy ($g=0$) the energy is balanced equally between diffuse reflection and transmission. - The diffuse transmission lobe shape (in both hemispheres) is assumed to be controlled by the **`base_diffuse_roughness`** parameter. Typically the diffuse lobes $f_+$, $f_-$ will be represented by an Oren-Nayar lobe flipped into the appropriate hemisphere (which technically should be modified due to the dielectric boundaries, though a renderer may choose to ignore this). This model is useful for rendering cases such as light scattering through a thin sheet of paper (Figure [thinwalled]). + The diffuse transmission lobe shape (in both hemispheres) is assumed to be controlled by the **`base_diffuse_roughness`** parameter. Typically the diffuse lobes $f_+$, $f_-$ will be represented by an Oren-Nayar lobe flipped into the appropriate hemisphere (which technically should be modified due to the dielectric boundaries, though a renderer may choose to ignore this). Note that in this mode, the **`subsurface_radius`** and **`subsurface_radius_scale`** are ignored and have no effect, since the scattering MFP is infinitesimal. + + This model is useful for rendering cases such as light scattering through a thin sheet of paper (Figure [thinwalled]). ![](images/thin_walled1.jpg width=99% align=right) ![](images/thin_walled2.jpg width=99% align=left) @@ -1265,9 +1286,9 @@ As an example, we give here a brief derivation of a mixture model representation analogous to Autodesk Standard Surface, from the stated material structure of OpenPBR. Following Autodesk Standard Surface, we assume here that layering is implemented via the non-reciprocal albedo-scaling of equation [non-reciprocal-albedo-scaling]. This derivation also informs how we implement our MaterialX [reference implementation](reference/open_pbr_surface.mtlx). -### Non-thin-walled case +### Non-thin-walled mode -Consider first the non-thin-walled case (i.e. **`geometry_thin_walled`** is false). +Consider first the default non-thin-walled mode (i.e. **`geometry_thin_walled`** is false). For brevity, in the following we suppress all the direction arguments, and use the notation of the tree diagram in the Model section for the weight factors i.e.: \begin{eqnarray} \mathtt{\alpha} &=& \mathtt{geometry\_opacity} \nonumber \\ @@ -1302,7 +1323,7 @@ Here the substrate lobes $\color{darkblue}{f^T_\textrm{specular}}$ and $\color{darkblue}{f_\textrm{SSS}}$ are technically BSSRDFs, which model the entry into the internal medium via the dielectric interface, transport of light from entry point to exit points including absorption and scattering processes, and exit from the medium back though the interface, generating both a reflection and transmission component. [^BSDF_BSSRDF_sum] The "specular" BTDF/BSSRDF $\color{darkblue}{f^T_\textrm{specular}}$ corresponds to transmission into the medium parametrized in the Translucent base section, and BSSRDF $\color{darkblue}{f_\textrm{SSS}}$ corresponds to transmission into the medium parametrized in the Subsurface section. In the case of $f_\textrm{glossy-diffuse}$, the BSSRDF degenerates into the BRDF $\color{darkblue}{f_\mathrm{diffuse}}$ as described in the Glossy-diffuse section. -Note that in this albedo-scaling approximation, the transmission Fresnel factor associated with $\color{darkblue}{f^T_\textrm{specular}}$ and $f_\textrm{SSS}$ can be *omitted* as the energy conservation of the dielectric BSDF as a whole is maintained automatically, even without explicit multiple scattering compensation or in the presence of modifications to the reflection Fresnel factor via **`specular_color`**. +Note that in this albedo-scaling approximation, the transmission Fresnel factor associated with $\color{darkblue}{f^T_\textrm{specular}}$ and $\color{darkblue}{f_\textrm{SSS}}$ can be *omitted* as the energy conservation of the dielectric BSDF as a whole is maintained automatically, even without explicit multiple scattering compensation or in the presence of modifications to the reflection Fresnel factor via **`specular_color`**. Since $\color{darkblue}{f^R_\textrm{specular}}$ appears in each of the three component slabs of the dielectric base, it follows that on collecting terms, $f_\textrm{dielectric-base}$ reduces to: @@ -1373,9 +1394,9 @@ | Diffuse reflection | $\color{darkblue}{f_\mathrm{diffuse}}$ | diffuse BRDF | as in the Glossy-diffuse section | -### Thin-walled case +### Thin-walled mode -In the thin walled case (i.e. when **`geometry_thin_walled`** is true), we will assume the approximation described in the Thin-walled case section where the coat and fuzz are ignored on the underside, and the surface always flipped to so that incident rays enter top-down. Then the derivation is the same as above except the translucent-base and subsurface slabs behave differently: +In the [thin-walled mode](index.html#model/thin-walledmode) (i.e. when **`geometry_thin_walled`** is true), the simplest approximation is to assume the coat and fuzz are ignored on the underside, and the surface always flipped so that incident rays enter top-down. Then the derivation is the same as above except the translucent-base and subsurface slabs behave differently: - The translucent-base reduces to a thin sheet of dielectric. This can just be considered the thin-wall limit of the BTDF $\color{darkblue}{f^T_\textrm{specular}}$. Note that in this limit, the reflection lobe from the dielectric $\color{darkblue}{f^R_\textrm{specular}}$ will also technically be modified due to the internal bounces in the sheet. @@ -1385,7 +1406,7 @@ ### Entering versus exiting -An aspect that has been ignored in this approximation (in the non-thin-walled case) is the different light transport for rays incident from the top or the bottom side. In reality the physical effect of the layers differs in these cases. For entering rays: +An aspect that has been ignored in this approximation (in the non-thin-walled mode) is the different light transport for rays incident from the top or the bottom side. In reality the physical effect of the layers differs in these cases. For entering rays: - The fuzz reflection is not tinted by the coat absorption. - The coat reflection is dimmed and roughened by the fuzz. @@ -1431,6 +1452,20 @@ We provide a [reference implementation](reference/open_pbr_surface.mtlx) in MaterialX, which is based on the derivation in the previous section and the implementation of Autodesk Standard Surface [#Georgiev2019]. +Flexibility of implementation +============================= + +We want this material model to be renderable on a wide range of platforms, from offline path tracers all the way to real-time game engines on mobile devices. + +The Historical background and objectives section explains how the goal of this specification is to provide an ideal, reference appearance. Complete conformance to the specification is defined as reproducing all the physical light transport effects of that ideal appearance. + +However, a number of features can be computationally expensive and therefore impractical to support under certain constraints. Enforcing a specific implementation would tailor the material model to a particular set of constraints, limiting its versatility, which would ultimately make it less useful. For this reason, the specification focuses solely on defining the target appearance. The choice of the final BSDF implementation and its associated trade-off is left entirely to the implementer, allowing them to best suit it to their needs. + +Each implementation must decide what level of approximation to use, trading off accuracy for efficiency according to its own particular use case. As a guideline, we suggest approaching those approximations conceptually like different level of detail (LOD) variants of an asset. Just like such an asset would become coarser with distance while retaining as much detail as necessary to remain faithful to the original, an implementation of OpenPBR may decide to make simplifications, as long as the result remains reasonably faithful to the intent given the practical constraints. In the most extreme hypothetical case, the model might even get reduced to as little as a single Lambert BRDF. + +This means the implementer must carefully consider the handling of parameters they do not plan to fully support. A parameter that drastically modifies the appearance of a material should not be discarded just because the corresponding effect is not supported. As an example, in a renderer that doesn't have subsurface scattering, the subsurface color might be used as the albedo of a diffuse BRDF. + + - @@ -23,7 +23,7 @@ doc="Index of refraction of the dielectric base." /> - @@ -75,9 +75,9 @@ doc="The amount of emitted light, as a luminance in nits." /> - - @@ -424,14 +424,10 @@ - - - - - + @@ -439,7 +435,7 @@ - + @@ -615,6 +611,7 @@ +