HLMS PBR BRDF

Discussion area about developing with Ogre2 branches (2.1, 2.2 and beyond)
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4496
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 935
Contact:

Re: HLMS PBR BRDF

Post by dark_sylinc »

@xrgo
I'm comparing the BRDF from Filament you ported and it is actually not very different from ours!!!

Mathematically, VdotH is the same as LdotH (because H is the halfway vector and sits in the exactly in the middle between V and L)

Filament squares roughness, which we don't (I suspect this is THE main difference):

Code: Select all

float roughness = pixelData.roughness * pixelData.roughness;
We perform R term:

Code: Select all

float f = ( NdotH * sqR - NdotH ) * NdotH + 1.0;
float R = sqR / (f * f + 1e-6f);
They perform:

Code: Select all

float a2 = a * a; //note: a2 = sqR.
float f = (NoH * a2 - NoH) * NoH + 1.0;
return a2 / (PI * f * f);
The only difference is their last multiplication by PI in the divisor which we don't. But we perform it later (continue reading).

We perform G term:

Code: Select all

float Lambda_GGXV = NdotL * sqrt( (-pixelData.NdotV * sqR + pixelData.NdotV) * pixelData.NdotV + sqR );
float Lambda_GGXL = pixelData.NdotV * sqrt( (-NdotL * sqR + NdotL) * NdotL + sqR );

float G = 0.5 / (( Lambda_GGXV + Lambda_GGXL + 1e-6f ) * 3.141592654);
They perform:

Code: Select all

float a2 = a * a;
float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2);
float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2);
return 0.5 / (GGXV + GGXL);
The only difference is their last multiplication by PI in the divisor which they don't. But Filament does this in the R term. R and G get multiplied together, so this is essentially the same thing.

Basically:
(R / PI) * G = R * (G / PI)

Schlick (fresnel) is exactly the same code, so no need to compare.

Another subtle difference:
We do:

Code: Select all

float3 Rs = ( fresnelS * (R * G) ) * pixelData.specular.xyz * lightSpecular;
They do:

Code: Select all

vec3 Fr = (D * V) * F;
At no point your modified code uses "pixelData.specular.xyz * lightSpecular", so that's different. But you use lightDiffuse instead. They're extremely likely to be the same value but not necessarily.

Your code doesn't use pixelData.specular.xyz which is wrong (this is user/material data; could be set to 1,1,1 which is the default)

We perform more fancy stuff with diffuse, but it causes some subtle differences, nothing ultra major.

Therefore the main differences between the BRDF you implemented from filament and our current default are:
  • Roughness is squared (I suspect this is THE major cause of the difference)
  • You use lightDiffuse, don't use lightSpecular nor pixelData.specular.xyz
  • Ogre does some more fancy stuff with diffuse (I seriously doubt this is the reason)
xrgo: Could you try once again the default BRDF from Ogre, but with the following modification?

Code: Select all

float sqR = pixelData.roughness * pixelData.roughness;
sqR = sqR * sqR;
I believe this is the major difference between Filament's and our BRDF, unless pixelData.specular.xyz * lightSpecular gives a hugely different value from just multiplying against lightDiffuse

Cheers

User avatar
TaaTT4
OGRE Contributor
OGRE Contributor
Posts: 241
Joined: Wed Apr 23, 2014 3:49 pm
x 45

Re: Compute Shaders and cubemaps [SOLVED]

Post by TaaTT4 »

xrgo wrote:
Thu Dec 12, 2019 8:56 pm
now the next step is to process the cubemaps like SolarPortal did but it seems a bit over my skills
I believe it's out of my skills too. Don't know if/how much SolarPortal can share with us, but if he could provide us the computer shader he uses to process the cubemap, I guess it would be easy enough to integrate it in the PCC workflow.
Otherwise, this is the source code of the tool used in Filament to process cubemaps.
Senior game programmer at Vae Victis
Working on Racecraft

rujialiu
Goblin
Posts: 292
Joined: Mon May 09, 2016 8:21 am
x 35

Re: Compute Shaders and cubemaps [SOLVED]

Post by rujialiu »

