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

KHR_materials_volume #1726

Merged
Merged
Show file tree
Hide file tree
Changes from 49 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
25cbc3f
Added KHR_materials_volume.
proog128 Dec 6, 2019
52e090e
Added implementation details.
proog128 Dec 7, 2019
6e3aa63
Added more details.
proog128 Dec 7, 2019
dc227b1
Added the term "extinction coefficient".
proog128 Dec 12, 2019
25c8ab7
Swapped V and L to use common path tracing convention.
proog128 Dec 12, 2019
4a26990
Added images to explain refraction, absorption and SSS.
proog128 Dec 12, 2019
901d32e
Align notation with core spec.
proog128 Jan 8, 2020
4149c67
Added thickness texture.
proog128 Jan 8, 2020
1c8008e
Update schema.
proog128 Jan 8, 2020
81e157c
Place images side-by-side in Github markdown.
proog128 Jan 8, 2020
00bc2e5
Do not mention TIR.
proog128 Jan 10, 2020
e1bae20
Remove hint.
proog128 May 20, 2020
a2170ea
Change parameter names to make them understandable without extension …
proog128 Jun 16, 2020
f9889eb
Clarify texture type.
proog128 Jun 16, 2020
e19b29b
Add Boolean parameter that switches between thin-walled and volumetri…
proog128 Jun 16, 2020
20b4327
Add information about interaction with KHR_materials_translucency.
proog128 Jun 30, 2020
7e0455c
Sample thickness from G channel.
proog128 Jun 30, 2020
336470c
Major refactoring of the volume extension to account for recent sugge…
proog128 Jul 30, 2020
e9ba47e
Add em tags for captions.
proog128 Jul 31, 2020
2271905
Fix references.
proog128 Jul 31, 2020
d7354be
Remove left-overs and add details.
proog128 Aug 3, 2020
d03ac76
Default IOR is 1.5.
proog128 Aug 3, 2020
ca21deb
Fix sigma_t.
proog128 Aug 3, 2020
a1cd9b7
Use SVG for figures.
proog128 Aug 3, 2020
13d363f
Fix half vector.
proog128 Aug 3, 2020
6bd1f3f
Use consistent notation to KHR_materials_transmission in implementati…
proog128 Aug 4, 2020
f2a5ba8
Fix array lengths of defaults.
proog128 Aug 19, 2020
fe66014
Add details about Fresnel.
proog128 Aug 19, 2020
3af4caa
Double sided has only an effect on thin-walled materials.
proog128 Sep 21, 2020
ccd2c19
Add link to properties section.
proog128 Oct 28, 2020
1c24b36
Add hint about disabling SSS.
proog128 Oct 28, 2020
c6be3db
Add some links and details about translucency and SSS.
proog128 Nov 5, 2020
0a9d209
Volume extension split WIP
bsdorra Jan 6, 2021
cfb190a
Add drawing to explain refraction and absorption.
proog128 Jan 7, 2021
d4c5be2
Change volume ext to use attenuation semantics
bsdorra Jan 7, 2021
0f62577
Change sss ext to use scatter distance+color
bsdorra Jan 7, 2021
56963a9
Add suggested changes from review
bsdorra Jan 8, 2021
b9734a6
More review changes
bsdorra Jan 11, 2021
470700f
Remove sss ext from volume
bsdorra Jan 11, 2021
8133e9b
Remove translucency references from volume
bsdorra Jan 16, 2021
033af7b
Add suggested changes
bsdorra Jan 18, 2021
74c9075
Fix TOC
bsdorra Jan 18, 2021
262261a
Merge remote-tracking branch 'upstream/master' into KHR_materials_volume
proog128 Jan 19, 2021
e5c297c
Make compatible to new Appendix B.
proog128 Jan 18, 2021
a30002b
Make compatible to new Appendix B.
proog128 Jan 18, 2021
d250b2e
Add figure.
proog128 Jan 19, 2021
aab749d
Update extensions/2.0/Khronos/KHR_materials_volume/schema/glTF.KHR_ma…
bsdorra Jan 25, 2021
f616d7b
Change thickness/attenuationDistance description
bsdorra Jan 26, 2021
77d55aa
Update contributor list
emackey Apr 5, 2021
e7cdd9a
More contributors
emackey Apr 5, 2021
b37c6af
Fix maximum of attenuation color.
proog128 Apr 6, 2021
780f5b4
Clean up info about coordinate spaces and add more details regarding …
proog128 Apr 6, 2021
87f3e4a
Improve wording.
proog128 Apr 6, 2021
a5f3f2f
Add boilerplate.
proog128 Apr 12, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 60 additions & 13 deletions extensions/2.0/Khronos/KHR_materials_transmission/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,34 +134,81 @@ Metals effectively absorb all refracted light (light that isn't reflected), prev
The metallic parameter of a glTF material effectively scales the `baseColor` of the material toward black while, at the same time scaling the F0 (reflectivity) value towards 1.0. This makes the material opaque for metallic values of 1.0 because transmitted light is attenuated out by absorption. Therefore, for a material with `metallicFactor=1.0`, the value of `transmissionFactor` doesn't matter.

## Transmission BTDF ##
From the core [glTF BRDF](https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#appendix-b-brdf-implementation), we have:

*f* = *f*<sub>*diffuse*</sub> + *f*<sub>*specular*</sub>

*f*<sub>*diffuse*</sub> = (1 - *F*) * *diffuse*
From the core [glTF BRDF](https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#appendix-b-brdf-implementation), we have:

*f*<sub>*specular*</sub> = *F* * *G* * *D* / (4 * dot(*N*, *L*) * dot(*N*, *V*)), where *F* is the Surface Reflection Ratio.
```
dielectric_brdf =
fresnel_mix(
ior = 1.5,
base = diffuse_brdf(color = baseColor),
layer = specular_brdf(α = roughness^2))
```

We will now add an additional term for the transmitted light:

*f* = *f*<sub>*diffuse*</sub> + *f*<sub>*specular*</sub> + *f*<sub>*transmission*</sub>
```
dielectric_brdf =
fresnel_mix(
ior = 1.5,
base = mix(
diffuse_brdf(baseColor),
specular_btdf(α = roughness^2) * baseColor,
transmission),
layer = specular_brdf(α = roughness^2))
```

*f*<sub>*transmission*</sub> = (1 - *F*) * *T* * *baseColor* * *D<sub>T</sub>* * *G<sub>T</sub>* / *(4 * abs(dot(N, L))* * *abs(dot(N, V)))*
where `transmission` is the transmission percentage defined by this extension's `transmissionFactor` and `transmissionTexture` properties and `specular_btdf` is a bidirectional transmission distribution function (BTDF) based on microfacet theory. The microfacet distribution function is the same Trowbridge-Reitz model used by specular reflection except sampled along the view vector rather than the reflection. The *baseColor* factor causes the transmitted light to be tinted by the surface.

where *T* is the transmission percentage defined by this extension's `transmission` and `transmissionTexture` properties and *D<sub>T</sub>* is the distribution function for the transmitted light. The distribution function is the same Trowbridge-Reitz model used by specular reflection except sampled along the view vector rather than the reflection. *G<sub>T</sub>* is the geometric occlusion function for transmission. The *baseColor* factor causes the transmitted light to be tinted by the surface.
<figure>
<img src="./figures/Nodes.png"/>
<figcaption><em>KHR_material_transmission adds a specular_btdf to the core glTF BRDF.</em></figcaption>
</figure>

Note that unless otherwise specified by another extension, this transmissive surface is really two surfaces back-to-back, representing a thin material. As such there is no average refraction, but in the presence of roughness there is refraction at the microfacet level. This is because the distribution function is appled to both the front and back surface microfacets and they are uncorrelated to each other. These microfacet pairs form tiny prisms that cause the roughness map to blur the transmitted light, and as such this effect will be modulated by the material's index of refraction (IOR). Recall that the default IOR from the base spec is 1.5.

Light that penetrates a surface and is transmitted will not be diffusely reflected so we also need to modify the diffuse calculation to account for this.
*f*<sub>*diffuse*</sub> = (1 - *F*) * (1 - *T*) * *diffuse*

Optical transparency does not require any changes whatsoever to the specular term. So this can all be rearranged so that the transmitted light amounts to a modification of the diffuse lobe.
*f* = (1 - *F*) * (*T* * *D<sub>T</sub>* * *G<sub>T</sub>* / *(4 * abs(dot(N, L))* * *abs(dot(N, V)))* + (1 - *T*) * *diffuse*) + *f*<sub>*specular*</sub>
Optical transparency does not require any changes whatsoever to the specular term. So the transmitted light amount to a modification of the `base` layer only.

## Implementation Notes

*This section is non-normative.*

The specular transmission `specular_btdf(α)` is a microfacet BTDF

<img src="https://render.githubusercontent.com/render/math?math=\displaystyle \text{MicrofacetBTDF} = \frac{G_T D_T}{4 \, \left|N \cdot L \right| \, \left| N \cdot V \right|}">

with the Trowbridge-Reitz/GGX microfacet distribution

<img src="https://render.githubusercontent.com/render/math?math=\displaystyle D_T = \frac{\alpha^2 \, \chi^%2B(N \cdot H_T)}{\pi ((N \cdot H_T)^2 (\alpha^2 - 1) %2B 1)^2}">

and the separable form of the Smith joint masking-shadowing function

<img src="https://render.githubusercontent.com/render/math?math=\displaystyle G_T = \frac{2 \, \left| N \cdot L \right| \, \chi^%2B\left(\frac{H_T \cdot L}{N \cdot L}\right)}{\left| N \cdot L \right| %2B \sqrt{\alpha^2 %2B (1 - \alpha^2) (N \cdot L)^2}} \frac{2 \, \left| N \cdot V \right| \, \chi^%2B\left(\frac{H_T \cdot V}{N \cdot V}\right)}{\left| N \cdot V \right| %2B \sqrt{\alpha^2 %2B (1 - \alpha^2) (N \cdot V)^2}}">,

using the transmission half vector *H*<sub>*T*</sub>

<img src="https://render.githubusercontent.com/render/math?math=\displaystyle H_T = \text{normalize}(V %2B \, 2 \, \left| N \cdot L \right| \, N %2B L)">.

Introducing the visibility function

<img src="https://render.githubusercontent.com/render/math?math=\displaystyle V_T = \frac{G_T}{4 \, \left| N \cdot L \right| \, \left| N \cdot V \right|}">

simplifies the original microfacet BTDF to

<img src="https://render.githubusercontent.com/render/math?math=\displaystyle \text{MicrofacetBTDF} = V_T D_T">

with

<img src="https://render.githubusercontent.com/render/math?math=\displaystyle V_T = \frac{\, \chi^%2B(H \cdot L)}{\left| N \cdot L\right| %2B \sqrt{\alpha^2 %2B (1 - \alpha^2) (N \cdot L)^2}} \frac{\, \chi^-(H \cdot V)}{\left| N \cdot V \right| %2B \sqrt{\alpha^2 %2B (1 - \alpha^2) (N \cdot V)^2}}">.

Thus we have the function

```
function specular_btdf(α) {
return V_T * D_T
}
```

Rendering transparency in a real-time rasterizer in an efficient manner is a difficult problem, especially when an arbitrary number of transparent polygons may be overlapping in view. This is because rendering transparency is order-dependent (i.e. we see background objects through foreground objects) and also because the rendering of absorption and reflections involves two distinct blend operations. Consequently, it may not be possible on the target platform to render every transparent polygon in the correct order, in a reasonable time, and with the correct blending. Therefore, correct ordering is not an absolute requirement when implementing this extension in realtime renderers, nor is rendering all potentially overlapping layers.

Various techniques are available to trade off physical accuracy against realtime performance requirements in client implementations. This extension does not mandate any particular technique. However, be aware that the simplest such technique — transmitting only the IBL and no scene objects — will often fall short of what a model's author intended. We recommend that client implementations aim to display at least opaque objects through a transmissive material. When that is not feasible, it may be preferable to fall back to simple alpha blending with 0 < alpha < 1.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
digraph D {
graph [rankdir="LR", fontname="Helvetica"]
node [shape=plaintext, fontname="Helvetica"]
edge [fontname="Helvetica"]

subgraph cluster_dielectric {
label="Dielectric"

dielectric_specular_brdf [label=<
<table border="1" cellborder="0">
<tr><td port="out"><font point-size="14"><b>specular_brdf</b></font></td></tr>
<tr><td><font point-size="10">α = <i>&lt;roughness&gt;</i><sup>2</sup></font></td></tr>
</table>
>]

dielectric_specular_btdf [label=<
<table border="1" cellborder="0">
<tr><td port="out"><font point-size="14"><b>specular_btdf</b></font></td></tr>
<tr><td><font point-size="10">color = <i>&lt;baseColor&gt;</i></font></td></tr>
<tr><td><font point-size="10">roughness = <i>&lt;roughness&gt;</i><sup>2</sup></font></td></tr>
</table>
>]

dielectric_diffuse_brdf [label=<
<table border="1" cellborder="0">
<tr><td port="out"><font point-size="14"><b>diffuse_brdf</b></font></td></tr>
<tr><td><font point-size="10">color = <i>&lt;baseColor&gt;</i></font></td></tr>
</table>
>]

dielectric_base_mix [label=<
<table border="1" cellborder="0">
<tr><td port="out"><font point-size="14"><b>mix</b></font></td></tr>
<tr><td port="in_bsdf0"><font point-size="10">bsdf0</font></td></tr>
<tr><td port="in_bsdf1"><font point-size="10">bsdf1</font></td></tr>
<tr><td><font point-size="10">weight = <i>&lt;transmission&gt;</i></font></td></tr>
</table>
>]

dielectric_fresnel_mix [label=<
<table border="1" cellborder="0">
<tr><td port="out"><font point-size="14"><b>fresnel_mix&nbsp;</b></font></td></tr>
<tr><td port="in_layer"><font point-size="10">layer</font></td></tr>
<tr><td port="in_base"><font point-size="10">base</font></td></tr>
<tr><td><font point-size="10">ior = 1.5</font></td></tr>
</table>
>]

dielectric_diffuse_brdf:out -> dielectric_base_mix:in_bsdf0
dielectric_specular_btdf:out -> dielectric_base_mix:in_bsdf1

dielectric_base_mix:out -> dielectric_fresnel_mix:in_base
dielectric_specular_brdf:out -> dielectric_fresnel_mix:in_layer
}

subgraph cluster_metal {
label="Metal"

metal_specular_brdf [label=<
<table border="1" cellborder="0">
<tr><td port="out"><font point-size="14"><b>specular_brdf</b></font></td></tr>
<tr><td><font point-size="10">α = <i>&lt;roughness&gt;</i><sup>2</sup></font></td></tr>
</table>
>]

metal_conductor_fresnel [label=<
<table border="1" cellborder="0">
<tr><td port="out"><font point-size="14"><b>conductor_fresnel&nbsp;&nbsp;</b></font></td></tr>
<tr><td port="in_bsdf"><font point-size="10">bsdf</font></td></tr>
<tr><td><font point-size="10">f0 = <i>&lt;baseColor&gt;</i></font></td></tr>
</table>
>]

metal_specular_brdf:out -> metal_conductor_fresnel:in_bsdf
}

subgraph core {
core_mix [label=<
<table border="1" cellborder="0">
<tr><td port="out"><font point-size="14"><b>mix</b></font></td></tr>
<tr><td port="in_bsdf0"><font point-size="10">bsdf0</font></td></tr>
<tr><td port="in_bsdf1"><font point-size="10">bsdf1</font></td></tr>
<tr><td><font point-size="10">weight = <i>&lt;metallic&gt;</i></font></td></tr>
</table>
>]

dielectric_fresnel_mix:out -> core_mix:in_bsdf0
metal_conductor_fresnel:out -> core_mix:in_bsdf1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading