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_specular #1719

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
3847e6b
Added KHR_materials_specular.
proog128 Dec 2, 2019
cbd0d0e
Split texture.
proog128 Dec 18, 2019
3c3e048
Added more details, removed energy-preserving diffuse BRDF for now.
proog128 Mar 2, 2020
0cf4352
Allow 1-channel texture for specular color.
proog128 Mar 3, 2020
e9fc32b
Added conversion from spec-gloss.
proog128 Mar 4, 2020
2102679
Implementation section now aligns better to current glTF 2.0 spec; cl…
proog128 May 8, 2020
cdad1e2
Describe conversion from KHR_materials_pbrSpecularGlossiness.
proog128 May 8, 2020
75083f1
Pack all values in one texture, use enum to indicate texture type.
proog128 May 8, 2020
758eef8
Add images.
proog128 May 8, 2020
20aa586
Several minor improvements.
proog128 May 8, 2020
975a226
Clarify requirement of specularTextureType.
proog128 May 8, 2020
63d8343
Remove texture type.
proog128 May 18, 2020
e73ff06
Add non-normative marker.
proog128 May 18, 2020
05e0f7b
Remove all traces of specularColorTexture (it is now merged into spec…
proog128 May 20, 2020
a2b0c05
Add contributors and Khronos copyright.
proog128 May 22, 2020
a62f4c9
Removed empty section.
proog128 Jun 15, 2020
3da2dfc
Add details about complementary color weight.
proog128 Jul 15, 2020
c4f87b2
Add exclusions section and fix small issues.
proog128 Aug 4, 2020
1cd78c6
Suggest ior=1000 for conversion from spec-gloss to metal-rough, as 0 …
proog128 Aug 19, 2020
06f85d7
Increase recommended ior for spec-gloss conversion.
proog128 Jan 12, 2021
e41ed16
Update copyright year.
proog128 Jan 12, 2021
abf2200
Add note to explain spec-gloss conversion.
proog128 Jan 12, 2021
e53e478
Make compatible to new Appendix B.
proog128 Jan 18, 2021
229d53a
Recommend ior=0 for spec-gloss conversion.
proog128 Jan 19, 2021
7a3c821
Split specularTexture.
proog128 Jan 29, 2021
2002ef9
Remove upper limit of specular color and change recommendation for re…
proog128 Jan 29, 2021
8ae8ce6
Fix bug in fresnel_mix.
proog128 Feb 18, 2021
2c45562
Update contributor list
emackey Apr 5, 2021
4251448
Draft status
emackey Apr 5, 2021
395c52e
More contributors
emackey Apr 5, 2021
fc08213
Add suggestion from Alexey regarding clamping.
proog128 Apr 6, 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
296 changes: 296 additions & 0 deletions extensions/2.0/Khronos/KHR_materials_specular/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
# KHR\_materials\_specular

## Contributors

* Tobias Haeussler, Dassault Systemes [@proog128](https://github.com/proog128)
* Bastian Sdorra, Dassault Systemes [@bsdorra](https://github.com/bsdorra)
* Mike Bond, Adobe, [@miibond](https://github.com/MiiBond)
* Emmett Lalish, Google [@elalish](https://github.com/elalish)
* Don McCurdy, Google [@donrmccurdy](https://twitter.com/donrmccurdy)
* Norbert Nopper, UX3D [@UX3DGpuSoftware](https://twitter.com/UX3DGpuSoftware)
* Richard Sahlin, IKEA [@rsahlin](https://github.com/rsahlin)
* Eric Chadwick, Wayfair [echadwick-wayfair](https://github.com/echadwick-wayfair)
* Ben Houston, ThreeKit [@bhouston](https://github.com/bhouston)
* Gary Hsu, Microsoft [@bghgary](https://twitter.com/bghgary)
* Sebastien Vandenberghe, Microsoft [@sebavanjs](https://twitter.com/sebavanjs)
* Nicholas Barlow, Microsoft
* Nicolas Savva, Autodesk [@nicolassavva-autodesk](https://github.com/nicolassavva-autodesk)
* Henrik Edstrom, Autodesk
* Bruce Cherniak, Intel
* Adam Morris, Target [@weegeekps](https://github.com/weegeekps)
* Sandra Voelker, Target
* Alex Jamerson, Amazon
* Thomas Dideriksen, Amazon
* Alex Wood, AGI [@abwood](https://twitter.com/abwood)
* Ed Mackey, AGI [@emackey](https://twitter.com/emackey)
* Alexey Knyazev [@lexaknyazev](https://github.com/lexaknyazev)

Copyright (C) 2018-2021 The Khronos Group Inc. All Rights Reserved. glTF is a trademark of The Khronos Group Inc.
See [Appendix](#appendix-full-khronos-copyright-statement) for full Khronos Copyright Statement.

## Status

Draft

## Dependencies

Written against the glTF 2.0 spec.

## Exclusions

* This extension must not be used on a material that also uses `KHR_materials_pbrSpecularGlossiness`.
* This extension must not be used on a material that also uses `KHR_materials_unlit`.

## Overview

This extension adds two parameters to the metallic-roughness material: `specular` and `specularColor`.

`specular` allows users to configure the strength of the specular reflection in the dielectric BRDF. A value of zero disables the specular reflection, resulting in a pure diffuse material. The metal BRDF is not affected by the parameter.
rsahlin marked this conversation as resolved.
Show resolved Hide resolved

`specularColor` changes the F0 color of the specular reflection in the dielectric BRDF, allowing artists to use effects known from the specular-glossiness material (`KHR_materials_pbrSpecularGlossiness`) in the metallic-roughness material.
rsahlin marked this conversation as resolved.
Show resolved Hide resolved

## Extending Materials

The strength of the specular reflection is defined by adding the `KHR_materials_specular` extension to any glTF material.

```json
{
"materials": [
{
"extensions": {
"KHR_materials_specular": {
"specularFactor": 1.0,
"specularColorFactor": [1.0, 1.0, 1.0],
}
}
}
]
}
```

Factor and texture are combined by multiplication to describe a single value.

| |Type|Description|Required|
|-|----|-----------|--------|
| **specularFactor** | `number` | The strength of the specular reflection. | No, default: `1.0`|
rsahlin marked this conversation as resolved.
Show resolved Hide resolved
| **specularTexture** | `textureInfo` | A texture that defines the strength of the specular reflection, stored in the alpha (`A`) channel. This will be multiplied by specularFactor. | No |
| **specularColorFactor** | `number[3]` | The F0 color of the specular reflection (linear RGB). | No, default: `[1.0, 1.0, 1.0]`|
| **specularColorTexture** | [`textureInfo`](/specification/2.0/README.md#reference-textureInfo) | A texture that defines the F0 color of the specular reflection, stored in the `RGB` channels and encoded in sRGB. This texture will be multiplied by specularColorFactor. | No |

The `specular` and `specularColor` parameters affect the `dielectric_brdf` of the glTF 2.0 metallic-roughness material.

```
dielectric_brdf =
fresnel_mix(
f0_color = specularColor.rgb,
ior = 1.5,
weight = specular,
base = diffuse_brdf(color = baseColor),
layer = specular_brdf(α = roughness^2))
```

The `fresnel_mix` function mixes two BSDFs according to a Fresnel term. The `layer` is weighted with `weight * fresnel(ior, f0_color)`. The `base` is weighted with `1 - weight * fresnel(ior, f0_color)`.

The specular factor used as `weight` scales `layer` and `base`. The less energy is reflected by the `layer` (`specular_brdf`), the more can be shifted to the `base` (`diffuse_brdf`). The following image shows specular factor increasing from 0 to 1.

![](figures/specular.png)

The specular color is a directional-dependent weight included in the Fresnel term. At normal incidence (`f0`), `specularColor` scales the F0 reflectance `f0_color`. At grazing incidence (`f90`), the reflectance remains at 1. In between the scale factor is smoothly interpolated.

As with specular factor, `base` will be weighted with the directional-dependent remaining energy according to the Fresnel term. `f0_color` is an RGB color, involving the complementary to specular color. To make it easy to use and ensure energy conservation, the RGB color is converted to scalar via `max(r, g, b)`. The following images show specular color increasing from [0,0,0] to [1,1,1] (top) and from [0,0,0] to [1,0,0] (bottom).

![](figures/specular-color.png)
![](figures/specular-color-2.png)

The specular color factor is allowed to be set to values greater than [1, 1, 1]. Thus, the reflection amount can go beyond what is determined by the index of refraction (IOR). To still ensure energy conservation, the product of specular color factor, specular color texture, and f0 reflectance from IOR is clamped to 1. Please refer to [Implementation](#Implementation) for an example on where to place the clamping operation.

## Implementation

*This section is non-normative.*

[Appendix B](/specification/2.0/README.md#appendix-b-brdf-implementation) defines the function `fresnel_mix`. In this extension, we add two additional arguments called `weight` and `f0_color`. It scales `f0` computed inside the function:

```
function fresnel_mix(f0_color, ior, weight, base, layer) {
f0 = ((1-ior)/(1+ior))^2 * f0_color
f0 = min(f0, float3(1.0))
fr = f0 + (1 - f0)*(1 - abs(VdotH))^5
return mix(base, layer, weight * fr)
}
```

Therefore, the Fresnel term `F` in the final BRDF of the material changes to

```
dielectricSpecularF0 = min(0.04 * specularColorFactor * specularColorTexture.rgb, float3(1.0)) *
specularFactor * specularTexture.a
dielectricSpecularF90 = specularFactor * specularTexture.a

F0 = lerp(dielectricSpecularF0, baseColor.rgb, metallic)
F90 = lerp(dielectricSpecularF90, 1, metallic)

F = F0 + (F90 - F0) * (1 - VdotH)^5
```

Note that in `dielectricSpecularF0` we clamp the product of specular color and f0 reflectance from IOR (`0.04`), before multiplying by specular.

In the diffuse component we have to account for the fact that `F` is now an RGB value.

```
c_diff = lerp(baseColor.rgb * (1 - max(F0.r, F0.g, F0.b)), black, metallic)
diffuse = c_diff / PI
f_diffuse = (1 - max(F.r, F.g, F.b)) * diffuse
emackey marked this conversation as resolved.
Show resolved Hide resolved
```

## Interaction with other extensions

If `KHR_materials_ior` is used in combination with `KHR_materials_specular`, the constant `0.04` is replaced by the value computed from the IOR.

```
dielectricSpecularF0 = min(((ior - outside_ior) / (ior + outside_ior))^2 * specularColorFactor * specularColorTexture.rgb, float3(1.0)) * specularFactor * specularTexture.a
dielectricSpecularF90 = specularFactor * specularTexture.a
```

`outside_ior` is typically set to 1.0, the index of refraction of air.

If `KHR_materials_transmission` is used in combination with `KHR_materials_specular`, the ratio of transmission and reflection computed from the Fresnel term also depends on `dielectricSpecularF0` and `dielectricSpecularF90`. The following images show a thin, transmissive material.

Specular from 0 to 1:

![](figures/specular-thin.png)

Specular color from [0,0,0] to [1,1,1] (top) and [0,0,0] to [1,0,0]:

![](figures/specular-color-thin.png)
![](figures/specular-color-thin-2.png)

If `KHR_materials_transmission` and `KHR_materials_volume` are used in combination with `KHR_materials_specular`, specular factor and specular color have no effect on the refraction angle. The direction of the refracted light ray is only based on the index of refraction defined in `KHR_materials_ior`. The ratio of transmission and reflection computed from the Fresnel term still depends on `dielectricSpecularF0` and `dielectricSpecularF90`. The following images show a refractive material.

Specular from 0 to 1:

![](figures/specular-refraction.png)

Specular color from [0,0,0] to [1,1,1] (top) and [0,0,0] to [1,0,0]:

![](figures/specular-color-refraction.png)
![](figures/specular-color-refraction-2.png)

## Conversions

### Materials with reflectance parameter

Material models that define F0 in terms of reflectance at normal incidence can be converted by encoding the reflectance in the specular color parameters. Typically, the reflectance ranges from 0% to 8%, given as a value in range [0,1], with 0.5 (=4%) being the default. F0 is computed from `reflectance` in the following way:

```
dielectricSpecularF0 = 0.08 * reflectance
```

In contrast, `KHR_materials_specular` defines a constant factor of 0.04 to compute F0, as this corresponds to glTF's default IOR of 1.5. Therefore, by encoding an additional constant factor of 2 in `specularColorFactor`, we can convert from reflectance to specular color without any loss.

The following JSON snippets shows the conversion from `reflectanceFactor` and `reflectanceTexture` to `specularColorFactor` and `specularColorTexture`:

```json
{
"materials": [
{
"extensions": {
"KHR_materials_specular": {
"specularColorFactor": [2 * reflectanceFactor],
"specularColorTexture": [reflectanceTexture]
}
}
}
]
}
```

### Specular-glossiness materials

Materials that use the specular-glossiness workflow (`KHR_materials_pbrSpecularGlossiness`) can be converted with help of the `KHR_materials_ior`. The `ior` parameter has to be set to 0. In JSON:

```json
{
"materials": [
{
"extensions": {
"KHR_materials_specular": {
"specularColorFactor":
[KHR_materials_pbrSpecularGlossiness__specularFactor],
},
"KHR_materials_ior": {
"ior": 0
}
}
}
]
}
```

This makes it possible to add advanced effects like clearcoat (`KHR_materials_clearcoat`) and sheen (`KHR_materials_sheen`) to traditional specular-glossiness materials.

> **NOTE**
>
> As the `ior` also affects the refraction effect, this conversion is not compatible with volumetric materials (`KHR_materials_volume`). We do not recommended to use this conversion when creating new materials from scratch.

> **Why does it work?**
>
> There is no clear separation between dielectrics and metals in the specular-glossiness workflow. Thus, it is possible to create materials that do not fall into either of the categories. This doesn't have to be an explicit decision in authoring (although it can be for various artistic styles), it is often just the result of baking several materials into a single texture. Due to anti-aliasing at the borders some texels contain a mix of different material types. This mix may not map to metallic-roughness parameters that are in a realistic range.
>
> We achieve an easy, lossless mapping by treating any specular-glossiness material, even pure metals, as dielectric materials in the metallic-roughness workflow. `KHR_materials_ior` gives us the means to do so. As the `ior` determines the upper bound of the specular reflection's strength, we can increase it to its maximum, making it large enough to hold all possible specular-glossiness materials. Looking at the formula to compute F0 from IOR `f0 = ((ior - outside_ior) / (ior + outside_ior))^2`, we can see that both `ior = 0` and `ior = inf` will result in `f0 = 1`. As `f0` is multiplied by specular color, the value `1` will give us full control over the specular reflection via the specular color.

## Schema

- [glTF.KHR_materials_specular.schema.json](schema/glTF.KHR_materials_specular.schema.json)

## Appendix: Full Khronos Copyright Statement

Copyright 2018-2021 The Khronos Group Inc.

Some parts of this Specification are purely informative and do not define requirements
necessary for compliance and so are outside the Scope of this Specification. These
parts of the Specification are marked as being non-normative, or identified as
**Implementation Notes**.

Where this Specification includes normative references to external documents, only the
specifically identified sections and functionality of those external documents are in
Scope. Requirements defined by external documents not created by Khronos may contain
contributions from non-members of Khronos not covered by the Khronos Intellectual
Property Rights Policy.

This specification is protected by copyright laws and contains material proprietary
to Khronos. Except as described by these terms, it or any components
may not be reproduced, republished, distributed, transmitted, displayed, broadcast
or otherwise exploited in any manner without the express prior written permission
of Khronos.

This specification has been created under the Khronos Intellectual Property Rights
Policy, which is Attachment A of the Khronos Group Membership Agreement available at
www.khronos.org/files/member_agreement.pdf. Khronos grants a conditional
copyright license to use and reproduce the unmodified specification for any purpose,
without fee or royalty, EXCEPT no licenses to any patent, trademark or other
intellectual property rights are granted under these terms. Parties desiring to
implement the specification and make use of Khronos trademarks in relation to that
implementation, and receive reciprocal patent license protection under the Khronos
IP Policy must become Adopters and confirm the implementation as conformant under
the process defined by Khronos for this specification;
see https://www.khronos.org/adopters.

Khronos makes no, and expressly disclaims any, representations or warranties,
express or implied, regarding this specification, including, without limitation:
merchantability, fitness for a particular purpose, non-infringement of any
intellectual property, correctness, accuracy, completeness, timeliness, and
reliability. Under no circumstances will Khronos, or any of its Promoters,
Contributors or Members, or their respective partners, officers, directors,
employees, agents or representatives be liable for any damages, whether direct,
indirect, special or consequential damages for lost revenues, lost profits, or
otherwise, arising from or in connection with these materials.

Vulkan is a registered trademark and Khronos, OpenXR, SPIR, SPIR-V, SYCL, WebGL,
WebCL, OpenVX, OpenVG, EGL, COLLADA, glTF, NNEF, OpenKODE, OpenKCAM, StreamInput,
OpenWF, OpenSL ES, OpenMAX, OpenMAX AL, OpenMAX IL, OpenMAX DL, OpenML and DevU are
trademarks of The Khronos Group Inc. ASTC is a trademark of ARM Holdings PLC,
OpenCL is a trademark of Apple Inc. and OpenGL and OpenML are registered trademarks
and the OpenGL ES and OpenGL SC logos are trademarks of Silicon Graphics
International used under license by Khronos. All other product names, trademarks,
and/or company names are used solely for identification and belong to their
respective owners.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"$schema": "http://json-schema.org/draft-04/schema",
"title": "KHR_materials_specular glTF extension",
"type": "object",
"description": "glTF extension that defines the strength of the specular reflection.",
"allOf": [ { "$ref": "glTFProperty.schema.json" } ],
"properties": {
"specularFactor": {
"type": "number",
"description": "The strength of the specular reflection.",
"default": 1.0,
"minimum": 0.0,
"maximum": 1.0,
"gltf_detailedDescription": "This parameter scales the amount of specular reflection on non-metallic surfaces. It has no effect on metals."
},
"specularTexture": {
"allOf": [ { "$ref": "textureInfo.schema.json" } ],
"description": "A texture that defines the specular factor in the alpha channel.",
"gltf_detailedDescription": "A texture that defines the specular factor in the alpha channel. This will be multiplied by specularFactor."
},
"specularColorFactor": {
"type": "array",
"items": {
"type": "number",
"minimum": 0.0
lexaknyazev marked this conversation as resolved.
Show resolved Hide resolved
},
"description": "The F0 RGB color of the specular reflection.",
"default": [ 1.0, 1.0, 1.0 ],
"minItems": 3,
"maxItems": 3,
"gltf_detailedDescription": "This is an additional RGB color parameter that tints the specular reflection of non-metallic surfaces. At grazing angles, the reflection still blends to white, and the parameter has not effect on metals. The value is linear."
},
"specularColorTexture": {
"allOf": [ { "$ref": "textureInfo.schema.json" } ],
"description": "A texture that defines the F0 color of the specular reflection.",
"gltf_detailedDescription": "A texture that defines the specular color in the RGB channels (encoded in sRGB). This will be multiplied by specularColorFactor."
},
"extensions": { },
"extras": { }
}
}