Skip to content

Commit 2a1111b

Browse files
committed
Clarify how specular color > 1 behaves
1 parent a8e9e47 commit 2a1111b

File tree

1 file changed

+12
-3
lines changed
  • extensions/2.0/Vendor/EXT_materials_specular_edge_color

1 file changed

+12
-3
lines changed

extensions/2.0/Vendor/EXT_materials_specular_edge_color/README.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ Here is the same comparison for colored specular, increasing from [0,0,0] to [1,
8989
#### EXT_materials_specular_edge_color
9090
![](figures/edgeColorDielectricColor.png)
9191

92-
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.
92+
In OpenPBR, specular_weight can exceed 1.0 but not specular_color. In KHR_materials_specular, the opposite is true. In this extension, we inherit the same properties so proper clamping needs to be used to ensure energy conservation and compatibility with OpenPBR. For specular color factor values greater than 1.0, we increase the specular factor by that amount and then normalize the specular color factor. This new weight is then clamped so that the fresnel mix does not result in diffuse dropping below 0.0 or specular going above 1.0. Please refer to [Implementation](#Implementation) for an example on where to place the clamping operations.
9393

9494
### Conductors
9595

@@ -117,9 +117,13 @@ From the OpenPBR specs:
117117
```
118118
function fresnel_mix(specular_color, ior, weight, base, layer) {
119119
f0 = ((1-ior)/(1+ior))^2
120-
f0 = min(f0, float3(1.0))
121120
fr = f0 + (1 - f0)*(1 - abs(VdotH))^5
122-
return (1 - weight * fr) * base + weight * fr * specular_color * layer
121+
max_specular = max_value(specular_color)
122+
if (max_specular > 1.0) {
123+
weight *= max_specular
124+
specular_color /= max_specular
125+
}
126+
return max(1 - weight * fr, 0.0) * base + min(weight * fr * specular_color, 1.0) * layer
123127
}
124128
```
125129

@@ -144,6 +148,11 @@ function fresnel_f82(specular_color, weight, F0, roughness) {
144148
}
145149
```
146150
All that remains is a simple lerp between the dielectric and metallic lobes based on the metallic value.
151+
```
152+
dielectric_specular = fresnel_mix(specular_color, ior, specular_weight, base, layer);
153+
metallic_specular = fresnel_f82(specular_color, specular_weight, F0, roughness);
154+
final_spec = mix(dielectric_specular, metallic_specular, metallic);
155+
```
147156

148157
## Interaction with other extensions
149158

0 commit comments

Comments
 (0)