EEVEE-Next: Port SSS profile to Pre-compute shader

This moves the pre-computation offline and store the pre-computed
table in the binary. The pre-computed tables are quite small and are
not a concern with respect to binary size increase.

This rewrites the precomputation to use manually fitted
approximations for both burley and random walk.
The approximations fix a discrepancy between cycles and EEVEE
SSS translucency look. The absolute maximum error is below 2%.
I believe better results could be achieved with automatic fitting
tools.

Note that Cycles Burley translucency profile has some issues as it
does not give a smooth profile. The profile is biased near the end
of the lower radii. For this reason, the fit was done on a white
diffuse with (1,1,1) radii which does not exhibit this artifact.

Note that while this adds the profile for random walk, it isn't
currently used because the profile type is not yet passed down
the deferred path.

The fitting data can be found attached to this PR.

Pull Request: https://projects.blender.org/blender/blender/pulls/112512
This commit is contained in:
Clément Foucault 2023-09-20 15:17:27 +02:00 committed by Clément Foucault
parent da495765b4
commit e2cef1c713
12 changed files with 423 additions and 125 deletions

@ -50616,4 +50616,290 @@ const float btdf_ggx[16][64][64][1] = {
{0.484816f}, {0.489247f}, {0.493525f}, {0.497667f}, {0.501639f}, {0.505508f}, {0.509225f},
{0.512815f}}}};
const float burley_sss_profile[64][1] = {
{1.000000f}, {0.957576f}, {0.890814f}, {0.813161f}, {0.732056f}, {0.652729f}, {0.578802f},
{0.512565f}, {0.455203f}, {0.407017f}, {0.365151f}, {0.326306f}, {0.291256f}, {0.259690f},
{0.231309f}, {0.205831f}, {0.182989f}, {0.162537f}, {0.144246f}, {0.127905f}, {0.113320f},
{0.100316f}, {0.088730f}, {0.078418f}, {0.069247f}, {0.061096f}, {0.053858f}, {0.047435f},
{0.041740f}, {0.036693f}, {0.032225f}, {0.028272f}, {0.024776f}, {0.021688f}, {0.018961f},
{0.016556f}, {0.014436f}, {0.012569f}, {0.010926f}, {0.009482f}, {0.008213f}, {0.007100f},
{0.006124f}, {0.005270f}, {0.004523f}, {0.003871f}, {0.003302f}, {0.002806f}, {0.002375f},
{0.002002f}, {0.001678f}, {0.001398f}, {0.001156f}, {0.000948f}, {0.000770f}, {0.000617f},
{0.000487f}, {0.000376f}, {0.000283f}, {0.000204f}, {0.000138f}, {0.000083f}, {0.000037f},
{0.000000f}};
const float random_walk_sss_profile[64][1] = {
{1.000000f}, {0.760107f}, {0.611901f}, {0.513783f}, {0.444313f}, {0.392204f}, {0.351327f},
{0.318198f}, {0.290730f}, {0.267583f}, {0.247844f}, {0.230851f}, {0.216102f}, {0.203204f},
{0.191843f}, {0.181761f}, {0.172748f}, {0.164631f}, {0.157263f}, {0.150525f}, {0.144317f},
{0.138554f}, {0.133166f}, {0.128095f}, {0.123292f}, {0.118714f}, {0.114328f}, {0.110104f},
{0.106017f}, {0.102048f}, {0.098178f}, {0.094393f}, {0.090680f}, {0.087030f}, {0.083434f},
{0.079884f}, {0.076376f}, {0.072904f}, {0.069466f}, {0.066058f}, {0.062679f}, {0.059328f},
{0.056006f}, {0.052712f}, {0.049448f}, {0.046216f}, {0.043019f}, {0.039860f}, {0.036744f},
{0.033675f}, {0.030658f}, {0.027700f}, {0.024807f}, {0.021987f}, {0.019248f}, {0.016600f},
{0.014052f}, {0.011614f}, {0.009298f}, {0.007116f}, {0.005081f}, {0.003206f}, {0.001508f},
{0.000000f}};
#ifdef CYCLES_REFERENCE_LUT /* Used for fitting. */
const float cycles_burley_reference_sss_profile[256][3] = {
{1.001349f, 1.005129f, 1.003057f}, {0.996234f, 0.937970f, 0.832274f},
{0.984534f, 0.833079f, 0.636661f}, {0.968951f, 0.729798f, 0.483946f},
{0.951269f, 0.637867f, 0.369217f}, {0.931896f, 0.556278f, 0.280570f},
{0.911943f, 0.485904f, 0.212907f}, {0.890728f, 0.423777f, 0.160349f},
{0.868180f, 0.368947f, 0.119834f}, {0.846582f, 0.321790f, 0.089213f},
{0.823967f, 0.279777f, 0.065628f}, {0.799325f, 0.242143f, 0.047621f},
{0.775499f, 0.209422f, 0.034016f}, {0.750743f, 0.180285f, 0.023687f},
{0.724644f, 0.153768f, 0.015651f}, {0.694837f, 0.128887f, 0.009247f},
{0.649793f, 0.100032f, 0.002824f}, {0.609569f, 0.077227f, 0.000000f},
{0.593871f, 0.066654f, 0.000000f}, {0.577724f, 0.057329f, 0.000000f},
{0.563388f, 0.049366f, 0.000000f}, {0.548080f, 0.042173f, 0.000000f},
{0.533839f, 0.036029f, 0.000000f}, {0.518934f, 0.030586f, 0.000000f},
{0.503859f, 0.025775f, 0.000000f}, {0.488154f, 0.021467f, 0.000000f},
{0.471856f, 0.017675f, 0.000000f}, {0.456286f, 0.014305f, 0.000000f},
{0.440492f, 0.011402f, 0.000000f}, {0.423739f, 0.008708f, 0.000000f},
{0.405961f, 0.006242f, 0.000000f}, {0.383785f, 0.003919f, 0.000000f},
{0.355914f, 0.001515f, 0.000000f}, {0.330087f, 0.000000f, 0.000000f},
{0.322205f, 0.000000f, 0.000000f}, {0.313107f, 0.000000f, 0.000000f},
{0.305684f, 0.000000f, 0.000000f}, {0.298305f, 0.000000f, 0.000000f},
{0.290766f, 0.000000f, 0.000000f}, {0.284501f, 0.000000f, 0.000000f},
{0.277168f, 0.000000f, 0.000000f}, {0.270779f, 0.000000f, 0.000000f},
{0.264595f, 0.000000f, 0.000000f}, {0.257483f, 0.000000f, 0.000000f},
{0.251835f, 0.000000f, 0.000000f}, {0.245278f, 0.000000f, 0.000000f},
{0.238797f, 0.000000f, 0.000000f}, {0.232752f, 0.000000f, 0.000000f},
{0.226898f, 0.000000f, 0.000000f}, {0.221044f, 0.000000f, 0.000000f},
{0.215808f, 0.000000f, 0.000000f}, {0.209979f, 0.000000f, 0.000000f},
{0.205014f, 0.000000f, 0.000000f}, {0.199265f, 0.000000f, 0.000000f},
{0.194127f, 0.000000f, 0.000000f}, {0.189446f, 0.000000f, 0.000000f},
{0.184623f, 0.000000f, 0.000000f}, {0.179929f, 0.000000f, 0.000000f},
{0.175405f, 0.000000f, 0.000000f}, {0.170868f, 0.000000f, 0.000000f},
{0.166011f, 0.000000f, 0.000000f}, {0.161839f, 0.000000f, 0.000000f},
{0.157865f, 0.000000f, 0.000000f}, {0.153985f, 0.000000f, 0.000000f},
{0.149645f, 0.000000f, 0.000000f}, {0.145994f, 0.000000f, 0.000000f},
{0.142004f, 0.000000f, 0.000000f}, {0.138097f, 0.000000f, 0.000000f},
{0.134363f, 0.000000f, 0.000000f}, {0.130533f, 0.000000f, 0.000000f},
{0.127376f, 0.000000f, 0.000000f}, {0.124018f, 0.000000f, 0.000000f},
{0.120724f, 0.000000f, 0.000000f}, {0.117440f, 0.000000f, 0.000000f},
{0.114474f, 0.000000f, 0.000000f}, {0.110925f, 0.000000f, 0.000000f},
{0.107756f, 0.000000f, 0.000000f}, {0.104074f, 0.000000f, 0.000000f},
{0.101206f, 0.000000f, 0.000000f}, {0.098670f, 0.000000f, 0.000000f},
{0.095842f, 0.000000f, 0.000000f}, {0.093562f, 0.000000f, 0.000000f},
{0.090276f, 0.000000f, 0.000000f}, {0.087599f, 0.000000f, 0.000000f},
{0.085057f, 0.000000f, 0.000000f}, {0.082433f, 0.000000f, 0.000000f},
{0.080531f, 0.000000f, 0.000000f}, {0.078609f, 0.000000f, 0.000000f},
{0.076213f, 0.000000f, 0.000000f}, {0.074083f, 0.000000f, 0.000000f},
{0.072166f, 0.000000f, 0.000000f}, {0.069501f, 0.000000f, 0.000000f},
{0.067523f, 0.000000f, 0.000000f}, {0.065427f, 0.000000f, 0.000000f},
{0.063125f, 0.000000f, 0.000000f}, {0.061604f, 0.000000f, 0.000000f},
{0.059982f, 0.000000f, 0.000000f}, {0.058250f, 0.000000f, 0.000000f},
{0.056052f, 0.000000f, 0.000000f}, {0.054623f, 0.000000f, 0.000000f},
{0.053044f, 0.000000f, 0.000000f}, {0.051472f, 0.000000f, 0.000000f},
{0.049807f, 0.000000f, 0.000000f}, {0.048165f, 0.000000f, 0.000000f},
{0.046592f, 0.000000f, 0.000000f}, {0.045360f, 0.000000f, 0.000000f},
{0.044138f, 0.000000f, 0.000000f}, {0.043084f, 0.000000f, 0.000000f},
{0.041529f, 0.000000f, 0.000000f}, {0.040134f, 0.000000f, 0.000000f},
{0.038586f, 0.000000f, 0.000000f}, {0.037457f, 0.000000f, 0.000000f},
{0.036212f, 0.000000f, 0.000000f}, {0.034872f, 0.000000f, 0.000000f},
{0.033882f, 0.000000f, 0.000000f}, {0.032777f, 0.000000f, 0.000000f},
{0.031593f, 0.000000f, 0.000000f}, {0.030589f, 0.000000f, 0.000000f},
{0.029223f, 0.000000f, 0.000000f}, {0.028413f, 0.000000f, 0.000000f},
{0.027221f, 0.000000f, 0.000000f}, {0.026115f, 0.000000f, 0.000000f},
{0.025458f, 0.000000f, 0.000000f}, {0.024576f, 0.000000f, 0.000000f},
{0.023826f, 0.000000f, 0.000000f}, {0.022929f, 0.000000f, 0.000000f},
{0.022254f, 0.000000f, 0.000000f}, {0.021391f, 0.000000f, 0.000000f},
{0.020656f, 0.000000f, 0.000000f}, {0.019991f, 0.000000f, 0.000000f},
{0.019231f, 0.000000f, 0.000000f}, {0.018549f, 0.000000f, 0.000000f},
{0.017666f, 0.000000f, 0.000000f}, {0.017044f, 0.000000f, 0.000000f},
{0.016422f, 0.000000f, 0.000000f}, {0.015765f, 0.000000f, 0.000000f},
{0.015152f, 0.000000f, 0.000000f}, {0.014275f, 0.000000f, 0.000000f},
{0.013667f, 0.000000f, 0.000000f}, {0.012905f, 0.000000f, 0.000000f},
{0.012515f, 0.000000f, 0.000000f}, {0.012135f, 0.000000f, 0.000000f},
{0.011499f, 0.000000f, 0.000000f}, {0.010930f, 0.000000f, 0.000000f},
{0.010361f, 0.000000f, 0.000000f}, {0.009792f, 0.000000f, 0.000000f},
{0.009257f, 0.000000f, 0.000000f}, {0.008541f, 0.000000f, 0.000000f},
{0.008039f, 0.000000f, 0.000000f}, {0.007511f, 0.000000f, 0.000000f},
{0.007045f, 0.000000f, 0.000000f}, {0.006428f, 0.000000f, 0.000000f},
{0.005688f, 0.000000f, 0.000000f}, {0.005073f, 0.000000f, 0.000000f},
{0.004643f, 0.000000f, 0.000000f}, {0.004030f, 0.000000f, 0.000000f},
{0.003692f, 0.000000f, 0.000000f}, {0.003418f, 0.000000f, 0.000000f},
{0.002779f, 0.000000f, 0.000000f}, {0.002202f, 0.000000f, 0.000000f},
{0.001355f, 0.000000f, 0.000000f}, {0.000631f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f}};
const float cycles_random_walk_reference_sss_profile[256][3] = {
{0.998589f, 0.998557f, 0.998620f}, {0.915669f, 0.707256f, 0.558430f},
{0.850023f, 0.556568f, 0.395164f}, {0.794334f, 0.460739f, 0.304475f},
{0.746514f, 0.392311f, 0.248659f}, {0.704975f, 0.341595f, 0.211408f},
{0.669223f, 0.302535f, 0.183040f}, {0.636678f, 0.272048f, 0.161929f},
{0.605708f, 0.247362f, 0.145065f}, {0.579075f, 0.226898f, 0.130431f},
{0.554892f, 0.209521f, 0.118052f}, {0.531778f, 0.194031f, 0.108264f},
{0.511444f, 0.181311f, 0.099382f}, {0.492432f, 0.170533f, 0.091852f},
{0.474961f, 0.160716f, 0.083810f}, {0.458917f, 0.151794f, 0.076523f},
{0.443574f, 0.143627f, 0.068829f}, {0.429108f, 0.136497f, 0.062427f},
{0.415735f, 0.129236f, 0.056356f}, {0.403294f, 0.123633f, 0.050555f},
{0.391345f, 0.117985f, 0.045086f}, {0.380587f, 0.112950f, 0.040050f},
{0.370766f, 0.108091f, 0.035180f}, {0.360591f, 0.103149f, 0.030221f},
{0.351328f, 0.098884f, 0.026461f}, {0.342819f, 0.094375f, 0.023097f},
{0.334290f, 0.090286f, 0.019406f}, {0.326302f, 0.086282f, 0.016382f},
{0.318789f, 0.082196f, 0.013610f}, {0.311554f, 0.078111f, 0.011696f},
{0.304418f, 0.074763f, 0.009818f}, {0.297789f, 0.071177f, 0.008059f},
{0.291398f, 0.067713f, 0.006669f}, {0.284717f, 0.064418f, 0.005455f},
{0.279107f, 0.060826f, 0.004499f}, {0.273939f, 0.057600f, 0.003608f},
{0.268261f, 0.054409f, 0.002991f}, {0.263058f, 0.051668f, 0.002612f},
{0.258612f, 0.049441f, 0.002191f}, {0.253361f, 0.046681f, 0.001783f},
{0.248583f, 0.043406f, 0.001415f}, {0.244151f, 0.040832f, 0.001145f},
{0.239688f, 0.038572f, 0.000965f}, {0.235360f, 0.036236f, 0.000771f},
{0.231062f, 0.033796f, 0.000604f}, {0.226948f, 0.031833f, 0.000483f},
{0.222936f, 0.029632f, 0.000377f}, {0.219348f, 0.027854f, 0.000371f},
{0.216285f, 0.025880f, 0.000210f}, {0.212846f, 0.024203f, 0.000165f},
{0.209798f, 0.022357f, 0.000121f}, {0.207216f, 0.020772f, 0.000144f},
{0.204138f, 0.018929f, 0.000091f}, {0.201391f, 0.017868f, 0.000076f},
{0.198583f, 0.016490f, 0.000046f}, {0.195519f, 0.015242f, 0.000016f},
{0.192952f, 0.014055f, 0.000016f}, {0.190503f, 0.012530f, 0.000054f},
{0.187560f, 0.011652f, 0.000016f}, {0.184811f, 0.010695f, 0.000038f},
{0.181494f, 0.009551f, 0.000038f}, {0.178895f, 0.008694f, 0.000038f},
{0.176584f, 0.007979f, 0.000000f}, {0.174711f, 0.007353f, 0.000038f},
{0.172580f, 0.006561f, 0.000000f}, {0.170692f, 0.005895f, 0.000000f},
{0.168351f, 0.005279f, 0.000000f}, {0.165891f, 0.004679f, 0.000038f},
{0.163747f, 0.004216f, 0.000038f}, {0.161710f, 0.003726f, 0.000000f},
{0.159570f, 0.003386f, 0.000038f}, {0.157822f, 0.002994f, 0.000038f},
{0.156176f, 0.002691f, 0.000038f}, {0.154411f, 0.002341f, 0.000038f},
{0.152678f, 0.002006f, 0.000038f}, {0.151122f, 0.001923f, 0.000000f},
{0.148831f, 0.001732f, 0.000038f}, {0.147277f, 0.001573f, 0.000000f},
{0.146147f, 0.001413f, 0.000038f}, {0.144642f, 0.001278f, 0.000038f},
{0.143287f, 0.001218f, 0.000038f}, {0.141765f, 0.001091f, 0.000000f},
{0.140889f, 0.000953f, 0.000000f}, {0.139290f, 0.000756f, 0.000000f},
{0.138189f, 0.000688f, 0.000038f}, {0.136729f, 0.000580f, 0.000038f},
{0.135104f, 0.000450f, 0.000000f}, {0.133794f, 0.000412f, 0.000038f},
{0.132695f, 0.000349f, 0.000038f}, {0.131162f, 0.000296f, 0.000000f},
{0.129554f, 0.000303f, 0.000038f}, {0.128187f, 0.000234f, 0.000000f},
{0.126865f, 0.000209f, 0.000038f}, {0.125874f, 0.000188f, 0.000000f},
{0.124408f, 0.000194f, 0.000038f}, {0.123253f, 0.000157f, 0.000000f},
{0.122158f, 0.000141f, 0.000000f}, {0.120646f, 0.000141f, 0.000000f},
{0.119765f, 0.000048f, 0.000000f}, {0.118912f, 0.000054f, 0.000038f},
{0.117264f, 0.000022f, 0.000038f}, {0.116459f, 0.000016f, 0.000000f},
{0.115503f, 0.000016f, 0.000000f}, {0.114394f, 0.000000f, 0.000000f},
{0.113467f, 0.000000f, 0.000000f}, {0.112297f, 0.000006f, 0.000039f},
{0.111491f, 0.000000f, 0.000000f}, {0.110609f, 0.000006f, 0.000039f},
{0.109727f, 0.000000f, 0.000000f}, {0.108768f, 0.000000f, 0.000000f},
{0.107718f, 0.000000f, 0.000000f}, {0.106835f, 0.000006f, 0.000039f},
{0.105800f, 0.000000f, 0.000000f}, {0.104871f, 0.000000f, 0.000000f},
{0.103805f, 0.000006f, 0.000039f}, {0.102997f, 0.000000f, 0.000000f},
{0.101992f, 0.000000f, 0.000000f}, {0.101124f, 0.000006f, 0.000039f},
{0.100254f, 0.000000f, 0.000000f}, {0.099369f, 0.000006f, 0.000039f},
{0.098484f, 0.000006f, 0.000039f}, {0.097720f, 0.000000f, 0.000000f},
{0.096804f, 0.000000f, 0.000000f}, {0.095767f, 0.000006f, 0.000039f},
{0.095003f, 0.000000f, 0.000000f}, {0.094072f, 0.000000f, 0.000000f},
{0.093048f, 0.000000f, 0.000000f}, {0.092329f, 0.000000f, 0.000000f},
{0.091458f, 0.000006f, 0.000039f}, {0.090677f, 0.000006f, 0.000039f},
{0.090049f, 0.000006f, 0.000039f}, {0.089344f, 0.000006f, 0.000039f},
{0.088503f, 0.000006f, 0.000039f}, {0.087950f, 0.000000f, 0.000000f},
{0.087260f, 0.000006f, 0.000039f}, {0.086524f, 0.000006f, 0.000039f},
{0.085636f, 0.000006f, 0.000039f}, {0.084870f, 0.000000f, 0.000000f},
{0.084073f, 0.000006f, 0.000039f}, {0.083352f, 0.000006f, 0.000039f},
{0.082401f, 0.000006f, 0.000039f}, {0.081512f, 0.000006f, 0.000039f},
{0.080668f, 0.000000f, 0.000000f}, {0.079687f, 0.000000f, 0.000000f},
{0.078935f, 0.000000f, 0.000000f}, {0.078273f, 0.000000f, 0.000000f},
{0.077718f, 0.000006f, 0.000039f}, {0.077240f, 0.000006f, 0.000039f},
{0.076486f, 0.000006f, 0.000039f}, {0.075596f, 0.000006f, 0.000039f},
{0.074949f, 0.000006f, 0.000039f}, {0.074179f, 0.000006f, 0.000039f},
{0.073349f, 0.000000f, 0.000000f}, {0.072625f, 0.000006f, 0.000039f},
{0.071978f, 0.000000f, 0.000000f}, {0.071177f, 0.000000f, 0.000000f},
{0.070499f, 0.000000f, 0.000000f}, {0.069774f, 0.000000f, 0.000000f},
{0.069156f, 0.000006f, 0.000039f}, {0.068493f, 0.000000f, 0.000000f},
{0.068012f, 0.000000f, 0.000000f}, {0.067303f, 0.000006f, 0.000039f},
{0.066547f, 0.000000f, 0.000000f}, {0.065745f, 0.000000f, 0.000000f},
{0.065097f, 0.000006f, 0.000039f}, {0.064371f, 0.000000f, 0.000000f},
{0.063813f, 0.000000f, 0.000000f}, {0.063179f, 0.000006f, 0.000039f},
{0.062346f, 0.000006f, 0.000039f}, {0.061636f, 0.000006f, 0.000039f},
{0.060970f, 0.000000f, 0.000000f}, {0.060244f, 0.000006f, 0.000039f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f},
{0.000000f, 0.000000f, 0.000000f}, {0.000000f, 0.000000f, 0.000000f}};
#endif
} // namespace blender::eevee::lut

