You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The coat effect is modeled via a microfacet BRDF. The BRDF is layered on top of the glTF 2.0 Metallic-Roughness material, excluding emission, using a new `fresnel_coat` function:
114
+
The coat effect is modeled via a microfacet BRDF. The BRDF is layered on top of the glTF 2.0 Metallic-Roughness material, including emission and all extensions, using a new `fresnel_coat` function:
115
115
116
116
```
117
117
# base material (from glTF 2.0 Metallic-Roughness)
@@ -193,31 +197,6 @@ Note that this view-dependent absorption is more pronounced when the ratio of IO
193
197
</figcaption>
194
198
</figure>
195
199
196
-
## Implementation
197
-
198
-
*This section is non-normative.*
199
-
200
-
At normal incidence, `coatColor` can simply be multiplied by the light coming from the underlying base layer. However, we need to modify this based on the incident angle:
201
-
202
-
```
203
-
// cos_i is the non-negative cosine of the unrefracted view angle
204
-
sin2_i = 1.0f - cos_i * cos_i
205
-
// eta is the ratio of IOR's of the coat and surrounding medium. i.e. coat_ior / 1.0 for air.
206
-
sin2_t = sin2_i / (eta * eta)
207
-
// Total internal reflection. i.e. no light makes it out of coating.
208
-
if (sin2_t >= 1.0)
209
-
{
210
-
final_coat_color = vec3(0.0f)
211
-
}
212
-
// Compute cosine of transmition angle.
213
-
cos_t = sqrt(1.0f - sin2_t);
214
-
// Calculate the path length through the coating, relative to normal incidence.
215
-
path_length = 1.0 / cos_t;
216
-
// Use the path length to calculate the final tinting.
217
-
final_coat_color = pow(coatColor, path_length)
218
-
```
219
-
220
-
221
200
## Darkening Control
222
201
223
202
The coating will naturally darken the appearance of the underlying surface due to internal reflections. However, when this physically-correct behavior is not be desired, the the `coatDarkeningFactor` can be used to control the amount of darkening:
@@ -243,32 +222,6 @@ Things that affect the amount of darkening observed:
243
222
244
223
1. Roughness Modulation: Rougher coats scatter light internally, reducing the coherent reflection effect. Increased diffuse internal reflections results in less darkening.
245
224
246
-
### Implementation
247
-
248
-
*This section is non-normative.*
249
-
250
-
Some renderers (such as path-tracers) may already model this darkening behaviour by the nature of their light transport algorithms. In these cases, implementing support for this extension will involve adding a term to compensate for the energy loss when the darknening value is < 1.0. The [specification of OpenPBR](https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/coat/darkening) contains a detailed description of what this entails.
251
-
252
-
Other renderers (such as rasterizers) will most likely need to add logic to approximate the loss of energy due to these internal reflections when the darkening value is > 0.0. We provide some example logic to do this below:
253
-
254
-
#### Real-time Implementation
255
-
256
-
We want to calculate a multiplier that represents the amount of transmitted light that makes its way through the coat and impacts the underlying layer. To approximate this, we want to find the average reflectance, $R$, of the coat and then model an infinite number of reflections using a geometric series to get the total transmission, $T$.
257
-
258
-
$T = (1-R) / (1 + R + R² + R³ + ...)$<br>
259
-
$T = (1-R) / (1/(1-R))$</br>
260
-
$T = (1-R)²$
261
-
262
-
The $(1-R)$ in the numerator represents the initial transmission of light through the coat and the denominator accounts for the infinite reflections within the coating. This converges to $1/(1-R)$.
263
-
264
-
By "average reflectance", we mean the average reflectance for the round trip (light in, view out) so it can be computed as the sum of the Schlick Fresnel approximation for $dot(N, V)$ and $dot(N, L)$ and then dividing by 2.
For environment lighting (IBL), however, light is coming from all angles so we calculate the hemisphere-averaged reflectance as $F_0 + 0.5 * F_{90}$ which gives a value halfway between $F_0$ and $F_{90}$. We then add to this the Schlick Fresnel approximation for $dot(N, V)$ and divide by 2.
When coat roughness increases, light is diffused and darkening decreases. We can approximate this empirically by scaling the average reflectance, $R$, by $1.0 - M_c * 0.5$ where $M_c$ is the roughness of the clearcoat.
271
-
272
225
## Anisotropy
273
226
274
227
The coating can exhibit anisotropic behavior where specular reflection is stretched in one direction, similar to brushed metal or directionally polished surfaces.Anisotropy modifies the microfacet distribution of the coating layer such that the specular lobe is stretched along a direction relative to the surface tangents.
@@ -341,6 +294,66 @@ More sophisticated layering models may be implemented for improved accuracy.
341
294
-`KHR_materials_ior`: Sets base layer IOR; `coatIor` is independent
342
295
- Other material extensions: Generally apply to the base layer, with the coat layered on top
343
296
297
+
## Implementation
298
+
299
+
*This section is non-normative.*
300
+
301
+
### Colored Absorption
302
+
303
+
At normal incidence, `coatColor` can simply be multiplied by the light coming from the underlying base layer. However, we need to modify this based on the incident angle:
304
+
305
+
```
306
+
// cos_i is the non-negative cosine of the unrefracted view angle
307
+
sin2_i = 1.0f - cos_i * cos_i
308
+
// eta is the ratio of IOR's of the coat and surrounding medium. i.e. coat_ior / 1.0 for air.
309
+
sin2_t = sin2_i / (eta * eta)
310
+
// Total internal reflection. i.e. no light makes it out of coating.
311
+
if (sin2_t >= 1.0)
312
+
{
313
+
final_coat_color = vec3(0.0f)
314
+
}
315
+
// Compute cosine of transmition angle.
316
+
cos_t = sqrt(1.0f - sin2_t);
317
+
// Calculate the path length through the coating, relative to normal incidence.
318
+
path_length = 1.0 / cos_t;
319
+
// Use the path length to calculate the final tinting.
320
+
final_coat_color = pow(coatColor, path_length)
321
+
```
322
+
323
+
### Darkening
324
+
325
+
Some renderers (such as path-tracers) may already model this darkening behaviour by the nature of their light transport algorithms. In these cases, implementing support for this extension will involve adding a term to compensate for the energy loss when the darknening value is < 1.0. The [specification of OpenPBR](https://academysoftwarefoundation.github.io/OpenPBR/index.html#model/coat/darkening) contains a detailed description of what this entails.
326
+
327
+
Other renderers (such as rasterizers) will most likely need to add logic to approximate the loss of energy due to these internal reflections when the darkening value is > 0.0. We provide some example logic to do this below:
328
+
329
+
#### Real-time Implementation
330
+
331
+
We want to calculate a multiplier that represents the amount of transmitted light that makes its way through the coat and impacts the underlying layer. To approximate this, we want to find the average reflectance, $R$, of the coat and then model an infinite number of reflections using a geometric series to get the total transmission, $T$.
332
+
333
+
$T = (1-R) / (1 + R + R² + R³ + ...)$<br>
334
+
$T = (1-R) / (1/(1-R))$</br>
335
+
$T = (1-R)²$
336
+
337
+
The $(1-R)$ in the numerator represents the initial transmission of light through the coat and the denominator accounts for the infinite reflections within the coating. This converges to $1/(1-R)$.
338
+
339
+
By "average reflectance", we mean the average reflectance for the round trip (light in, view out) so it can be computed as the sum of the Schlick Fresnel approximation for $dot(N, V)$ and $dot(N, L)$ and then dividing by 2.
For environment lighting (IBL), however, light is coming from all angles so we calculate the hemisphere-averaged reflectance as $F_0 + 0.5 * F_{90}$ which gives a value halfway between $F_0$ and $F_{90}$. We then add to this the Schlick Fresnel approximation for $dot(N, V)$ and divide by 2.
When coat roughness increases, light is diffused and darkening decreases. We can approximate this empirically by scaling the average reflectance, $R$, by $1.0 - M_c * 0.5$ where $M_c$ is the roughness of the clearcoat.
345
+
346
+
## Conversion from KHR_materials_clearcoat
347
+
348
+
The parameters from KHR_materials_clearcoat are fully transferable to this extension, with no changes.
The default values of the new parameters should, for the most part, result in fully backwards-compatible behaviour. The one exception is `coatDarkeningFactor` where the default value is `1.0` which enables the physically-correct darkening. This may or may not match a renderer's handling of the `KHR_materials_clearcoat` extension as modeling these internal reflections was not required by that extension. Therefore it is left up to the implementor of conversion tools whether to set this property to `0.0` during conversion.
Copy file name to clipboardExpand all lines: extensions/2.0/Khronos/KHR_materials_coat/schema/material.KHR_materials_coat.schema.json
+1-9Lines changed: 1 addition & 9 deletions
Original file line number
Diff line number
Diff line change
@@ -40,15 +40,7 @@
40
40
"type": "number",
41
41
"description": "The index of refraction of the coat layer.",
42
42
"default": 1.5,
43
-
"oneOf": [
44
-
{
45
-
"minimum": 0.0,
46
-
"maximum": 0.0
47
-
},
48
-
{
49
-
"minimum": 1.0
50
-
}
51
-
],
43
+
"minimum": 1.0,
52
44
"gltf_detailedDescription": "The index of refraction (IOR) of the coat layer is a measured physical number usually in the range between 1 and 2 that determines how much the path of light is bent, or refracted, when entering the coat material. It also influences the ratio between reflected and transmitted light in the coat layer, calculated from the Fresnel equations."
0 commit comments