I love this discussion!!! Recently I'm struggling with our PBR look too.
TaaTT4 wrote:
Fri Dec 13, 2019 1:36 am
I believe it's out of my skills too. Don't know if/how much SolarPortal can share with us, but if he could provide us the computer shader he uses to process the cubemap, I guess it would be easy enough to integrate it in the PCC workflow.
Otherwise, this is the source code of the tool used in Filament to process cubemaps.
I'm aware of this tool (cmgen) too. It'll be great if we can directly use its output (including the third-order SH coefficients).

User avatar
SolarPortal
OGRE Contributor
OGRE Contributor
Posts: 203
Joined: Sat Jul 16, 2011 8:29 pm
Location: UK
x 50
Contact:

Re: HLMS PBR BRDF

Post by SolarPortal »

I believe this is the major difference between Filament's and our BRDF, unless pixelData.specular.xyz * lightSpecular gives a hugely different value from just multiplying against lightDiffuse
i would apply the diffuse and specular lighting part in the end of the BRDF as such:

Code: Select all

return NoL * ( (Fd * lightDiffuse) + (Fr * lightSpecular) );
in case this helps,

i found that adding the lightdiffuse during the diffuse BRDF section caused a bug when multiplied with the light specular at the end as it would be overpowered if the powerscale of a light was large. so if diffuse was 1,1,1 multiplied by 97 powerscale, in shader the diffuse was 97,97,97, then that got multiplied by the light specular sending it out of whack due to a 97 * 97 multiplication, doing them at the end fixed it for me :)
Lead developer of the Skyline Game Engine: https://aurasoft-skyline.co.uk

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4496
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 935
Contact:

Re: Compute Shaders and cubemaps [SOLVED]

Post by dark_sylinc »

I'll be trying to implement this extremely soon.
TaaTT4 wrote:
Fri Dec 13, 2019 1:36 am
xrgo wrote:
Thu Dec 12, 2019 8:56 pm
now the next step is to process the cubemaps like SolarPortal did but it seems a bit over my skills
I believe it's out of my skills too. Don't know if/how much SolarPortal can share with us, but if he could provide us the computer shader he uses to process the cubemap, I guess it would be easy enough to integrate it in the PCC workflow.
I'll explain in it in plain english.

What we're doing right now is (explaining specular for now):
  1. Grab a cubemap
  2. Generate the mipmaps with a simple filter (i.e. a regular downscale, or a gaussian one if you're fancy which gets blurrier less blocky results)
  3. In the pixel shader, we sample the cubemap (using mip = roughness)
  4. Perform a simple fake BRDF approximation to blend this sampled value from previous step into the final result
What needs to be fixed:

This is a bad approximation. Looks cool, but that's it. For Mip 0 (e.g. roughness = 0), there's virtually no difference.
But once the roughness becomes higher, the mips we sample are wrong.

We need to improve step 2 (mipmap generation) and step 4 (BRDF) formula.

Fixing Mipmaps (step 2)
Mipmaps must be generated by evaluating lots of samples from its lower mip.

The best way is to think this mipmap generation as a smaller sphere (mip N+1) integrating the output BRDF coming from a bigger sphere (mip N).
In 2D it would look like the smaller circle is shooting rays to sample the bigger one:
Circles.png
Circles.png (11.09 KiB) Viewed 1280 times
IBLBaker has an easy to understand code about it.

The function "ImportanceSample" shoots "ConvolutionSampleCount" rays and averages them together with a particular formula (this 'particular formula' is tuned to match the BRDF behavior)

Other resources that explain this step:
https://placeholderart.wordpress.com/20 ... -lighting/
https://learnopengl.com/PBR/IBL/Specular-IBL
http://chanhaeng.blogspot.com/2018/08/p ... r-ibl.html (in Korean)
https://www.cnblogs.com/bitzhuwei/p/specular-IBL.html (in Chinese)

Fixing Merging in Pixel Shader (step 4)
When we integrated the larger sphere into a smaller sphere:
Circles.png
Circles.png (11.09 KiB) Viewed 1280 times
We had 2 things: Normal (perpendicular to the sphere), incoming Light direction (the direction of each ray, it's blue in the picture).
However we need two more we didn't have at that time: Eye direction (only known at render time) and roughness (varies per material).

Therefore the cubemap integration is a precomputed value that is incomplete. However it can be completed at render time with another 2D texture which stores lots of combinations of NdotV (Normal dot View) in one axis, and Roughness in the other.

IblBrdf.hlsl performs this step where the function integrate() generates that look up texture, and stores coefficient for NdotV in X axis, and coefficient for Roughness in the Y offset.

The resulting texture looks like this, and can doesn't change with scenes/materials/etc:
383191-20190506023301378-1055636818.png
383191-20190506023301378-1055636818.png (34.98 KiB) Viewed 1280 times
This lookup texture can be generated once and then stored on disk.

Thus, once we have these two things (filtered cubemap and brdf 2D lookup table), we need to perform:

Code: Select all

float lod = getMipLevelFromRoughness(roughness);
float3 prefilteredColor = textureCubeLod(PrefilteredEnvMap, refVec, lod);
float2 envBRDF = texture2D(BRDFIntegrationMap, float2(NdotV, roughness)).xy;
float3 indirectSpecular = prefilteredColor * (F * envBRDF.x + envBRDF.y);
What I'll be doing is integrating IBLBaker's code into Ogre.

cmgen looks gigantic because there's a lot of C++ code to load textures from files, a lot of code to sample them (i.e. sample uvw coordinates by hand) and save this texture; whereas the actual work is much smaller and easier.

Diffuse IBL

Diffuse IBL is the same as Specular IBL (integrate a bigger sphere into a smaller sphere), but it is much easier because:
  1. We often assume it doesn't change with roughness (it's wrong but nobody cares)
  2. There is no eye direction
  3. There's only normal and light vectors required (known at baking/integration time)
  4. The BRDF is much simpler (it's a simple NdotL)
Additionally, diffuse IBL looks very blurry by nature, hence a 64x64 cubemap is often enough to capture everything. More resolution doesn't really add much quality.

And SH (Spherical Harmonics) can be used to lossy compress 64x64x6 pixels into just 9 floats. But SH is not strictly necessary.
Otherwise, this is the source code of the tool used in Filament to process cubemaps.
Thanks for the link. I think I'm going to need if we implement SH (I loathe writing SH coefficient generation)

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Re: HLMS PBR BRDF

Post by xrgo »

dark_sylinc wrote:
Fri Dec 13, 2019 1:14 am
Roughness is squared (I suspect this is THE major cause of the difference)
You use lightDiffuse, don't use lightSpecular nor pixelData.specular.xyz
Ogre does some more fancy stuff with diffuse (I seriously doubt this is the reason)
thank you for the explanation =)
your'e right the squared roughness was the main difference, about lightSpecular I just forgot because I really don't care about it (usually pbr stuffs don't separate them, its physically incorrect, but it does gives more flexibility to artists)
there is a slight difference in color in the surface that might be due to the "fancy stuff with diffuse"... but its matching almost perfectly.
This means that there was a bug? and the default should have always had the squared rough? =D

dark_sylinc wrote:
Fri Dec 13, 2019 3:53 pm
I'll be trying to implement this extremely soon.
I love you so much!

User avatar
TaaTT4
OGRE Contributor
OGRE Contributor
Posts: 241
Joined: Wed Apr 23, 2014 3:49 pm
x 45

Re: Compute Shaders and cubemaps [SOLVED]

Post by TaaTT4 »

dark_sylinc wrote:
Fri Dec 13, 2019 3:53 pm
I'll be trying to implement this extremely soon.
It's xmas time!
Image

Thanks for the explanation, you made very clear what importance sampling means. Can't wait to see this improvement in action :D
Senior game programmer at Vae Victis
Working on Racecraft

rujialiu
Goblin
Posts: 292
Joined: Mon May 09, 2016 8:21 am
x 35

Re: HLMS PBR BRDF

Post by rujialiu »

dark_sylinc wrote:
Fri Dec 13, 2019 1:14 am
Filament squares roughness, which we don't (I suspect this is THE main difference):

Code: Select all

float roughness = pixelData.roughness * pixelData.roughness;
From what I understand, the squaring remapping is to make the roughness parameter "perceptually linear" (thus more intuitive).

After carefully examine Disney's PBR course note 2012, Epic's PBR course note 2013 and Frostbite's PBR course note 2014, Substance player's shader (pbr_idl.glsl and, for example, physically_metallic_roughness/fs.glsl), and filament's shader (official documentation, listing 9), I found the following:

* Substance player's implementing Epic's course note, so even the variable names match
* Variable names in Epic's course note matches Disney's course note, that means roughness is user input (i.e. can be obtained by sampling roughness map), alpha is roughness^2
* Frostbite: linearRoughness is user input, roughness is disney/epic's "alpha"
* Filament (Listing 9): perceptualRoughness is user input, roughness is disney/epic's "alpha"

So it's clear that all these engines agree that user input is the "perceptual linear" one, but current Ogre shader assumes the user input is Disney's course note's "alpha". The only place I found that is actually correct is the disney diffuse part, which actually needs user input roughness (perceptual linear).

So it may be good to change Ogre officially to match all these other engines?

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4496
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 935
Contact:

Re: HLMS PBR BRDF

Post by dark_sylinc »

rujialiu wrote:
Sat Dec 14, 2019 11:50 am
dark_sylinc wrote:
Fri Dec 13, 2019 1:14 am
Filament squares roughness, which we don't (I suspect this is THE main difference):

Code: Select all

float roughness = pixelData.roughness * pixelData.roughness;
From what I understand, the squaring remapping is to make the roughness parameter "perceptually linear" (thus more intuitive).
Note that is was a GUESS.
I want to debug to see the differences and see what we're doing differently, exactly. If someone wants to help, the help is appreciated
rujialiu wrote:
Sat Dec 14, 2019 11:50 am
So it may be good to change Ogre officially to match all these other engines?
That's the idea

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Re: HLMS PBR BRDF

Post by xrgo »

I saw the commits on the ibl branch, yay!!!
I want to know if I understand correctly, this is going to use CmgenToCubemap tool to filter the cubemaps? instead of a compute shader like SolarPortal did? is it going to work with perpixel probes captured at runtime? if so, whats the expected processing time?

Saludos!

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4496
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 935
Contact:

Re: HLMS PBR BRDF

Post by dark_sylinc »

Hi!

I managed to get IBL specular working (it's done!) using cmgen's output of course.

I was also able to verify our results match very closely that of UE4's by comparing http://gl.ict.usc.edu/Data/HighResProbe ... s/pisa.hdr with the screenshots https://blog.selfshadow.com/publication ... tes_v2.pdf (the quality of the pictures in the PDF are not great so I can't say it's a pixel-perfect match, but they look **really** alike, even the known artifacts were there).

To get specular IBL working, grab an HDR file, and run it through cmgen e.g.:

Code: Select all

./cmgen --sh-shader --sh-output=coeff.txt --size=1024 --ibl-ld=/home/matias/IBLOutput MyHdrSkybox.hdr
This will generate a series of files in /home/matias/IBLOutput (one file per face, per mip)

Then run the new tool OgreCmgenToCubemap:

Code: Select all

./OgreCmgenToCubemap /home/matias/IBLOutput png 6 SkyboxForOgre.oitd
"6" here is the number of mipmaps. The tool should be able to figure that out, but right now it doesn't so it must be specified manually.
After running this, the file "SkyboxForOgre.oitd" is a single file containing all these faces and mips together. OITD stands for Ogre Internal Texture Dump.
Theoretically other output formats (aside from OITD) are supported (friendlier ones such as KTX and DDS), but DDSCodec2::encode and ETCCodec::encode are not implemented at the time of writing.

You could also skip OgreCmgenToCubemap and load each face & mip and stitch it together yourself (see Tools/CmgenToCubemap/main.cpp, its code is not really complex, it's just moving memory around; but the code forces serialization instead of doing background streaming).

Your app needs to call loadLtcMatrix and the file brtfLutDfg.dds must be somewhere in your data folder.

Once that's done what would be missing is to have a compute shader that can generate the prefiltered cubemaps at runtime. I won't waste my time on making an offline tool, because cmgen does a good job at that.
xrgo wrote:
Mon Dec 16, 2019 2:12 am
I want to know if I understand correctly, this is going to use CmgenToCubemap tool to filter the cubemaps?
This post is already answering it, but I want to make it explicit: No. CmgenToCubemap is simply taking the output from Filament's cmgen (which are individual files, by default png files but other formats are compatible) and converts it to a friendly format ready to use by Ogre.
whats the expected processing time?
Depends geometrically on resolution. cmgen takes like 10 seconds (ballpark, I didn't time it) on an i7 7770 3.2Ghz to filter a single 1024x1024 cubemap. But takes much lower timer for smaller resolution (e.g. a 256x256 cubemap output is literally 16x smaller)
instead of a compute shader like SolarPortal did? is it going to work with perpixel probes captured at runtime?
That's planned and hopefully very soon, but not yet supported.

Help requested: If someone can document this usage about CmgenToCubemap (what is CmgenToCubemap for, how to use it with filament's cmgen) for the online manual and submit a PR, it is much appreciated.

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4496
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 935
Contact:

Re: HLMS PBR BRDF

Post by dark_sylinc »

Comparison pics.

Old vs New. The "New" pics was generated from a poor resolution source, so it's not a fair comparison, but the superiority of cmgen is still by far very obvious. The low resolution is really only noticeable in the background



rujialiu
Goblin
Posts: 292
Joined: Mon May 09, 2016 8:21 am
x 35

Re: HLMS PBR BRDF

Post by rujialiu »

dark_sylinc wrote:
Mon Dec 16, 2019 2:32 am
To get specular IBL working, grab an HDR file, and run it through cmgen e.g.:

Code: Select all

./cmgen --sh-shader --sh-output=coeff.txt --size=1024 --ibl-dir=/home/matias/IBLOutput MyHdrSkybox.hdr
hmmm... --ibl-dir is invalid in my prebuilt filament v1.4.3 (windows binary) downloaded here:
https://github.com/google/filament/releases

I had to use -x just like in this tutorial:
https://google.github.io/filament/webgl ... dball.html

And --sh-shader doesn't seem to do anything. It's no big deal though because I can still get the cubemaps. Just curious :)

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4496
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 935
Contact:

Re: HLMS PBR BRDF

Post by dark_sylinc »

Oops. The param was --ibl-ld

rujialiu
Goblin
Posts: 292
Joined: Mon May 09, 2016 8:21 am
x 35

Re: HLMS PBR BRDF

Post by rujialiu »

I've just tested the latest commits from ibl branch. Both specular and diffuse IBL works great, though our app has mainly indoor scenes so specular environment IBL is quite useless without occlusion. However, diffuse IBL looks great.

For those who wants to test SH-based diffuse IBL quickly, here is a python script to convert filament cmgen's output sh.txt to C++ code that can be used directly.

Code: Select all

print('Ogre::Vector3 shCoeffs[9] = {')
with open('sh.txt') as fp:
  for line in fp.readlines():
    code = line.strip().replace(';', ',')
    print('Ogre::Vector3' + code)
print ('};')
using SH coefficients is extremely easy:

Code: Select all

(paste the script output here)
sceneManager->setSphericalHarmonics( shCoeffs );
hlmsPbs->setAmbientLightMode( Ogre::HlmsPbs::AmbientSh );
Note that SH diffuse doesn't use scenemanager's envMapScale so I scaled them manually.

BTW: The LUT filename brtfLutDfg.dds should be brdfLutDfg.dds?

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Re: HLMS PBR BRDF

Post by xrgo »

Hi! just tested the latest dynamic cubemap sample with the compute ibl specular pass in my AMD 7850 and it gives me 5 fps =D, this makes me think that this should be show off in the pbs materials samples instead, so the filtering is not happening every frame. Is it easy to filter a loaded (aka not captured) cubemap? if so the sample should be using an hdr cubemap to really take advantage, there must be a cc licensed cubemap out there, anyone has one at hand? I can search.
I believe the only thing missing would be the diffuse (irradiance?) component? and the alpha squared thingy
thanks again for this awesome christmas gift =D

Saludos!

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4496
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 935
Contact:

Re: HLMS PBR BRDF

Post by dark_sylinc »

xrgo wrote:
Tue Dec 24, 2019 12:37 pm
AMD 7850 and it gives me 5 fps =D
It's at really high quality; cmgen takes 10 seconds; so that's a very good difference :lol:
Lower the cubemap resolution and change CompositorPassIblSpecularDef::mSamplesPerIteration from 128 to 32 and framerate becomes much more acceptable; and quality is still really good.

It's not enabled, but the code supports blending, which means less samples per frame, higher framerate; and if everything is steady then at some point high quality is achieved.
Is it easy to filter a loaded (aka not captured) cubemap? if so the sample should be using an hdr cubemap to really take advantage, there must be a cc licensed cubemap out there, anyone has one at hand? I can search.
Use the cmgen procedure for now. Or create a workspace with the ibl_specular pass.

Btw
https://hdrihaven.com/
https://www.textures.com/browse/hdr-spheres/114552
xrgo wrote:
Tue Dec 24, 2019 12:37 pm
I believe the only thing missing would be the diffuse (irradiance?) component? and the alpha squared thingy
FFS don't just assume it's "only" the alpha squared thing. It is a guess from reading the code, I could be wrong. The difference was minor, but someone needs to test what makes the two codes diverge!!!

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Re: HLMS PBR BRDF

Post by xrgo »

dark_sylinc wrote:
Tue Dec 24, 2019 7:52 pm
It's at really high quality; cmgen takes 10 seconds; so that's a very good difference
yes! its very good indeed in comparison, in fact its not really a problem for me since I use static probes, so I prefer high quality, I was just saying that the decision to showcase this new feature using the dynamic cubemap sample might be bad, new users can think Ogre's performance is bad :P
dark_sylinc wrote:
Tue Dec 24, 2019 7:52 pm
FFS don't just assume it's "only" the alpha squared thing. It is a guess from reading the code, I could be wrong. The difference was minor, but someone needs to test what makes the two codes diverge!!!
Sorry I was trying to say that for to this thread to be resolved those were the remaining topics

in that regard, to continue my investigation:
as I mentioned before the only visual difference between the default brdf (with sqR = sqR*sqR;) and filament's one.. is that ther's a slight difference in color, the default is a bit darker in the diffuse component, see gif:

Image
and the difference comes from the energyFactor, if I force that to 1 it looks exactly the same

plus the specular blob in both (default with sqR*sqR and filament) looks very very similar than blender and ue4 (can't test substance since it doesn't allow adding lights) as I showed in the screenshots in previous posts

thanks!

PS: merry Christmas everyone!!

rujialiu
Goblin
Posts: 292
Joined: Mon May 09, 2016 8:21 am
x 35

Re: HLMS PBR BRDF

Post by rujialiu »

xrgo wrote:
Wed Dec 25, 2019 12:39 am
in that regard, to continue my investigation:
as I mentioned before the only visual difference between the default brdf (with sqR = sqR*sqR;) and filament's one.. is that ther's a slight difference in color, the default is a bit darker in the diffuse component, see gif:

Image
and the difference comes from the energyFactor, if I force that to 1 it looks exactly the same

plus the specular blob in both (default with sqR*sqR and filament) looks very very similar than blender and ue4 (can't test substance since it doesn't allow adding lights) as I showed in the screenshots in previous posts

thanks!

PS: merry Christmas everyone!!
Merry Christmas!
According filament's doc section 4.5, filament is using lambertian diffuse "Given our constraints we decided that the extra runtime cost does not justify the slight increase in quality." so if you're comparing Ogre's default BRDF, which uses Disney diffuse, they won't match 8-)
And I'm quite surprised by the fact "Forcing energyFactor => looks exactly the same" because looking at the shader, I don't think it'll be the same even if you do that.

Note that the shader codes in filament's document section 4.5, which is Disney diffuse, is still not the same as Ogre's (I believe it's following Frostbite's PBR lecture notes, which added the energyFactor on top of what filament described in the document).

So could you change Ogre's default (with sqR = sqR*sqr) to lambertian diffuse and compare again?

User avatar
TaaTT4
OGRE Contributor
OGRE Contributor
Posts: 241
Joined: Wed Apr 23, 2014 3:49 pm
x 45

Re: HLMS PBR BRDF

Post by TaaTT4 »

Happy new year folks!
After a bit of vacation, I'm trying to catch up the updates. I've seen @dark_sylinc work (kudos and thanks, as always) and indeed I've already started to integrate it in my rendering pipeline. For what I've understood (seeing @xrgo screenshots), the visual appearence is now pretty similar to the other engines.
The only remaining question to "solve" is how to treat the sqR factor, right?
Senior game programmer at Vae Victis
Working on Racecraft

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4496
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 935
Contact:

Re: HLMS PBR BRDF

Post by dark_sylinc »

TaaTT4 wrote:
Wed Jan 08, 2020 6:51 pm
Happy new year folks!
After a bit of vacation, I'm trying to catch up the updates. I've seen @dark_sylinc work (kudos and thanks, as always) and indeed I've already started to integrate it in my rendering pipeline. For what I've understood (seeing @xrgo screenshots), the visual appearence is now pretty similar to the other engines.
The only remaining question to "solve" is how to treat the sqR factor, right?
I'm fixing a few issues to integrate the new ibl_specular pass into PCC.

If anyone is into a rush to use the v2-2-irradiance-field branch, a major issue that will feel like a major bug is that 'mMaxSpecIblMipmap' is not seeing the max mipmap value from PCC (hence mMaxSpecIblMipmap will default to 1 so no roughness value above 0 will work with PCC).
I already have made that change in my computer but I can't push yet (I'm integrating ibl_specular to PCC).

If you want the old behavior, hardcode mMaxSpecIblMipmap to 11.0f until I push the fix.
TaaTT4 wrote:
Wed Jan 08, 2020 6:51 pm
The only remaining question to "solve" is how to treat the sqR factor, right?
It's not a matter on "how to solve", but rather "sit our asses in the chair, make the change, compare screenshots, ensure everything is as expected, clamp the min roughness (to avoid aliasing and NaNs) and commit"
We currently clamp roughness to 0.02 because otherwise a division by near zero becomes possible in the BRDF (and that can easily turn into either Inf or Nan, and Infs become easily NaN too) and also because even without NaNs, it becomes extremely aliased as the camera moves.

So likely the change will be along the lines of: roughness = max( 0.02, perceptualRoughness * perceptualRoughness );

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4496
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 935
Contact:

Re: HLMS PBR BRDF

Post by dark_sylinc »

ibl_specular was integrated into PCC, however:
  1. Per-pixel PCC fully uses ibl_specular
  2. Per-pixel PCC in DX10 HW is probably broken, honestly I don't think I should bother. These cards are too slow for ibl_specular + per pixel PCC. If someone complains we'll write a version that generates regular copies and transforms the cubemaps to DPM via pixel shaders.
  3. Regular PCC uses ibl_specular if it's manually assigned to a material (like in LocalCubemapsManualProbes)
  4. Regular PCC does not use ibl_specular in auto/blending mode. Making it work in this mode is too hard
Reflections in general could use a refactor, Regular PCC is way too complex unnecessarily (it's easy to see now), but that will be a fight for another day.
Per pixel PCC has the best quality path.

xrgo
OGRE Expert User
OGRE Expert User
Posts: 1147
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 166

Re: HLMS PBR BRDF

Post by xrgo »

great!!
what about the diffuse part, as solarportal mentioned:
SolarPortal wrote:then we rendered an irradiance texture which is a small 32x32 cubemap with no mips for the diffuse IBL and ran a separate compute shader that computes Diffuse Irradiance
apparently is very important...
SolarPortal wrote:to get normal maps in ambience that had little specular
SolarPortal wrote:When i compared the old roughness to the new diffuse irradiance technique, there was a huge difference in look and quality(old uses mips to get the blur which can be quite noticeable on certain environment maps and materials whereas using the compute shader means we have higher mips with blurs which produce a smoother more accurate result) and of course ambient lighting normals that don't rely on the specular reflection to highlight to normals is a big render improvement.
------
dark_sylinc wrote:
Wed Jan 08, 2020 7:17 pm
"sit our asses in the chair, make the change, compare screenshots,
I did that and can confirm that change is needed, also posted proof comparing with blender and ue4, hopefully more people can do the same =)

thank you so much!!
Saludos!

rujialiu
Goblin
Posts: 292
Joined: Mon May 09, 2016 8:21 am
x 35

Re: HLMS PBR BRDF

Post by rujialiu »

dark_sylinc wrote:
Sat Jan 11, 2020 9:55 pm
ibl_specular was integrated into PCC, however:
  1. Per-pixel PCC fully uses ibl_specular
  2. Per-pixel PCC in DX10 HW is probably broken, honestly I don't think I should bother. These cards are too slow for ibl_specular + per pixel PCC. If someone complains we'll write a version that generates regular copies and transforms the cubemaps to DPM via pixel shaders.
  3. Regular PCC uses ibl_specular if it's manually assigned to a material (like in LocalCubemapsManualProbes)
  4. Regular PCC does not use ibl_specular in auto/blending mode. Making it work in this mode is too hard
Reflections in general could use a refactor, Regular PCC is way too complex unnecessarily (it's easy to see now), but that will be a fight for another day.
Per pixel PCC has the best quality path.
I've just updated Ogre but for me, LocalCubemaps sample is not working. (I've only built D3D11 in my CMake so I don't know whether OpenGL RS is working)

First of all, I ran into an assersion failed that complains that the IBL texture doesn't have UAV flag set. After debugging I found this:

Code: Select all

 uint32 ParallaxCorrectedCubemapBase::getIblTargetTextureFlags( PixelFormatGpu pixelFormat ) const
    {
        const RenderSystemCapabilities *caps =
            mSceneManager->getDestinationRenderSystem()->getCapabilities();
        uint32 textureFlags;
        if( caps->hasCapability( RSC_UAV ) ) <---- return false!!!
        {
...
Since Tutorial_DynamicCubemap sample is working on my machine (I even toggled between quality settings), I THINK UAV is supported, so I tried to change it to if (true) then I got a shader compile error:
100000007PixelShader_ps.hlsl(1403,20): error X3004: undeclared identifier 'samplerState5'

Code: Select all

#define brdfLUT ltcMatrix
float2 envBRDF = OGRE_SampleArray2D( brdfLUT, samplerState5,
                                     float2( pixelData.NdotV, 1.0 - pixelData.roughness ), 2 ).xy;
I noticed that only one sampler is defined:

Code: Select all

Texture2DArray<float4> ltcMatrix    : register(t3);
            SamplerState ltcSampler             : register(s3);
I'm running out of time today so I'd like to ask whether other people have the same problem. I've made some custom changes to Ogre so maybe it's my fault. I haven't changed the LocalCubemaps sample so it's using per-pixel PCC (confirmed)

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4496
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 935
Contact:

Re: HLMS PBR BRDF

Post by dark_sylinc »

rujialiu wrote:
Sun Jan 12, 2020 10:33 am
First of all, I ran into an assersion failed that complains that the IBL texture doesn't have UAV flag set. After debugging I found this:

Code: Select all

 uint32 ParallaxCorrectedCubemapBase::getIblTargetTextureFlags( PixelFormatGpu pixelFormat ) const
    {
        const RenderSystemCapabilities *caps =
            mSceneManager->getDestinationRenderSystem()->getCapabilities();
        uint32 textureFlags;
        if( caps->hasCapability( RSC_UAV ) ) <---- return false!!!
        {
...
Fixed! Thanks!
Since Tutorial_DynamicCubemap sample is working on my machine (I even toggled between quality settings), I THINK UAV is supported, so I tried to change it to if (true) then I got a shader compile error:
100000007PixelShader_ps.hlsl(1403,20): error X3004: undeclared identifier 'samplerState5'

Code: Select all

#define brdfLUT ltcMatrix
float2 envBRDF = OGRE_SampleArray2D( brdfLUT, samplerState5,
                                     float2( pixelData.NdotV, 1.0 - pixelData.roughness ), 2 ).xy;
I noticed that only one sampler is defined:

Code: Select all

Texture2DArray<float4> ltcMatrix    : register(t3);
            SamplerState ltcSampler             : register(s3);
Also fixed!
Thanks!
TaaTT4 reported this bug through Skype too, but since I saw everything was working I forgot what exactly was. I forgot to test D3D11.

Cheers
Matias

Post Reply