@ -26,5 +26,16 @@ extern const float bsdf_ggx[16][64][64][3];
extern const float btdf_ggx[16][64][64][1];
/* 4 different blue noise, one per channel. */
extern const float blue_noise[64][64][4];
/* Precomputed translucency profile of a slab of material with varying thickness. */
extern const float burley_sss_profile[64][1];
/* Precomputed translucency profile of a slab of material with varying thickness. */
extern const float random_walk_sss_profile[64][1];
#ifdef CYCLES_REFERENCE_LUT
/* Precomputed translucency profile of a slab of material with varying thickness. */
extern const float cycles_burley_reference_sss_profile[256][3];
/* Precomputed translucency profile of a slab of material with varying thickness. */
extern const float cycles_random_walk_reference_sss_profile[256][3];
#endif
} // namespace blender::eevee::lut

@ -382,15 +382,16 @@ class UtilityTexture : public Texture {
}
{
Layer &layer = data[UTIL_SSS_TRANSMITTANCE_PROFILE_LAYER];
const Vector<float> &transmittance_profile = SubsurfaceModule::transmittance_profile();
BLI_assert(transmittance_profile.size() == lut_size);
/* Repeatedly stored on every row for correct interpolation. */
for (auto y : IndexRange(lut_size)) {
for (auto x : IndexRange(lut_size)) {
/* Only the first channel is used. */
layer.data[y][x] = float4(transmittance_profile[x]);
/* Repeatedly stored on every row for correct interpolation. */
layer.data[y][x][0] = lut::burley_sss_profile[x][0];
layer.data[y][x][1] = lut::random_walk_sss_profile[x][0];
layer.data[y][x][2] = 0.0f;
layer.data[y][x][UTIL_DISK_INTEGRAL_COMP] = lut::ltc_disk_integral[y][x][0];
}
}
BLI_assert(UTIL_SSS_TRANSMITTANCE_PROFILE_LAYER == UTIL_DISK_INTEGRAL_LAYER);
}
{
Layer &layer = data[UTIL_LTC_MAT_LAYER];
@ -408,14 +409,6 @@ class UtilityTexture : public Texture {
}
BLI_assert(UTIL_LTC_MAG_LAYER == UTIL_BSDF_LAYER);
}
{
Layer &layer = data[UTIL_DISK_INTEGRAL_LAYER];
for (auto x : IndexRange(lut_size)) {
for (auto y : IndexRange(lut_size)) {
layer.data[y][x][UTIL_DISK_INTEGRAL_COMP] = lut::ltc_disk_integral[y][x][0];
}
}
}
{
for (auto layer_id : IndexRange(16)) {
Layer &layer = data[UTIL_BTDF_LAYER + layer_id];

@ -105,7 +105,7 @@ class Precompute {
std::ofstream file;
file.open(std::string(name) + ".hh");
file << "const VecBase<float, " << VecT::type_length << "> " << name;
file << "const float " << name;
if (n_w > 1) {
file << "[" << n_w << "]";
}
@ -118,6 +118,7 @@ class Precompute {
if (n_x > 1) {
file << "[" << n_x << "]";
}
file << "[" << VecT::type_length << "]";
file << " = {\n";
/* Print data formatted as C++ array. */
for (auto w : IndexRange(n_w)) {

@ -90,6 +90,8 @@ enum PrecomputeType : uint32_t {
LUT_GGX_BRDF_SPLIT_SUM = 0u,
LUT_GGX_BTDF_IOR_GT_ONE = 1u,
LUT_GGX_BSDF_SPLIT_SUM = 2u,
LUT_BURLEY_SSS_PROFILE = 3u,
LUT_RANDOM_WALK_SSS_PROFILE = 4u,
};
/** \} */
@ -1199,7 +1201,7 @@ BLI_STATIC_ASSERT_ALIGN(AOData, 16)
#define SSS_BURLEY_TRUNCATE 16.0
#define SSS_BURLEY_TRUNCATE_CDF 0.9963790093708328
#define SSS_TRANSMIT_LUT_SIZE 64.0
#define SSS_TRANSMIT_LUT_RADIUS 1.218
#define SSS_TRANSMIT_LUT_RADIUS 2.0
#define SSS_TRANSMIT_LUT_SCALE ((SSS_TRANSMIT_LUT_SIZE - 1.0) / float(SSS_TRANSMIT_LUT_SIZE))
#define SSS_TRANSMIT_LUT_BIAS (0.5 / float(SSS_TRANSMIT_LUT_SIZE))
#define SSS_TRANSMIT_LUT_STEP_RES 64.0
@ -1217,6 +1219,37 @@ struct SubsurfaceData {
};
BLI_STATIC_ASSERT_ALIGN(SubsurfaceData, 16)
static inline float3 burley_setup(float3 radius, float3 albedo)
{
/* TODO(fclem): Avoid constant duplication. */
const float m_1_pi = 0.318309886183790671538;
float3 A = albedo;
/* Diffuse surface transmission, equation (6). */
float3 s = 1.9 - A + 3.5 * ((A - 0.8) * (A - 0.8));
/* Mean free path length adapted to fit ancient Cubic and Gaussian models. */
float3 l = 0.25 * m_1_pi * radius;
return l / s;
}
static inline float3 burley_eval(float3 d, float r)
{
/* Slide 33. */
float3 exp_r_3_d;
/* TODO(fclem): Vectorize. */
exp_r_3_d.x = expf(-r / (3.0 * d.x));
exp_r_3_d.y = expf(-r / (3.0 * d.y));
exp_r_3_d.z = expf(-r / (3.0 * d.z));
float3 exp_r_d = exp_r_3_d * exp_r_3_d * exp_r_3_d;
/* NOTE:
* - Surface albedo is applied at the end.
* - This is normalized diffuse model, so the equation is multiplied
* by 2*pi, which also matches `cdf()`.
*/
return (exp_r_d + exp_r_3_d) / (4.0 * d);
}
/** \} */
/* -------------------------------------------------------------------- */
@ -1294,7 +1327,7 @@ BLI_STATIC_ASSERT_ALIGN(UniformData, 16)
#define UTIL_LTC_MAG_LAYER 3
#define UTIL_BSDF_LAYER 3
#define UTIL_BTDF_LAYER 5
#define UTIL_DISK_INTEGRAL_LAYER 4
#define UTIL_DISK_INTEGRAL_LAYER UTIL_SSS_TRANSMITTANCE_PROFILE_LAYER
#define UTIL_DISK_INTEGRAL_COMP 3
/* __cplusplus is true when compiling with MSL, so include if inside a shader. */

@ -59,7 +59,7 @@ void SubsurfaceModule::render(View &view, Framebuffer &fb, Texture &diffuse_ligh
void SubsurfaceModule::precompute_samples_location()
{
/* Precompute sample position with white albedo. */
float d = burley_setup(1.0f, 1.0f);
float d = burley_setup(float3(1.0f), float3(1.0f)).x;
float rand_u = inst_.sampling.rng_get(SAMPLING_SSS_U);
float rand_v = inst_.sampling.rng_get(SAMPLING_SSS_V);
@ -69,7 +69,7 @@ void SubsurfaceModule::precompute_samples_location()
float theta = golden_angle * i + M_PI * 2.0f * rand_u;
/* Scale using rand_v in order to keep first sample always at center. */
float x = (1.0f + (rand_v / data_.sample_len)) * (i / float(data_.sample_len));
float r = burley_sample(d, x);
float r = SubsurfaceModule::burley_sample(d, x);
data_.samples[i].x = cosf(theta) * r;
data_.samples[i].y = sinf(theta) * r;
data_.samples[i].z = 1.0f / burley_pdf(d, r);
@ -78,65 +78,6 @@ void SubsurfaceModule::precompute_samples_location()
inst_.push_uniform_data();
}
const Vector<float> &SubsurfaceModule::transmittance_profile()
{
static Vector<float> profile;
if (!profile.is_empty()) {
return profile;
}
profile.resize(SSS_TRANSMIT_LUT_SIZE);
/* Precompute sample position with white albedo. */
float radius = 1.0f;
float d = burley_setup(radius, 1.0f);
/* For each distance d we compute the radiance incoming from an hypothetical parallel plane. */
for (auto i : IndexRange(SSS_TRANSMIT_LUT_SIZE)) {
/* Distance from the lit surface plane.
* Compute to a larger maximum distance to have a smoother falloff for all channels. */
float lut_radius = SSS_TRANSMIT_LUT_RADIUS * radius;
float distance = lut_radius * (i + 1e-5f) / profile.size();
/* Compute radius of the footprint on the hypothetical plane. */
float r_fp = sqrtf(square_f(lut_radius) - square_f(distance));
profile[i] = 0.0f;
float area_accum = 0.0f;
for (auto j : IndexRange(SSS_TRANSMIT_LUT_STEP_RES)) {
/* Compute distance to the "shading" point through the medium. */
float r = (r_fp * (j + 0.5f)) / SSS_TRANSMIT_LUT_STEP_RES;
float r_prev = (r_fp * (j + 0.0f)) / SSS_TRANSMIT_LUT_STEP_RES;
float r_next = (r_fp * (j + 1.0f)) / SSS_TRANSMIT_LUT_STEP_RES;
r = hypotf(r, distance);
float R = burley_eval(d, r);
/* Since the profile and configuration are radially symmetrical we
* can just evaluate it once and weight it accordingly */
float disk_area = square_f(r_next) - square_f(r_prev);
profile[i] += R * disk_area;
area_accum += disk_area;
}
/* Normalize over the disk. */
profile[i] /= area_accum;
}
/** NOTE: There's something very wrong here.
* This should be a small remap,
* but current profile range goes from 0.0399098 to 0.0026898. */
/* Make a smooth gradient from 1 to 0. */
float range = profile.first() - profile.last();
float offset = profile.last();
for (float &value : profile) {
value = (value - offset) / range;
/** HACK: Remap the curve to better fit Cycles values. */
value = std::pow(value, 1.6f);
}
profile.first() = 1;
profile.last() = 0;
return profile;
}
/** \} */
/* -------------------------------------------------------------------- */
@ -147,17 +88,6 @@ const Vector<float> &SubsurfaceModule::transmittance_profile()
* https://graphics.pixar.com/library/ApproxBSSRDF/approxbssrdfslides.pdf
* \{ */
float SubsurfaceModule::burley_setup(float radius, float albedo)
{
float A = albedo;
/* Diffuse surface transmission, equation (6). */
float s = 1.9f - A + 3.5f * square_f(A - 0.8f);
/* Mean free path length adapted to fit ancient Cubic and Gaussian models. */
float l = 0.25 * M_1_PI * radius;
return l / s;
}
float SubsurfaceModule::burley_sample(float d, float x_rand)
{
x_rand *= SSS_BURLEY_TRUNCATE_CDF;

@ -49,9 +49,6 @@ struct SubsurfaceModule {
~SubsurfaceModule(){};
/** Contains translucence profile for a single color channel. */
static const Vector<float> &transmittance_profile();
void end_sync();
void render(View &view, Framebuffer &fb, Texture &diffuse_light_tx);
@ -60,7 +57,6 @@ struct SubsurfaceModule {
void precompute_samples_location();
/** Christensen-Burley implementation. */
static float burley_setup(float radius, float albedo);
static float burley_sample(float d, float x_rand);
static float burley_eval(float d, float r);
static float burley_pdf(float d, float r);

@ -170,6 +170,53 @@ vec4 ggx_btdf_gt_one(vec3 lut_coord)
return vec4(transmission_factor, 0.0, 0.0, 0.0);
}
/* Generate SSS translucency profile.
* We precompute the exit radiance for a slab of homogenous material backface-lit by a directional
* light. We only integrate for a single color primary since the profile will be applied to each
* primary independantly.
* For each distance `d` we compute the radiance incoming from an hypothetical parallel plane. */
vec4 burley_sss_translucency(vec3 lut_coord)
{
/* Note that we only store the 1st (radius == 1) component.
* The others are here for debugging overall appearance. */
vec3 radii = vec3(1.0, 0.2, 0.1);
float thickness = lut_coord.x * SSS_TRANSMIT_LUT_RADIUS;
vec3 r = thickness / radii;
/* Manual fit based on cycles render of a backlit slab of varying thickness.
* Mean Error: 0.003
* Max Error: 0.015 */
vec3 exponential = exp(-3.6 * pow(r, vec3(1.11)));
vec3 gaussian = exp(-pow(3.4 * r, vec3(1.6)));
vec3 fac = square(saturate(0.5 + r / 0.6));
vec3 profile = saturate(mix(gaussian, exponential, fac));
/* Mask off the end progressively to 0. */
profile *= saturate(1.0 - pow5f(lut_coord.x));
return vec4(profile, 0.0);
}
vec4 random_walk_sss_translucency(vec3 lut_coord)
{
/* Note that we only store the 1st (radius == 1) component.
* The others are here for debugging overall appearance. */
vec3 radii = vec3(1.0, 0.2, 0.1);
float thickness = lut_coord.x * SSS_TRANSMIT_LUT_RADIUS;
vec3 r = thickness / radii;
/* Manual fit based on cycles render of a backlit slab of varying thickness.
* Mean Error: 0.003
* Max Error: 0.016 */
vec3 scale = vec3(0.31, 0.47, 0.32);
vec3 exponent = vec3(-22.0, -5.8, -0.5);
vec3 profile = vec3(dot(scale, exp(exponent * r.r)),
dot(scale, exp(exponent * r.g)),
dot(scale, exp(exponent * r.b)));
profile = saturate(profile - 0.1);
/* Mask off the end progressively to 0. */
profile *= saturate(1.0 - pow5f(lut_coord.x));
return vec4(profile, 0.0);
}
void main()
{
/* Make sure coordinates are covering the whole [0..1] range at texel center. */
@ -186,6 +233,12 @@ void main()
case LUT_GGX_BSDF_SPLIT_SUM:
result = ggx_bsdf_split_sum(lut_normalized_coordinate);
break;
case LUT_BURLEY_SSS_PROFILE:
result = burley_sss_translucency(lut_normalized_coordinate);
break;
case LUT_RANDOM_WALK_SSS_PROFILE:
result = random_walk_sss_translucency(lut_normalized_coordinate);
break;
}
imageStore(table_img, ivec3(gl_GlobalInvocationID), result);
}

@ -124,10 +124,21 @@ vec3 sample_cylinder(vec2 rand)
vec3 sample_sphere(vec2 rand)
{
float omega = rand.y * 2.0 * M_PI;
float cos_theta = rand.x * 2.0 - 1.0;
float sin_theta = safe_sqrt(1.0 - cos_theta * cos_theta);
return vec3(sin_theta * vec2(cos(omega), sin(omega)), cos_theta);
return vec3(sin_theta * sample_circle(rand.y), cos_theta);
}
/**
* Uniform hemisphere distribution.
* \a rand is 2 random float in the [0..1] range.
* Returns point on a Z positive hemisphere of radius 1 and centered on the origin.
*/
vec3 sample_hemisphere(vec2 rand)
{
float cos_theta = rand.x;
float sin_theta = safe_sqrt(1.0 - sqr(cos_theta));
return vec3(sin_theta * sample_circle(rand.y), cos_theta);
}
/** \} */

@ -20,31 +20,6 @@
#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl)
vec3 burley_setup(vec3 radius, vec3 albedo)
{
/* Scale albedo because we can have HDR value caused by BSDF sampling. */
vec3 A = albedo / max(1e-6, max_v3(albedo));
/* Diffuse surface transmission, equation (6). */
vec3 s = 1.9 - A + 3.5 * sqr(A - 0.8);
/* Mean free path length adapted to fit ancient Cubic and Gaussian models. */
vec3 l = 0.25 * M_1_PI * radius;
return l / s;
}
vec3 burley_eval(vec3 d, float r)
{
/* Slide 33. */
vec3 exp_r_3_d = exp(-r / (3.0 * d));
vec3 exp_r_d = exp_r_3_d * exp_r_3_d * exp_r_3_d;
/* NOTE:
* - Surface albedo is applied at the end.
* - This is normalized diffuse model, so the equation is multiplied
* by 2*pi, which also matches `cdf()`.
*/
return (exp_r_d + exp_r_3_d) / (4.0 * d);
}
void main(void)
{
vec2 center_uv = uvcoordsvar.xy;
@ -82,7 +57,9 @@ void main(void)
}
diffuse.sss_radius = max(vec3(1e-4), diffuse.sss_radius / max_radius) * max_radius;
vec3 d = burley_setup(diffuse.sss_radius, diffuse.color);
/* Scale albedo because we can have HDR value caused by BSDF sampling. */
vec3 albedo = diffuse.color / max(1e-6, max_v3(diffuse.color));
vec3 d = burley_setup(diffuse.sss_radius, albedo);
/* Do not rotate too much to avoid too much cache misses. */
float golden_angle = M_PI * (3.0 - sqrt(5.0));

@ -20,7 +20,7 @@
void main()
{
int surfel_index = int(gl_GlobalInvocationID.x);
if (surfel_index >= capture_info_buf.surfel_len) {
if (surfel_index >= int(capture_info_buf.surfel_len)) {
return;
}
@ -32,5 +32,5 @@ void main()
surfel_buf[surfel_index].ray_distance = ray_distance;
/* NOTE: We only need to init the `list_start_buf` to -1 for the whole list to be valid since
* every surfel will load its `next` value from the list head. */
surfel_buf[surfel_index].next = atomicExchange(list_start_buf[list_index], surfel_index);
// surfel_buf[surfel_index].next = atomicExchange(list_start_buf[list_index], surfel_index);
}

@ -1451,14 +1451,21 @@ static void test_eevee_lut_gen()
auto brdf_ggx_gen = Precompute(manager, LUT_GGX_BRDF_SPLIT_SUM, {64, 64, 1}).data<float2>();
auto btdf_ggx_gen = Precompute(manager, LUT_GGX_BTDF_IOR_GT_ONE, {64, 64, 16}).data<float1>();
auto bsdf_ggx_gen = Precompute(manager, LUT_GGX_BSDF_SPLIT_SUM, {64, 64, 16}).data<float3>();
auto burley_gen = Precompute(manager, LUT_BURLEY_SSS_PROFILE, {64, 1, 1}).data<float1>();
auto rand_walk_gen = Precompute(manager, LUT_RANDOM_WALK_SSS_PROFILE, {64, 1, 1}).data<float1>();
Span<float2> brdf_ggx_lut((const float2 *)&eevee::lut::brdf_ggx, 64 * 64);
Span<float1> btdf_ggx_lut((const float1 *)&eevee::lut::btdf_ggx, 64 * 64 * 16);
Span<float3> bsdf_ggx_lut((const float3 *)&eevee::lut::bsdf_ggx, 64 * 64 * 16);
Span<float1> burley_sss_lut((const float1 *)&eevee::lut::burley_sss_profile, 64);
Span<float1> rand_walk_lut((const float1 *)&eevee::lut::random_walk_sss_profile, 64);
EXPECT_NEAR_ARRAY_ND(brdf_ggx_lut.data(), brdf_ggx_gen.data(), brdf_ggx_gen.size(), 2, 1e-4f);
EXPECT_NEAR_ARRAY_ND(btdf_ggx_lut.data(), btdf_ggx_gen.data(), btdf_ggx_gen.size(), 1, 1e-4f);
EXPECT_NEAR_ARRAY_ND(bsdf_ggx_lut.data(), bsdf_ggx_gen.data(), bsdf_ggx_gen.size(), 3, 1e-4f);
const float eps = 3e-3f;
EXPECT_NEAR_ARRAY_ND(brdf_ggx_lut.data(), brdf_ggx_gen.data(), brdf_ggx_gen.size(), 2, eps);
EXPECT_NEAR_ARRAY_ND(btdf_ggx_lut.data(), btdf_ggx_gen.data(), btdf_ggx_gen.size(), 1, eps);
EXPECT_NEAR_ARRAY_ND(bsdf_ggx_lut.data(), bsdf_ggx_gen.data(), bsdf_ggx_gen.size(), 3, eps);
EXPECT_NEAR_ARRAY_ND(burley_gen.data(), burley_sss_lut.data(), burley_sss_lut.size(), 1, eps);
EXPECT_NEAR_ARRAY_ND(rand_walk_gen.data(), rand_walk_lut.data(), rand_walk_lut.size(), 1, eps);
GPU_render_end();
}