pex-gl / pex-renderer

Physically based renderer (PBR) and scene graph for PEX.
https://pex-gl.github.io/pex-renderer/examples/index.html
MIT License
237 stars 16 forks source link

Reflection map prefiltering improvements #331

Open vorg opened 1 year ago

vorg commented 1 year ago

Current implementation suffers from two major issues: a) due to lack of multiple scattering metals get darker and they get rougher - solved by bumping reflection color based on roughness b) bright spots cause fireflies due to insufficient filtering - solved by sampling different mipmap levels

Both are described here https://bruop.github.io/ibl/

vorg commented 1 year ago

First implementation in a branch is promising.

Before (see dark metals on the right and very pale transition to plastic going down left column)

before

Getting blurry faster, and bright metals. Matches reference from Satin

after

ezgif-3-4f5a327465

vorg commented 1 year ago

The issue of sparkles persists

Screenshot 2022-11-14 at 09 25 50

and could be fixed by adding the following (from here and here) to prefilter-from-oct-map-atlas.frag.js#LL93

 if (NoL > 0.0) {
            // Based off https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch20.html
            // Typically you'd have the following:
            // float pdf = D_GGX(NoH, roughness) * NoH / (4.0 * VoH);
            // but since V = N => VoH == NoH
            float pdf = D_GGX(NoH, roughness) / 4.0 + 0.001;
            // Solid angle of current sample -- bigger for less likely samples
            float omegaS = 1.0 / (float(NUM_SAMPLES) * pdf);
            // Solid angle of texel
            float omegaP = 4.0 * PI / (6.0 * imgSize * imgSize);
            // Mip level is determined by the ratio of our sample's solid angle to a texel's solid angle
            float mipLevel = max(0.5 * log2(omegaS / omegaP), 0.0);
            prefilteredColor += textureCubeLod(s_source, L, mipLevel).rgb * NoL;
            totalWeight += NoL;
        }

but.. the code is for cubemaps... which could be converted to octahedral maps if we find solid angle formula for them and improve mipmapping. So we either implement Improve reflection probes seams #321 or switch to cubemaps that can be seamless and mipmapped in webgl2.

dmnsgn commented 1 year ago

but.. the code is for cubemaps... which could be converted to octahedral maps if we find solid angle formula for them and improve mipmapping. So we either implement Improve reflection probes seams #321 or switch to cubemaps that can be seamless and mipmapped in webgl2.

Would that impact #7 ?

vorg commented 1 year ago

Possibly as having prefiltered cubemap would allow us to convert it to SPH like e.g. BabylonJS does.

vorg commented 1 year ago

If we move to cubemap mipmaps then we could reconsider atlas packing to the following as it would be half the size.

Do85vNyX0AEi9Cw