-
Notifications
You must be signed in to change notification settings - Fork 240
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
Correctly interpret material roughness as perceptual and convert to material #34
Conversation
I was back and forth on the naming; I feel like roughnessSq doesn't properly convey the conceptual difference between the perceptual roughness in the texture and the transformed material roughness. If anything, I could just name one "perceptualRoughness" and the other "materialRoughness" or something. |
Oh, this is interesting. I had no idea that the roughness from the textures wasn't the same as the material roughness discussed in papers. @snagy, do you have a reference to confirm this? I do agree that the branch's results captures the specular falloffs more nicely. As for naming, I think that being explicit and naming the variables |
Isn't that just a ... how to call it ... "implementation detail" or "convention" that was introduced by Disney? See https://disney-animation.s3.amazonaws.com/library/s2012_pbs_disney_brdf_notes_v2.pdf#page=15 , penultimate paragraph:
Not sure what's "right" and "wrong" here, though.... |
It's definitely a convention, @javagl, but one that's currently followed in Unreal, Unity, and Frostbite, so I feel like we should side with the masses. Edit: as well as Babylon.js and three.js! |
Sure! It doesn't make sense to propose a technique that will look different from all other PBR renderers. I also wanted to add the link here to give a reference (as moneimne asked for this), and maybe this explains where the name "alpha" comes from - although I also think that this is a highly unfortunate name, as "alpha" in rendering usually refers to opacity (24 letters, and they had to pick this one... however, |
Well I guess my call for reference is less about the theory and more about the glTF 2.0 spec here. Roughness will be a value between 0.0 and 1.0 regardless of whether we square it or not, but which visual results would artists expect when creating a model? Right now, the spec only mentions that |
Given that the other implementations are already doing this, our behavior should follow theirs. It was already demonstrated with the "Y flip" issue that at this late stage we would rather clarify (or even edit) the spec to match existing implementations, rather than ask all of the implementations to change. |
The spec already describes the behavior represented in this PR:
I don't think an update to the spec is required, and I don't really think that we need to call this out specifically in the shader code as to why we're doing it (there's a lot of conventional assumptions being made all over the place!) For me, the main question is naming; do we stick with 'alpha' because that's what the spec calls it, or should we call it something else? |
Formulas in the spec tend to use single-letter variable names, but implementations would do well to use longer, clearer names where possible.
|
Ah, I'm sorry I should have read the line changes more carefully in the shader. I assumed we were already taking into account that I didn't know that |
shaders/pbr-frag.glsl
Outdated
@@ -106,7 +107,7 @@ float geometricOcclusionCookTorrance(PBRInfo pbrInputs) | |||
// implementation of microfacet occlusion from “An Inexpensive BRDF Model for Physically based Rendering” by Christophe Schlick | |||
float geometricOcclusionSchlick(PBRInfo pbrInputs) | |||
{ | |||
float k = pbrInputs.roughness * 0.79788; // 0.79788 = sqrt(2.0/3.1415); | |||
float k = pbrInputs.alpha * 0.79788; // 0.79788 = sqrt(2.0/3.1415); | |||
// alternately, k can be defined with | |||
// float k = (pbrInputs.roughness + 1)*(pbrInputs.roughness + 1)/8; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could be wrong here, but in Schlick's paper, he presents k=sqrt(2*m*m / PI)
(Equation 19). Does that suggest that we should keep pbrInputs.roughness here?
Also, I noticed in the Epic paper that they only did this alpha remapping (roughness + 1)/2) * (roughness + 1)/2), for analytic light sources and that with IBL the results at glancing angles is too dark.
@moneimne I don't think we should use alpha for the brdf lookup. In their paper, they state the input is Roughness (with no mention to alpha). |
@abwood, yeah I think you're right. The sample code in UE4's paper seems to distinguish between |
// alternately, k can be defined with | ||
// float k = (pbrInputs.roughness + 1)*(pbrInputs.roughness + 1)/8; | ||
// float k = (pbrInputs.alphaRoughness + 1)*(pbrInputs.alphaRoughness + 1)/8; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to Epic's implementation notes, this commented-out alternative should use pbrInputs.perceptualRoughness rather than alphaRoughness:
float k = (pbrInputs.perceptualRoughness + 1)*(pbrInputs.perceptualRoughness + 1)/8;
See Equation 4 in http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was my impression, too.
We also chose to use Disney’s modification to reduce “hotness” by remapping roughness using (Roughness+1)/2 before squaring.
Just that one comment from me. From a visual standpoint this is a great improvement 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall! Just echoing @abwood on his review.
// alternately, k can be defined with | ||
// float k = (pbrInputs.roughness + 1)*(pbrInputs.roughness + 1)/8; | ||
// float k = (pbrInputs.alphaRoughness + 1)*(pbrInputs.alphaRoughness + 1)/8; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was my impression, too.
We also chose to use Disney’s modification to reduce “hotness” by remapping roughness using (Roughness+1)/2 before squaring.
Since the only remaining review comment is on a line that's commented out, I'm going to merge this. @abwood can you open a PR with the proposed change that didn't get included here? Thanks! |
The roughness value stored in the PBR textures is perceptual linear roughness, and needs to be converted to material roughness. Most folks square the linear roughness to get a good material roughness estimate, so we'll do that as well.
This changes the look of surfaces but is more aligned with how other renderers display the same content.