Skip to content

EXT_materials_specular_edge_color #2488

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

MiiBond
Copy link
Contributor

@MiiBond MiiBond commented May 12, 2025

Here's an extremely rough draft of an OpenPBR-compatible specular extension.
Based on @lexaknyazev's advice, I've made this a sub extension of KHR_materials_specular as they share the same parameters though I'm not sure how to specify this requirement in the schema.

Feedback would be very appreciated.


Specular reflectance in glTF as defined by `KHR_materials_specular` behaves a bit different than in OpenPBR. This extension defines an interpretation of the specular parameters that is compatible with OpenPBR's specular reflectance for both dielectrics and metals.

This extension adds no additional parameters. Its presence merely changes how the parameters of `KHR_materials_specular` are used.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PBR Material extensions are generally designed to be "as if always defined" with their default state not affecting the material appearance. To follow this convention, consider adding a boolean property (optional, false by default) that enables the new semantics.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a single boolean value to the extension to enable it.

@@ -0,0 +1,145 @@
# EXT\_materials\_specular\_openpbr
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be safer to name the extension based on the actual interpretation difference rather than using a reference.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was expecting that issue to be raised but I'm not sure of a good name.
EXT_materials_specular_edge_color?
EXT_materials_specular_f82? - the F82 really only refers to the metallic model so probably isn't ideal.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed the name to EXT_materials_specular_edge_color for now.

Copy link
Contributor

@bghgary bghgary left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know the math to be able to review that part, but the wording and explanation seems fine to me.

@MiiBond MiiBond changed the title EXT_materials_specular_openpbr EXT_materials_specular_edge_color May 16, 2025
#### EXT_materials_specular_edge_color
![](figures/edgeColorDielectricColor.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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sentence doesn't seem to be valid anymore.
Also, I think the reflectance conversion as such doesn't work when the specular color also affects f90.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the needed logic here is a bit more complex. I've tried to clarify.

Basically, OpenPBR allows specular_weight > 1.0 but not specular_color. Assuming that we want the data to remain the same for this sub-extension, we need to apply specularColorFactors > 1 to the weighting while keeping the color itself as a multiply on the specular lobe. I've updated the implementation code as well. Does it make sense?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me

```
function fresnel_mix(specular_color, ior, weight, base, layer) {
f0 = ((1-ior)/(1+ior))^2
f0 = min(f0, float3(1.0))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

min not needed anymore

f0 = ((1-ior)/(1+ior))^2
f0 = min(f0, float3(1.0))
fr = f0 + (1 - f0)*(1 - abs(VdotH))^5
return (1 - weight * fr) * base + weight * fr * specular_color * layer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the base weight needs to consider the specular_color for reasons of energy preservation. E.g. low specular_color will lead to low specular contribution that is not compensated by the base layer. Also specular color values > 1.0 need to be handled somehow. Haven't fully thought this through but maybe sth. like

specular_weight =  weight * fr * min(specular_color, float3(1.0))
base_weight = 1 -  max_value(specular_weight)
return base_weight * base + specular_weight * layer

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that, in OpenPBR, specular_color does not effect the base weight.
From the specs:

The specular_color parameter modulates the Fresnel factor of Fdielectric, but only for the initial reflection of light incident from above, while the light transmitted from above or below (or reflected from below) is assumed to be unaffected. This is technically unphysical if altered from the default white color (as real dielectrics have a Fresnel factor dependent only on the index of refraction), but can be useful in practice to artificially tint the specular highlight without disturbing other aspects of the light transport, i.e. the reflection due to scattering from the internal medium, or the reflection from below, or the transmission from above or below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I've got something that works in the Implementation section now.
I definitely wasn't handling the > 1.0 case correctly.

}
```
All that remains is a simple lerp between the dielectric and metallic lobes based on the metallic value.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe small code chunk that shows the lerp for clarity?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants