Skip to content
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

Better roughness remapping for IBLs #1981

Merged
merged 1 commit into from
Dec 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
282 changes: 282 additions & 0 deletions docs/math/IBL Roughness Remapping.nb
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
(* Content-type: application/vnd.wolfram.mathematica *)

(*** Wolfram Notebook File ***)
(* http://www.wolfram.com/nb *)

(* CreatedBy='Mathematica 12.0' *)

(*CacheID: 234*)
(* Internal cache information:
NotebookFileLineBreakTest
NotebookFileLineBreakTest
NotebookDataPosition[ 158, 7]
NotebookDataLength[ 10780, 274]
NotebookOptionsPosition[ 9948, 252]
NotebookOutlinePosition[ 10286, 267]
CellTagsIndexPosition[ 10243, 264]
WindowFrame->Normal*)

(* Beginning of Notebook Content *)
Notebook[{

Cell[CellGroupData[{
Cell[BoxData[{
RowBox[{
RowBox[{"f", "[", "x_", "]"}], ":=",
RowBox[{
RowBox[{
RowBox[{"(",
RowBox[{"2", "/",
RowBox[{"(",
RowBox[{
RowBox[{
RowBox[{"(",
RowBox[{
RowBox[{"2", "/",
RowBox[{"(",
RowBox[{"x", "^", "4"}], ")"}]}], "-", "2"}], ")"}], "/", "4"}],
"+", "2"}], ")"}]}], ")"}], "^",
RowBox[{"(",
RowBox[{"1", "/", "4"}], ")"}]}], "/;",
RowBox[{"x", ">", "0"}]}]}], "\[IndentingNewLine]",
RowBox[{
RowBox[{"f", "[", "x_", "]"}], ":=", " ",
RowBox[{"0", "/;",
RowBox[{"x", "==", "0"}]}]}], "\[IndentingNewLine]",
RowBox[{
RowBox[{"data", " ", ":=", " ",
RowBox[{"Table", "[",
RowBox[{
RowBox[{"{",
RowBox[{"x", ",",
RowBox[{"f", "[", "x", "]"}]}], "}"}], ",",
RowBox[{"{",
RowBox[{"x", ",", " ", "0", ",", "1", ",", "0.01"}], "}"}]}], "]"}]}],
";"}], "\[IndentingNewLine]",
RowBox[{"parabola", " ", "=", " ",
RowBox[{"Normal", "[",
RowBox[{"NonlinearModelFit", "[",
RowBox[{"data", ",", " ",
RowBox[{"{",
RowBox[{
RowBox[{
RowBox[{"a", "*", "x"}], "+",
RowBox[{"b", "*",
RowBox[{"x", "^", "2"}]}]}], ",", " ",
RowBox[{
RowBox[{"a", "+", "b"}], "\[Equal]", "1"}]}], "}"}], ",", " ",
RowBox[{"{",
RowBox[{"a", ",", "b"}], "}"}], ",", " ", "x"}], "]"}],
"]"}]}], "\[IndentingNewLine]",
RowBox[{"Show", "[",
RowBox[{
RowBox[{"ListPlot", "[",
RowBox[{"data", ",",
RowBox[{"PlotStyle", "\[Rule]", "Red"}]}], "]"}], ",",
RowBox[{"Plot", "[",
RowBox[{
RowBox[{"{",
RowBox[{"line", ",", "parabola"}], "}"}], ",",
RowBox[{"{",
RowBox[{"x", ",", "0", ",", "1"}], "}"}]}], "]"}]}],
"]"}], "\[IndentingNewLine]"}], "Input",
CellChangeTimes->{{3.7853013256245613`*^9, 3.785301390186495*^9}, {
3.785301421642477*^9, 3.785301465776168*^9}, {3.7853017515859756`*^9,
3.785301908525689*^9}, {3.7853020327027817`*^9, 3.785302034437195*^9}, {
3.7853020894218187`*^9, 3.785302202204063*^9}, {3.78530224866191*^9,
3.78530224882778*^9}, {3.785302350469426*^9, 3.785302438172524*^9}, {
3.7853025481243563`*^9, 3.785302567825976*^9}, {3.785302633764064*^9,
3.785302690969706*^9}, {3.785302769267284*^9, 3.785302773737165*^9}, {
3.7853028214660187`*^9, 3.7853029304252*^9}, {3.7853030462655373`*^9,
3.785303046432098*^9}, {3.7853031781549597`*^9, 3.785303235566655*^9},
3.785303564600515*^9, {3.785303597702798*^9, 3.78530363051826*^9}, {
3.785303692790189*^9, 3.7853036993481417`*^9}, {3.7853041621306343`*^9,
3.785304162224794*^9}, {3.785304507674033*^9, 3.78530453730317*^9}},
CellLabel->
"In[217]:=",ExpressionUUID->"85027ebf-eb4f-4561-8636-5abaa20a4e91"],

Cell[BoxData[
RowBox[{
RowBox[{"1.6859867495347762`", " ", "x"}], "-",
RowBox[{"0.6859867495347762`", " ",
SuperscriptBox["x", "2"]}]}]], "Output",
CellChangeTimes->{3.785305622578298*^9},
CellLabel->
"Out[220]=",ExpressionUUID->"fed6f178-4c96-4662-aea8-90e31d064e10"],

Cell[BoxData[
GraphicsBox[{{{}, {
{RGBColor[1, 0, 0], PointSize[0.009166666666666668], AbsoluteThickness[
1.6], PointBox[CompressedData["
1:eJxdkntMU3cUx+kUBUGHrIA8ZJHABm5hinMzTvd1i4oMBNtNicIQEabLeEiY
8nBuugCNilAHMlAhQySCCA4DoThAeYkIapFHKfLoi9L37ZQSozhn68n+2Elu
bu7jd873+/2cFTFJ3Li3rKys4l5f5vv/6yi7NlCakYnExXtCzszm4M1zAVh5
153OzF6EwDNLyxGUYqSs2FMtqKDvlxF806b65Ow1nC82VxVeFv3Q7uh2g/6v
xY6HTT5jggboOOY3dTi8Wd1SEt5E5+uRmF7D+nq2GYtE5Yc2LmpE2rmOmYyv
blO/Jmw/3hF5y7UdfpF57SbfZrxXd3Xqb1UH9W8Fzyn0mr2gC5dfnxaV30au
6fklG143zWtD9aLA1PGdPVhjqQ6MTnLTTnj30vxO+LdePKZ+0ocOk+/rCV3w
YfMe2LQ9ID3d8Fj6bdbBQCG4loF3UTxyx9bVv5/09eDG9l0vctiPIM0wN7yH
n35kJ9x8/oj09oG7wPNwoWQAyWZ5h+6DVZXu7XRnkPQ/wAx3wXG/6iG8oSCE
qK4ioytvmPwIEdDbbRSniLDNMqAfA8+PVewKHyF//VD2f/bFyvVimKdF5j2C
Czue+6XHKPkdgGjJq7DTL0dhsSMaAKveqdQ4/pj8DyLET1MQ2TKGd81yPIfw
Suh4SnBhnPIYQr7XujFd2gQOfGeuYfxiCmNJv5mkfEQwOTb0trhIYO7GrhWh
bp/tBk6mhPIagUu114HlRglmze1MI+isSv6dHSGl/MRwHrsn9u2S4nNLw1Ew
/Bd2If4yynMUzQnxuqRCGSzysh4jdXXDyuyXMsp3DAleVunH98txv89cY4jL
dC7dcVdOeY9DL9TwVB8o4GQROIGdEclR63MVlP8EGusKCtcxCljaRU7CJ9fB
ejh0inhIkFY+Z7SumSI/EgQ7C32abZXER4Kcd67M18cqyZ8EgYJzBWdalcRL
Cpu9w2fznafJrxTNuyuOmuKniZ8UQYvL/rjaNk3+ZViz6rRfNVtFPGVwTA71
MsapKA8ZCsQBJ1IaVMRXDkVNwIer5qkpHzk6l38/tyJMTbzlCKi8cGtLsZry
UoAbq/y0WKom/gqsDTnv6u6rofwUKH8Vs7A3XkP7MIVcj4c5Vdc1lOcUhrwj
XARGDe3HFKzlXoZnH2kpXyXmQqN9kxK0tC9KvM2WXvKs0lLeSlxaWjJjJ9fS
/kzDhlcUs8FdR/lPo8l7w0ADR0f7NI2N9iFtP2friIcKdqbL/qVNOuKhwgBH
Ueiu1REPFYpOLpf946YnHirMbvwrfEeQnniood1SeXbZET3xUOPGbyNJ0WV6
4qGGe9NW+9W9euKhwc2Dqdfzn+rBt/DQYF4nv+usm4F4aDB/r8Pgx5sMxEOL
PX++fyg71kA8tBCzOtfyeQbioUVU8uZbEVUG4qEDf/dEyZMeA/HQIZlXy41S
G4iHDhFPU7ZVLmSIhx7WQcx9sTdDPPRIjJI6zG1iiIcekp4y12WRDPEwIHjJ
1u5PjjDEw4CtoZy+6DyGeBjQ6K6oLr3CEA8G+7r3Nz5rZYgHg4lf+fapQwzx
YBBczypYoWWIh/G/+7/CryID
"]]}, {
{RGBColor[1, 0, 0], PointSize[0.009166666666666668], AbsoluteThickness[
1.6]}, {}}, {
{RGBColor[1, 0, 0], PointSize[0.009166666666666668], AbsoluteThickness[
1.6]}, {}}}, {{}, {}}}, {{{}, {}, {},
TagBox[
{RGBColor[0.880722, 0.611041, 0.142051], AbsoluteThickness[1.6],
Opacity[1.], LineBox[CompressedData["
1:eJwVkHk4FHgcxh2TDqXEplF4XB2qVTlaK71ZNqLLtbRuG8rutDr2wW7XuLaN
jCLZCEXnbAaNNqWISbLKHTLNjDGmmTEzP5IkYqc/vs/n+X6f932f9/maRvzq
Hamhpqa2UzVf6BEpaauV+m05UeW0dCo+YgvFxTCWT7XF9qxxm8iRrbApzM2/
S3XF/QV+ZZXDe+D5orviMtUXuzwp+hkkDP77xh+dp+5Dr4yb+aMiFm+s/3Q5
Sz2K5Zs9I9Wlp1D01e7UM9RkPIhOnfQTZII+5+7Kv6jZoGv+U6DRUoSAvVdY
wyMlMPG38+8JKof2DD3IzZgFPQdSeuRCFSy9lJL6NDZmeM6uq57UIu6lA3Lf
V8EmnJHv9okDA7YuT129BlqUMoVFbyPuCV2aWzbXoSO/9obDeDPqYi4v2yvn
oH9xHWtBXCvGVjgtvEN7Bjp/xDjerR0aE8xFyyybMP9g+JSvXSfsZ8Lu+ZSq
fI+7ZU4TXWhOtn3ZYNWCzMlcnwpmN0wyhyZuKVuxNto163hCL4bG+byu9e2I
8dDzCjfpQ4nsYZNORgcqEo6HC3hc6BjdICJRJ4wrbiY5p/OQfqAyqsjiFaza
6kxkcwX4sJUp2n+yGy9D+7fRegU4upHDXlLfA3PaE4PzOf3gl3LS2kxfI5ji
QM6FCDEZ05m3+vc+tMg2vZYZDWCN8+zpqIdcaDoXW4/+NwC3q6bR5QY8GN7U
in2SJEKcUahZfxAfbYmbcxqtBrFW7qfdvVOAY+ynDY5Ng9BbODyH80kArbal
BVGHxaDU5LHM8/uhc2jW7LZ5b/Gz7cPeuZ5ChLUWvdNnvgVze0TR4w9CdNEF
OrEuEowNGS4S5wzgc1pVjcELCSp93DSzXUU4caDoUnKwFCfdUwrZYhECpOfN
n/GlMH3j0VOcMgjmLp1FNoEyfLspOZu6UYwQZfS1H7gyBBm3TKh3iBFrIX3l
t2cIY01nhbH0t4hour3G+vkQcikhR70tJKCVJ3XS7OTQ41Ve1eBI8LHca75T
nhyzjtN9HQ5JIS4svd1NUUDtVghLuFgGeZbZY16EAocvsc4urpMhg7Gkor1e
gUdrTs/RPTiE1HSxnYaxEroeh9cm6sgxQtW6waQpwV3X2pFQLUdGFH3luhol
ygpgIQpRwNzWfahciyCYZa9rNK3AMpFQluxOcCrlCp17W4me4BVqZmkEdyRG
eTo7CNjq86obOQSnL6eE8XYRZBlabqt9SrDPW2FZ6kXwIfBYwr8NBMurq8t2
+hNsDeD3lTQSnGEENqRHEIzaxzH+aCbYb//3yLwEgrp0ZfnSTgKzZH332dcJ
tC9NDugOEEx/c2xB902CDfV5F6ZVe69ioP06k4CrHz8sExFk+t8N3lau6rNh
8EqdmGDGyvtISjVBkte5UZpMpWtjFGh2EKSv3uDNHiG4nzr+U0cXQc/rrIt5
7wiyHUNXF/cQFLM3piaOEnhe+5r9HY+A028RunuM4EH8i+d0qaqXWd+M6CNB
zjo7hpec4KSBCeP5BMEhYb6vKVH9za7w2Z1PBKt2/MKvfa/Kk/nY/jZFQFHv
LMkcJ5ibeHp/wGcCQaVjTJhKN+w88b3jNEF1TLH1etU90Op6s9EMwUUT7bEZ
Fd0cGVNf+D+FDYXk
"]]},
Annotation[#, "Charting`Private`Tag$12958#2"]& ]}, {}}},
AspectRatio->NCache[GoldenRatio^(-1), 0.6180339887498948],
Axes->{True, True},
AxesLabel->{None, None},
AxesOrigin->{0, 0},
DisplayFunction->Identity,
Frame->{{False, False}, {False, False}},
FrameLabel->{{None, None}, {None, None}},
FrameTicks->{{Automatic, Automatic}, {Automatic, Automatic}},
GridLines->{None, None},
GridLinesStyle->Directive[
GrayLevel[0.5, 0.4]],
Method->{
"OptimizePlotMarkers" -> True,
"CoordinatesToolOptions" -> {"DisplayFunction" -> ({
(Identity[#]& )[
Part[#, 1]],
(Identity[#]& )[
Part[#, 2]]}& ), "CopiedValueFunction" -> ({
(Identity[#]& )[
Part[#, 1]],
(Identity[#]& )[
Part[#, 2]]}& )}},
PlotRange->{{0, 1.}, {0, 1.}},
PlotRangeClipping->True,
PlotRangePadding->{{
Scaled[0.02],
Scaled[0.02]}, {
Scaled[0.02],
Scaled[0.05]}},
Ticks->{Automatic, Automatic}]], "Output",
CellChangeTimes->{3.7853056226854563`*^9},
CellLabel->
"Out[221]=",ExpressionUUID->"f0514440-6790-4973-a178-10d605503692"]
}, Open ]],

Cell[CellGroupData[{

Cell[BoxData[
RowBox[{"InverseFunction", "[",
RowBox[{
RowBox[{
RowBox[{"a", "#"}], "+",
RowBox[{"b",
RowBox[{"#", "^", "2"}]}]}], " ", "&"}], "]"}]], "Input",
CellChangeTimes->{{3.785304489279614*^9, 3.785304502255611*^9}, {
3.785304551742334*^9, 3.785304576350375*^9}, {3.7853046419918413`*^9,
3.785304679053865*^9}},
CellLabel->
"In[222]:=",ExpressionUUID->"bfa1e7d7-2b86-4205-af6d-5bf1972b8f75"],

Cell[BoxData[
TemplateBox[{
"InverseFunction","ifun",
"\"Inverse functions are being used. Values may be lost for multivalued \
inverses.\"",2,222,56,28017100375262792097,"Local"},
"MessageTemplate"]], "Message", "MSG",
CellChangeTimes->{3.7853059996502647`*^9},
CellLabel->
"During evaluation of \
In[222]:=",ExpressionUUID->"b67cc035-eea8-40e8-9bf0-7511901cd5d4"],

Cell[BoxData[
RowBox[{
FractionBox[
RowBox[{
RowBox[{"-", "a"}], "-",
SqrtBox[
RowBox[{
SuperscriptBox["a", "2"], "+",
RowBox[{"4", " ", "b", " ", "#1"}]}]]}],
RowBox[{"2", " ", "b"}]], "&"}]], "Output",
CellChangeTimes->{{3.785304568300682*^9, 3.785304577012412*^9}, {
3.785304647755281*^9, 3.785304685707745*^9}, 3.785305999659697*^9},
CellLabel->
"Out[222]=",ExpressionUUID->"c63af4bc-f4df-419e-afb6-b17542ded991"]
}, Open ]]
},
WindowSize->{808, 911},
WindowMargins->{{Automatic, 166}, {47, Automatic}},
FrontEndVersion->"12.0 for Mac OS X x86 (64-bit) (April 8, 2019)",
StyleDefinitions->"Default.nb"
]
(* End of Notebook Content *)

(* Internal cache information *)
(*CellTagsOutline
CellTagsIndex->{}
*)
(*CellTagsIndex
CellTagsIndex->{}
*)
(*NotebookFileOutline
Notebook[{
Cell[CellGroupData[{
Cell[580, 22, 2816, 73, 136, "Input",ExpressionUUID->"85027ebf-eb4f-4561-8636-5abaa20a4e91"],
Cell[3399, 97, 282, 7, 34, "Output",ExpressionUUID->"fed6f178-4c96-4662-aea8-90e31d064e10"],
Cell[3684, 106, 4937, 101, 246, "Output",ExpressionUUID->"f0514440-6790-4973-a178-10d605503692"]
}, Open ]],
Cell[CellGroupData[{
Cell[8658, 212, 430, 11, 30, "Input",ExpressionUUID->"bfa1e7d7-2b86-4205-af6d-5bf1972b8f75"],
Cell[9091, 225, 377, 9, 24, "Message",ExpressionUUID->"b67cc035-eea8-40e8-9bf0-7511901cd5d4"],
Cell[9471, 236, 461, 13, 60, "Output",ExpressionUUID->"c63af4bc-f4df-419e-afb6-b17542ded991"]
}, Open ]]
}
]
*)

12 changes: 8 additions & 4 deletions shaders/src/light_indirect.fs
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,15 @@ vec3 diffuseIrradiance(const vec3 n) {
// IBL specular
//------------------------------------------------------------------------------

float perceptualRoughnessToLod(float perceptualRoughness) {
// See: https://s3.amazonaws.com/docs.knaldtech.com/knald/1.0.0/lys_power_drops.html
// (Pre-convolved Cube Maps vs Path Tracers)
// Below is a quadratic fit to the formula in the article above at NoV=1
return frameUniforms.iblMaxMipLevel.x * perceptualRoughness * (1.686 - 0.686 * perceptualRoughness);
}

vec3 prefilteredRadiance(const vec3 r, float perceptualRoughness) {
// lod = lod_count * sqrt(roughness), which is the mapping used by cmgen
// where roughness = perceptualRoughness^2
// using all the mip levels requires seamless cubemap sampling
float lod = frameUniforms.iblMaxMipLevel.x * perceptualRoughness;
float lod = perceptualRoughnessToLod(perceptualRoughness);
return decodeDataForIBL(textureLod(light_iblSpecular, r, lod));
}

Expand Down
18 changes: 12 additions & 6 deletions tools/cmgen/src/cmgen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,12 @@ void iblMipmapPrefilter(utils::JobSystem& js, const utils::Path& iname,
}
}

float lodToPerceptualRoughness(float lod) {
const float a = 1.686f;
const float b = -0.686f;
return saturate((std::sqrt(a * a + 4.0f * b * lod) - a) / (2.0f * b));
}

void iblRoughnessPrefilter(
utils::JobSystem& js, const utils::Path& iname, const std::vector<Cubemap>& levels,
bool prefilter, const utils::Path& dir) {
Expand Down Expand Up @@ -942,12 +948,12 @@ void iblRoughnessPrefilter(
const float lod = saturate(level / (numLevels - 1.0f));
// map the lod to a linear_roughness, here we're using ^2, but other mappings are possible.
// ==> lod = sqrt(linear_roughness)
const float linear_roughness = lod * lod;
const float perceptualRoughness = lodToPerceptualRoughness(lod);
const float roughness = perceptualRoughness * perceptualRoughness;
if (!g_quiet) {
std::cout << "Level " << level <<
std::setprecision(3)
<< ", roughness(lin) = " << linear_roughness
<< ", roughness = " << sqrt(linear_roughness)
std::cout << "Level " << level << std::setprecision(3)
<< ", roughness = " << roughness
<< ", roughness (perceptual) = " << perceptualRoughness
<< std::endl;
}
Image image;
Expand All @@ -957,7 +963,7 @@ void iblRoughnessPrefilter(
if (!g_quiet) {
updater.start();
}
CubemapIBL::roughnessFilter(js, dst, levels, linear_roughness, numSamples,
CubemapIBL::roughnessFilter(js, dst, levels, roughness, numSamples,
float3{ 1, 1, 1 }, prefilter,
[&updater, quiet = g_quiet](size_t index, float v) {
if (!quiet) {
Expand Down