{"componentChunkName":"component---src-templates-post-template-post-template-tsx","path":"/physically-based-rendering-material","result":{"data":{"markdownRemark":{"id":"8cb15794-43c3-5e2a-9fc3-42266e741fd9","html":"<p>I learned the shading magic like how the most of others did, from a classic Blinn-Phong model to some more complex models like Cook-Torrance model, but the understanding would always be confined around the common practices shaped by our slow speed computer,  and our eager desires for the more realistic results. With these compensations, tricks, and hacks we may achieve lots of cool and amazing stuff at first, but if we don’t have a clear bird’s-eye view (for example people like me who is always suffering among the formulae), then we would lose ourselves inside just shader code and strange artifacts often and can’t find the solutions without painful testing and doubting.</p>\n<p>Then I was thinking, why not implement and learn something from the basic of the physics again? Let’s forget about a little what I’ve already written and start to construct a shading pipeline from scratch, following the physical interpretations, then seeking for solutions to run between each 16 ms. Let’s go back to the start.</p>\n<h2 id=\"so-what-is-light\" style=\"position:relative;\"><a href=\"#so-what-is-light\" aria-label=\"so what is light permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>So, what is light?</h2>\n<blockquote>\n<p>“…In physical optics, light is modeled as an <em>electromagnetic transverse wave</em>, a wave</p>\n</blockquote>\n<p>that oscillates the electric and magnetic fields perpendicularly to the direction of its\npropagation…” - pg. 293, ”<strong>Real-Time Rendering</strong>”, 4th Edition.</p>\n<p>(The book already has become the bible of me, it’s a nice working reference, a balanced textbook and a well-formed dictionary, I’ll quote <span style=\"color: #ff9800; background-color: rgba(255 , 152 , 0 , 0.1); border: 0; padding-top: 2px; padding-right: 4px; padding-bottom: 2px; padding-left: 4px;\">a lot</span> from it later in this ctrl-c + ctrl-v style post (Why not?))</p>\n<p>Light, a kind of <strong>electromagnetic wave</strong> whose property shaped by its <strong>wavelengths</strong> majorly, is one of the fundamental beings in our universe, and all of our beautiful rendering works would focus on how to calculate the <span style=\"color: #ff9800; background-color: rgba(255 , 152 , 0 , 0.1); border: 0; padding-top: 2px; padding-right: 4px; padding-bottom: 2px; padding-left: 4px;\">physical transmission</span> of it always. But what about to think in this way, just because it could be received by our eyes (<span style=\"color: #ff9800; background-color: rgba(255 , 152 , 0 , 0.1); border: 0; padding-top: 2px; padding-right: 4px; padding-bottom: 2px; padding-left: 4px;\">a psychophysical phenomenon</span>) then it had a special name as “light”, and if we could treat it not so special in our theoretical discussion would something become easier and more generally to handle with?</p>\n<p>Let’s say, the basic electromagnetic mechanism works well too with light, all and no exceptions (of course it is), then we could just model a general solution in the computer, and feed it with the light wavelengths <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>λ</mi></mrow><annotation encoding=\"application/x-tex\">\\lambda</annotation></semantics></math></span></span> we emitted from some origins, and other relating properties of some objects which stops the light propagation to calculate the result (may also contain the influences from the space they are in later, now let’s just work inside an ideal static vacuum). The classic physics model of the electromagnetic mechanism is described by <a href=\"https://en.wikipedia.org/wiki/Maxwell%27s_equations\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Maxwell’s equations</a> successfully, and with it we could figure out how the electric field propagating through space, thus means to get the <em>correct</em> phenomenon of the electromagnetic wave in our simulation box.</p>\n<p>But unfortunately, we don’t have such huge computational resources to run a field propagation simulation in real-time inside our personal computer, representing a non-analytical electric field also requires a 3D data structure at least, we must allow some compensations. Luckily, physicists have already simplified the scope of the problems for us, instead of using the original electromagnetic field related methods, we could try to use the <em>radiation</em> methods to focus on the <strong>energy</strong> property only, and this would bring us a simplification of only considering about 2 things, the emitter and the receiver of the electromagnetic wave.</p>\n<h2 id=\"a-new-measurement\" style=\"position:relative;\"><a href=\"#a-new-measurement\" aria-label=\"a new measurement permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>A new measurement</h2>\n<blockquote>\n<p>“…Light waves are emitted when the electric charges in an object oscillate. Part of</p>\n</blockquote>\n<p>the energy that caused the oscillations—heat, electrical energy, chemical energy—is\nconverted to light energy, which is radiated away from the object. …” - pg. 296, ”<strong>Real-Time Rendering</strong>”, 4th Edition.</p>\n<p>Then we would arrive at <em>Radiometry</em>, which <span style=\"color: #ff9800; background-color: rgba(255 , 152 , 0 , 0.1); border: 0; padding-top: 2px; padding-right: 4px; padding-bottom: 2px; padding-left: 4px;\">deals with the measurement of electromagnetic radiation</span>. For the common usage, there are some radiometric quantities which represent the measurement of the electromagnetic radiation energy with respects to other basic physical quantities such like time/distance/area/angle, I’ll list some of them below which are more important to our rendering business, with the reference from <span style=\"color: #ff9800; background-color: rgba(255 , 152 , 0 , 0.1); border: 0; padding-top: 2px; padding-right: 4px; padding-bottom: 2px; padding-left: 4px;\">the book</span> and <a href=\"https://en.wikipedia.org/wiki/Radiometry\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Wikipedia</a>.</p>\n<table>\n<thead>\n<tr>\n<th>Quantity</th>\n<th></th>\n<th>Unit</th>\n<th></th>\n<th>Notes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Name</td>\n<td>Symbol</td>\n<td>Name</td>\n<td>Symbol</td>\n<td></td>\n</tr>\n<tr>\n<td>Radiant energy</td>\n<td><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>Q</mi><mi>e</mi></msub></mrow><annotation encoding=\"application/x-tex\">{Q_e}</annotation></semantics></math></span></span></td>\n<td>joule</td>\n<td><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>J</mi></mrow><annotation encoding=\"application/x-tex\">{J}</annotation></semantics></math></span></span></td>\n<td>Energy of electromagnetic radiation</td>\n</tr>\n<tr>\n<td>Radiant flux</td>\n<td><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi mathvariant=\"normal\">Φ</mi><mi>e</mi></msub></mrow><annotation encoding=\"application/x-tex\">{\\Phi_e}</annotation></semantics></math></span></span></td>\n<td>joule per second or watt</td>\n<td><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mfrac><mi>J</mi><mi>s</mi></mfrac></mrow><annotation encoding=\"application/x-tex\">{\\frac{J}{s}}</annotation></semantics></math></span></span> or <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>W</mi></mrow><annotation encoding=\"application/x-tex\">{W}</annotation></semantics></math></span></span></td>\n<td>also called Radiant power</td>\n</tr>\n<tr>\n<td>Radiant intensity</td>\n<td><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>I</mi><mi>e</mi></msub></mrow><annotation encoding=\"application/x-tex\">{I_e}</annotation></semantics></math></span></span></td>\n<td>watt per steradian</td>\n<td><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mfrac><mi>W</mi><mrow><mi>s</mi><mi>r</mi></mrow></mfrac></mrow><annotation encoding=\"application/x-tex\">{\\frac{W}{sr}}</annotation></semantics></math></span></span></td>\n<td>steradian is similar with angle in 2D space</td>\n</tr>\n<tr>\n<td>Irradiance Flux density</td>\n<td><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>M</mi><mi>e</mi></msub></mrow><annotation encoding=\"application/x-tex\">{M_e}</annotation></semantics></math></span></span> or  <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>E</mi><mi>e</mi></msub></mrow><annotation encoding=\"application/x-tex\">{E_e}</annotation></semantics></math></span></span></td>\n<td>watt per square metre</td>\n<td><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mfrac><mi>W</mi><msup><mi>m</mi><mn>2</mn></msup></mfrac></mrow><annotation encoding=\"application/x-tex\">{\\frac{W}{m^2}}</annotation></semantics></math></span></span></td>\n<td><em>Ir</em>-radiance, means the radiance received by a surface</td>\n</tr>\n<tr>\n<td>Radiance</td>\n<td><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>L</mi><mi>e</mi></msub></mrow><annotation encoding=\"application/x-tex\">{L_e}</annotation></semantics></math></span></span></td>\n<td>watt per steradian per square metre</td>\n<td><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mfrac><mi>W</mi><mrow><msup><mi>m</mi><mn>2</mn></msup><mo separator=\"true\">⋅</mo><mi>s</mi><mi>r</mi></mrow></mfrac></mrow><annotation encoding=\"application/x-tex\">{\\frac{W}{m^2·sr}}</annotation></semantics></math></span></span></td>\n<td></td>\n</tr>\n</tbody>\n</table>\n<p>We won’t directly calculate Radiant energy, because usually we would handle with some objects which has <strong>shape</strong> and some events which happens during a <strong>period</strong>, it’s more convenient to cancel these quantities at first, that means we better choose to use Radiant intensity, Irradiance Flux density and Radiance.</p>\n<p>To evaluate how a light source emitted light or energy, we need to define what is a light source at first. In this blog post, I would choose to discuss the ideal punctual light source only, which has an infinity small shape, the same as a point in space. Also, I would idealize it with an omnidirectional radiation characteristic, which means the radiation wouldn’t variant around different steradians.</p>\n<p>We could deduce the definition of Radiant Intensity first, imagine a <strong>unit</strong> sphere surrounding the point light source, a unit steradian would emit some energy per second, then <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>I</mi><mi>e</mi></msub><mo>=</mo><mfrac><mrow><mi>d</mi><mi mathvariant=\"normal\">Φ</mi></mrow><mrow><mi>d</mi><mi>ω</mi></mrow></mfrac></mrow><annotation encoding=\"application/x-tex\">I_e = \\frac{d\\Phi}{d\\omega}</annotation></semantics></math></span></span>.</p>\n<p><img src=\"/96f02a1d0cf62b6b50a534c9b1c9ea1a/1543478575023.drawio.svg\" alt=\"Diagram\"></p>\n<p>Similar, we could get Irradiance Flux density (or call it <strong>Radiant exitance</strong> if we want to emphasize it’s more about emitting rather than receiving, but it assumes we use some area light sources),  <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>M</mi><mi>e</mi></msub><mo>=</mo><mfrac><mrow><mi>d</mi><mi mathvariant=\"normal\">Φ</mi></mrow><mrow><mi>d</mi><mi>A</mi></mrow></mfrac></mrow><annotation encoding=\"application/x-tex\">M_e = \\frac{d\\Phi}{dA}</annotation></semantics></math></span></span>.</p>\n<p><img src=\"/ff1cefa1c814b543b7c144bf6e8e9509/1543478989212.drawio.svg\" alt=\"Diagram\"></p>\n<p>And then Radiance is <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>L</mi><mi>e</mi></msub><mo>=</mo><mfrac><mrow><mi>d</mi><mi mathvariant=\"normal\">Φ</mi></mrow><mrow><mi>d</mi><mi>ω</mi></mrow></mfrac><mo>∗</mo><mfrac><mrow><mi>d</mi><mi mathvariant=\"normal\">Φ</mi></mrow><mrow><mi>d</mi><mi>A</mi><mi>cos</mi><mo>⁡</mo><mi>θ</mi></mrow></mfrac><mo>=</mo><mfrac><mrow><msup><mi>d</mi><mn>2</mn></msup><mi mathvariant=\"normal\">Φ</mi></mrow><mrow><mi>d</mi><mi>ω</mi><mi>d</mi><mi>A</mi><mi>cos</mi><mo>⁡</mo><mi>θ</mi></mrow></mfrac></mrow><annotation encoding=\"application/x-tex\">L_e = \\frac{d\\Phi}{d\\omega} * \\frac{d\\Phi}{dA \\cos\\theta}  = \\frac{d^2\\Phi}{ d\\omega dA \\cos\\theta}</annotation></semantics></math></span></span>, we now need to consider about the angle between the surface normal and the unit steradian because the actual effective area is not same as the original unit area, it is <em>projected</em> (<span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>A</mi><mi>cos</mi><mo>⁡</mo><mi>θ</mi></mrow><annotation encoding=\"application/x-tex\">A\\cos\\theta</annotation></semantics></math></span></span> is called projected area), so here we add a cos to it. This kind of cos-weighted distribution is called <a href=\"https://en.wikipedia.org/wiki/Lambert%27s_cosine_law\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Lambert’s cosine law</a>.</p>\n<p><img src=\"/6fc7fee76546ccee6d6ae6359cad7892/1543479097755.drawio.svg\" alt=\"Diagram\"></p>\n<h2 id=\"through-time-and-space-once-and-forever\" style=\"position:relative;\"><a href=\"#through-time-and-space-once-and-forever\" aria-label=\"through time and space once and forever permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Through time and space, once and forever?</h2>\n<blockquote>\n<p>“…The oscillating electrical field pushes and pulls at the electrical</p>\n</blockquote>\n<p>charges in the matter, causing them to oscillate in turn. The oscillating charges emit\nnew light waves, which redirect some of the energy of the incoming light wave in new\ndirections. This reaction, called <em>scattering</em>, is the basis of a wide variety of optical\nphenomena. …” - pg. 297, ”<strong>Real-Time Rendering</strong>”, 4th Edition.</p>\n<p>If we emit any light/energy in vacuum, it would never change the direction and the energy unless meets with some obstructions (for example some molecules or small dust floating in space or some large giant gas planets like Saturn, or our body/eyes), then it would be absorbed or scattered due to the characteristics of the obstructions. Actually, this is all what we need to care about, the obstructions <em>IS</em> exactly the receiver! Then if we could model how the receiver it is we would solve the problem. But again, the limitation of our computational resources doesn’t allow us to simulate every molecule, instead, we have to follow some macro scope rules to abstract them. We call these single or group of trivial shape objects which influence the wave propagation as <em>particles</em>, and the volume the particles fulfilled with as <em>media</em>.</p>\n<p>We live on Earth where the air and water are the most common noticeable medium, who gives us an inspiration for aesthetic creations for thousands of years. For to measure how they influence the light propagation, we need to define a kind of ratio between the original light and the affected light.</p>\n<blockquote>\n<p>“…The ratio of the phase velocities of the original and new waves defines an optical</p>\n</blockquote>\n<p>property of the medium called the <em>index of refraction</em> (IOR) or refractive index,\ndenoted by the letter <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>n</mi></mrow><annotation encoding=\"application/x-tex\">n</annotation></semantics></math></span></span>. Some media are <em>absorptive</em>. They convert part of the light\nenergy to heat, causing the wave amplitude to decrease exponentially with distance.\nThe rate of decrease is defined by the <em>attenuation index</em>, denoted by the Greek letter\n<span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>κ</mi></mrow><annotation encoding=\"application/x-tex\">\\kappa</annotation></semantics></math></span></span> (kappa). Both n and <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>κ</mi></mrow><annotation encoding=\"application/x-tex\">\\kappa</annotation></semantics></math></span></span> typically vary by wavelength. Together, these two numbers\nfully define how the medium affects light of a given wavelength, and they are often\ncombined into a single complex number <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>n</mi><mo>+</mo><mi>i</mi><mi>κ</mi></mrow><annotation encoding=\"application/x-tex\">n + i \\kappa</annotation></semantics></math></span></span>, called the <em>complex index of refraction</em>. …” - pg. 298, ”<strong>Real-Time Rendering</strong>”, 4th Edition.</p>\n<p>As <span style=\"color: #ff9800; background-color: rgba(255 , 152 , 0 , 0.1); border: 0; padding-top: 2px; padding-right: 4px; padding-bottom: 2px; padding-left: 4px;\">the book</span> introduced, we use complex IOR to represent the characteristics of a media, but in practice of local illumination, we’d often only care about the real number part <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>n</mi></mrow><annotation encoding=\"application/x-tex\">n</annotation></semantics></math></span></span>, since the attenuation happens around the conductor medium more and we typically imply we would treat the air as our original media (or in the volume rendering business, but I won’t cover about that topic here). Then we could simply get IOR by <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>n</mi><mo>=</mo><mfrac><mi>c</mi><mi>v</mi></mfrac></mrow><annotation encoding=\"application/x-tex\">n = \\frac{c}{v}</annotation></semantics></math></span></span>, where <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>c</mi></mrow><annotation encoding=\"application/x-tex\">c</annotation></semantics></math></span></span> is the light speed in vacuum and <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>v</mi></mrow><annotation encoding=\"application/x-tex\">v</annotation></semantics></math></span></span> is the light speed in the media. For a further detailed discussion about complex IOR, I recommend this <a href=\"https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/#more-1921\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">post</a> by Sébastien Lagarde, which he talked around the situations that covering all the other possible medium interfaces.</p>\n<p>And then we would have a physical law called Snell’s law, which relates the incident angle with refracted angle by IOR of two mediums, written as <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>sin</mi><mo>⁡</mo><mo stretchy=\"false\">(</mo><msub><mi>θ</mi><mi>t</mi></msub><mo stretchy=\"false\">)</mo><mo>=</mo><mfrac><msub><mi>n</mi><mn>1</mn></msub><msub><mi>n</mi><mn>2</mn></msub></mfrac><mi>sin</mi><mo>⁡</mo><mo stretchy=\"false\">(</mo><msub><mi>θ</mi><mi>i</mi></msub><mo stretchy=\"false\">)</mo></mrow><annotation encoding=\"application/x-tex\">\\sin(\\theta_t) = \\frac{n_1}{n_2}\\sin(\\theta_i)</annotation></semantics></math></span></span>, where <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>θ</mi><mi>i</mi></msub></mrow><annotation encoding=\"application/x-tex\">\\theta_i</annotation></semantics></math></span></span> is the angle between the interface normal and the incident light direction, <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>θ</mi><mi>t</mi></msub></mrow><annotation encoding=\"application/x-tex\">\\theta_t</annotation></semantics></math></span></span> as the angle between the inverse of the interface normal and the refracted/<em>transmitted</em> light direction. <span style=\"color: #ff9800; background-color: rgba(255 , 152 , 0 , 0.1); border: 0; padding-top: 2px; padding-right: 4px; padding-bottom: 2px; padding-left: 4px;\">We denote the index of refraction on the “outside” (the side where the incoming, or incident, wave originates) as <span><span style=\"color: inherit;\"></span><span style=\"font-size: 100%; display: inline-block;\"><img style=\"vertical-align: middle; max-width: 100%; height: auto; border: 0;\" src=\"https://app.yinxiang.com/shard/s18/res/bcec0d8e-f392-44bc-aa9f-e7e0cd4299c6/c265ad38d170dee9df5191cfef57be30.png\" name=\"bcec0d8e-f392-44bc-aa9f-e7e0cd4299c6\" class=\"en-media\"></span></span> and the index of refraction on the “inside” (where the wave will be transmitted after passing through the surface) as <span><span style=\"color: inherit;\"></span><span style=\"font-size: 100%; display: inline-block;\"><img style=\"vertical-align: middle; max-width: 100%; height: auto; border: 0;\" src=\"https://app.yinxiang.com/shard/s18/res/aac6fe9b-7b21-491f-ae38-d2f40d1f6b2c/82f426df9519d93188b5481181949bae.png\" name=\"aac6fe9b-7b21-491f-ae38-d2f40d1f6b2c\" class=\"en-media\"></span></span>.</span></p>\n<p><img src=\"/bab1a00fbd569fb551238afea7c5c56d/1543509296989.drawio.svg\" alt=\"Diagram\"></p>\n<p>Now if we know the angles (here we abstract the light to a single <em>monochromatic</em> beam, which has “angle” and a single wavelength, but actually we’ve talked before how it is in real situation) and the IOR of the medium, could we calculate anything useful to display on the screen? Well, with Snell’s law we could figure out the direction change of the light, but we didn’t know how much energy would change, also if the light is not monochromatic, we don’t know which range of wavelengths would be reflected or refracted. And the most important problem is, we are receiving light through our eyes, but not always directly from the light source, what we want to receive are those light “reflected” from different surfaces, rather than those directly emitted from the sun or the bulbs!</p>\n<p>So actually, we need to figure out such a scenario: Light is emitted from a source, meets with some surfaces and changes, then somehow travels into our eyes. When the light “hit” the surface we then could try to apply Snell’s law. But Snell’s law is just about how light changes at the medium interface in a very ideal situation, we don’t know what would happen next, since the conservation of energy always work in this universe (until the moment I wrote this line it is still valid), the reflected light must be weaker than the incident light, but how much? Also, where the refracted light part goes?</p>\n<p>That requires us to give further information about how light continuously traveling. As I mentioned before,  media is made up by particles, then the size of particles and the distance of particles should have an influence on the light transmission. But since it’s impossible to calculate everything happened inside the media, we choose to model the region around the surface of the media only which has much more contributions to the light into our eyes.</p>\n<blockquote>\n<p>“…In rendering, we typically use <em>geometrical optics</em>, which ignores wave effects such as</p>\n</blockquote>\n<p>interference and diffraction. This is equivalent to assuming that all surface irregularities\nare either smaller than a light wavelength or much larger. …” - pg. 303, ”<strong>Real-Time Rendering</strong>”, 4th Edition.</p>\n<blockquote>\n<p>“…surface irregularities much larger than a wavelength</p>\n</blockquote>\n<p>change the local orientation of the surface. When these irregularities are too small\nto be individually rendered—in other words, smaller than a pixel—we refer to them\nas <em>microgeometry</em>. …” - pg. 304, ”<strong>Real-Time Rendering</strong>”, 4th Edition.</p>\n<blockquote>\n<p>“…For rendering, rather than modeling the microgeometry explicitly, we treat it statistically</p>\n</blockquote>\n<p>and view the surface as having a random distribution of microstructure\nnormals. As a result, we model the surface as reflecting (and refracting) light in a\ncontinuous spread of directions. The width of this spread, and thus the blurriness of\nreflected and refracted detail, depends on the statistical variance of the microgeometry\nnormal vectors—in other words, the surface microscale <em>roughness</em>. …” - pg. 304, ”<strong>Real-Time Rendering</strong>”, 4th Edition.</p>\n<p><span style=\"color: #ff9800; background-color: rgba(255 , 152 , 0 , 0.1); border: 0; padding-top: 2px; padding-right: 4px; padding-bottom: 2px; padding-left: 4px;\">The book</span> introduced the microgeometry theory, which is balanced between the computational burden and the credibility of the result when it was adopted into real-time rendering community. Since our screen has limited discrete pixels, then it’s meaningless and wasting to calculate anything too accurately, instead we choose to use some statistical models for a cheaper routine. You may have heard some statistical methods used in rendering like the most famous Monte Carlo method before, here we would follow the similar path to figure out how to get the final light.</p>\n<h2 id=\"the-rendering-equation\" style=\"position:relative;\"><a href=\"#the-rendering-equation\" aria-label=\"the rendering equation permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>The Rendering Equation</h2>\n<p>Now we could introduce an almost accurate representation of the interaction between light and surfaces. For a single light in wavelength <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>λ</mi></mrow><annotation encoding=\"application/x-tex\">\\lambda</annotation></semantics></math></span></span> at time <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>t</mi></mrow><annotation encoding=\"application/x-tex\">t</annotation></semantics></math></span></span> who hits the surface in a unit area <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>A</mi></mrow><annotation encoding=\"application/x-tex\">A</annotation></semantics></math></span></span> from a unit steradian <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>ω</mi><mi>i</mi></msub></mrow><annotation encoding=\"application/x-tex\">\\omega_i</annotation></semantics></math></span></span>, and is “changed” by the surface then finally “re-emitted” to our eyes by an unit steradian <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>ω</mi><mi>o</mi></msub></mrow><annotation encoding=\"application/x-tex\">\\omega_o</annotation></semantics></math></span></span>, we could write such a formula: <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>L</mi><mi>o</mi></msub><mo stretchy=\"false\">(</mo><mi>A</mi><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>o</mi></msub><mo separator=\"true\">,</mo><mi>λ</mi><mo separator=\"true\">,</mo><mi>t</mi><mo stretchy=\"false\">)</mo><mo>=</mo><msub><mi>f</mi><mi>r</mi></msub><msub><mi>L</mi><mi>i</mi></msub><mo stretchy=\"false\">(</mo><mi>A</mi><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">,</mo><mi>λ</mi><mo separator=\"true\">,</mo><mi>t</mi><mo stretchy=\"false\">)</mo></mrow><annotation encoding=\"application/x-tex\">L_o(A,\\omega_o,\\lambda,t) =  f_r L_i(A,\\omega_i,\\lambda,t)</annotation></semantics></math></span></span>, which describe the incident radiance is weighted by a factor <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mi>r</mi></msub></mrow><annotation encoding=\"application/x-tex\">f_r</annotation></semantics></math></span></span> who indicates the surface optic characteristic then contributes to the surface irradiance. Then we could do an integration for every possible incident direction of different light around the hemisphere centered at the surface normal, combine with the original emitted light from the surface itself, to get a more general formula. One summarization formula for rendering in this context is <a href=\"https://en.wikipedia.org/wiki/Rendering_equation\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">The Rendering Equation</a>, <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>L</mi><mi>o</mi></msub><mo stretchy=\"false\">(</mo><mi>p</mi><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>o</mi></msub><mo separator=\"true\">,</mo><mi>λ</mi><mo separator=\"true\">,</mo><mi>t</mi><mo stretchy=\"false\">)</mo><mo>=</mo><msub><mi>L</mi><mi>e</mi></msub><mo stretchy=\"false\">(</mo><mi>p</mi><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>o</mi></msub><mo separator=\"true\">,</mo><mi>λ</mi><mo separator=\"true\">,</mo><mi>t</mi><mo stretchy=\"false\">)</mo><mo>+</mo><munder><mo>∫</mo><mi mathvariant=\"normal\">Ω</mi></munder><msub><mi>f</mi><mi>r</mi></msub><mo stretchy=\"false\">(</mo><mi>p</mi><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>o</mi></msub><mo separator=\"true\">,</mo><mi>λ</mi><mo separator=\"true\">,</mo><mi>t</mi><mo stretchy=\"false\">)</mo><msub><mi>L</mi><mi>i</mi></msub><mo stretchy=\"false\">(</mo><mi>p</mi><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">,</mo><mi>λ</mi><mo separator=\"true\">,</mo><mi>t</mi><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">(</mo><mi>n</mi><mo>⋅</mo><msub><mi>ω</mi><mi>i</mi></msub><mo stretchy=\"false\">)</mo><mi>d</mi><msub><mi>ω</mi><mi>i</mi></msub></mrow><annotation encoding=\"application/x-tex\">L_o(p,\\omega_o,\\lambda,t) = L_e(p,\\omega_o,\\lambda,t) + \\int\\limits_{\\Omega} f_r(p,\\omega_i,\\omega_o,\\lambda,t) L_i(p,\\omega_i,\\lambda,t) (n \\cdot \\omega_i)  d\\omega_i</annotation></semantics></math></span></span>, basically it is the same transcript of what I talked before, but with a simplification that we ignore the surface area, just minimize it to a point <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>p</mi></mrow><annotation encoding=\"application/x-tex\">p</annotation></semantics></math></span></span>.</p>\n<p>Further more, we would like to treat the light-surface interaction as an time-domain individual event, then we could omit <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>t</mi></mrow><annotation encoding=\"application/x-tex\">t</annotation></semantics></math></span></span>. And because we would finally send a RGB color space data to the screen, so a continuous spectral irradiance is fairly unnecessary, then we would like to also cancel the spectrum by replacing it with 3 individual similar formulae, which have same form but care only about each color channels, thus we could just write one instead as The Reflectance Equation: <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>L</mi><mi>o</mi></msub><mo stretchy=\"false\">(</mo><mi>p</mi><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo><mo>=</mo><munder><mo>∫</mo><mi mathvariant=\"normal\">Ω</mi></munder><msub><mi>f</mi><mi>r</mi></msub><mo stretchy=\"false\">(</mo><mi>p</mi><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo><msub><mi>L</mi><mi>i</mi></msub><mo stretchy=\"false\">(</mo><mi>p</mi><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>i</mi></msub><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">(</mo><mi>n</mi><mo>⋅</mo><msub><mi>ω</mi><mi>i</mi></msub><mo stretchy=\"false\">)</mo><mi>d</mi><msub><mi>ω</mi><mi>i</mi></msub></mrow><annotation encoding=\"application/x-tex\">L_o(p,\\omega_o) = \\int\\limits_{\\Omega} f_r(p,\\omega_i,\\omega_o) L_i(p,\\omega_i) (n \\cdot \\omega_i)  d\\omega_i</annotation></semantics></math></span></span>.</p>\n<blockquote>\n<p>“…Local reflectance</p>\n</blockquote>\n<p>is quantified by the <em>bidirectional reflectance distribution function</em> (BRDF), denoted\nas <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>f</mi><mo stretchy=\"false\">(</mo><mi>l</mi><mo separator=\"true\">,</mo><mi>v</mi><mo stretchy=\"false\">)</mo></mrow><annotation encoding=\"application/x-tex\">f(l, v)</annotation></semantics></math></span></span>. …” - pg. 310, ”<strong>Real-Time Rendering</strong>”, 4th Edition.</p>\n<p>Now if we know how the incident light they are, then we just need to give a <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mi>r</mi></msub></mrow><annotation encoding=\"application/x-tex\">f_r</annotation></semantics></math></span></span> weight who described the entire optic characteristic of the media and would get the final results. This <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mi>r</mi></msub><mo stretchy=\"false\">(</mo><mi>p</mi><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo></mrow><annotation encoding=\"application/x-tex\">f_r(p,\\omega_i,\\omega_o)</annotation></semantics></math></span></span>, like <span style=\"color: #ff9800; background-color: rgba(255 , 152 , 0 , 0.1); border: 0; padding-top: 2px; padding-right: 4px; padding-bottom: 2px; padding-left: 4px;\">the book</span> introduced, is called BRDF, combining with the microgeometry method I listed above, we would have chance to finally write some codes to calculate. But at first, let’s take a look back at the surface model we used here, we say “surface” not “interface”, the “surface” indicates we are inspecting in a region around the “interface”, so it should have more properties than what Snell’s law could describe. Let’s take a look:</p>\n<p><img src=\"/213b1d04ebf8e3748605fa7a52376a9b/1543560653216.drawio.svg\" alt=\"Diagram\"></p>\n<p>As the media won’t always absorb and scatter all the refracted light inside (for example most of the non-conductors won’t, since there are too less free electrons inside to do the business), some of them would leave the media and enter the previous media again, which we called this kind of phenomenon as Subsurface Scattering. A typical practice is to separate the BRDF to 2 parts, a reflection part as <strong>specular</strong> and a <em>local</em> subsurface scattering part as <strong>diffuse</strong>. I would like to use the notation as <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mi>s</mi></msub></mrow><annotation encoding=\"application/x-tex\">f_s</annotation></semantics></math></span></span> and <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mi>d</mi></msub></mrow><annotation encoding=\"application/x-tex\">f_d</annotation></semantics></math></span></span> later.</p>\n<p>Also, sometimes we need to calculate more general subsurface scattering, then we would use a <em>bidirectional scattering distribution function</em> (abbr. BSSRDF) instead, and for the light who travel through the entire media and leave in another surface it becomes <em>bidirectional transmittance distribution function</em>  (abbr. BTDF). Together they are called as BxDF.</p>\n<p>To make a BxDF physically correct, we need to achieve 3 goals：</p>\n<ol>\n<li>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mi>r</mi></msub><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo><mo>≥</mo><mn>0</mn></mrow><annotation encoding=\"application/x-tex\">f_r(\\omega_i,\\omega_o) \\ge 0</annotation></semantics></math></span></span>, a BxDF never results negative weight;</p>\n</li>\n<li>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mi>r</mi></msub><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo><mo>=</mo><msub><mi>f</mi><mi>r</mi></msub><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>o</mi></msub><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>i</mi></msub><mo stretchy=\"false\">)</mo></mrow><annotation encoding=\"application/x-tex\">f_r(\\omega_i,\\omega_o) = f_r(\\omega_o,\\omega_i)</annotation></semantics></math></span></span>, it’s called Helmholtz reciprocity, simply speaking means if we change the incident and the observe direction it should have the same result;</p>\n</li>\n<li>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi mathvariant=\"normal\">∀</mi><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">,</mo><munder><mo>∫</mo><mi mathvariant=\"normal\">Ω</mi></munder><msub><mi>f</mi><mi>r</mi></msub><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">(</mo><mi>n</mi><mo>⋅</mo><msub><mi>ω</mi><mi>i</mi></msub><mo stretchy=\"false\">)</mo><mi>d</mi><msub><mi>ω</mi><mi>i</mi></msub><mo>≤</mo><mn>1</mn></mrow><annotation encoding=\"application/x-tex\">\\forall \\omega_i, \\int\\limits_{\\Omega}f_r(\\omega_i,\\omega_o)(n \\cdot \\omega_i)  d\\omega_i \\le 1</annotation></semantics></math></span></span>, means we need to follow the energy conservation law, the weight should never exceed than 1, the <em>relative</em> outgoing light energy should never exceed than the <em>relative</em> incoming light energy.</p>\n</li>\n</ol>\n<p>In practice there is a kind of convenient way to evaluate whether a BxDF is energy conservation or not called <a href=\"http://jcgt.org/published/0003/02/03/paper.pdf\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">White furnace test</a>, I’ll talk about it later.</p>\n<h2 id=\"brdf\" style=\"position:relative;\"><a href=\"#brdf\" aria-label=\"brdf permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>BRDF</h2>\n<p>BRDF would be thought as <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mi>r</mi></msub><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo><mo>=</mo><mfrac><mrow><mi>d</mi><msub><mi>L</mi><mi>o</mi></msub><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo></mrow><mrow><msub><mi>L</mi><mi>i</mi></msub><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>i</mi></msub><mo stretchy=\"false\">)</mo><mi>cos</mi><mo>⁡</mo><msub><mi>θ</mi><mi>i</mi></msub><mi>d</mi><msub><mi>ω</mi><mi>i</mi></msub></mrow></mfrac></mrow><annotation encoding=\"application/x-tex\">f_r(\\omega_i,\\omega_o) = \\frac{dL_o(\\omega_o)}{L_i(\\omega_i)\\cos\\theta_i d\\omega_i}</annotation></semantics></math></span></span>, which gives us a possibility to measure it in real, for example <a href=\"https://www.merl.com/brdf/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">MERL</a> is one kind of BRDF database. Also, we could write BRDF as <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mi>r</mi></msub><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo><mo>=</mo><msub><mi>f</mi><mi>d</mi></msub><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo><mo>+</mo><msub><mi>f</mi><mi>s</mi></msub><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo></mrow><annotation encoding=\"application/x-tex\">f_r(\\omega_i,\\omega_o) = f_d(\\omega_i,\\omega_o) + f_s(\\omega_i,\\omega_o)</annotation></semantics></math></span></span>, to indicate that we would like to seperate BRDF to the specular and diffuse parts and solve them independently.</p>\n<p>Let’s use <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>n</mi></mrow><annotation encoding=\"application/x-tex\">n</annotation></semantics></math></span></span> as the macro surface normal vector and <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>m</mi></mrow><annotation encoding=\"application/x-tex\">m</annotation></semantics></math></span></span> as the micro surface normal vector, and <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>h</mi><mtext> </mtext><mo>=</mo><mfrac><mrow><msub><mi>ω</mi><mi>o</mi></msub><mo>+</mo><msub><mi>ω</mi><mi>i</mi></msub></mrow><mrow><mi mathvariant=\"normal\">∣</mi><mi mathvariant=\"normal\">∣</mi><msub><mi>ω</mi><mi>o</mi></msub><mo>+</mo><msub><mi>ω</mi><mi>i</mi></msub><mi mathvariant=\"normal\">∣</mi><mi mathvariant=\"normal\">∣</mi></mrow></mfrac></mrow><annotation encoding=\"application/x-tex\">h\\ = \\frac{\\omega_o + \\omega_i}{||\\omega_o + \\omega_i||}</annotation></semantics></math></span></span> as the normalized halfway vector of the view direction and light direction.</p>\n<p>Also, for the sake of convenience to discuss BRDF more practically, I’d like to introduce the <em>Directional albedo</em> which <span style=\"color: #ff9800; background-color: rgba(255 , 152 , 0 , 0.1); border: 0; padding-top: 2px; padding-right: 4px; padding-bottom: 2px; padding-left: 4px;\">measures the amount of light coming from a given direction that is reflected at all, into any outgoing direction in the hemisphere around the surface normal</span>, in formula as <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>R</mi><mi>s</mi></msub><mo>=</mo><munder><mo>∫</mo><mi mathvariant=\"normal\">Ω</mi></munder><mi>f</mi><mo stretchy=\"false\">(</mo><mi>l</mi><mo separator=\"true\">,</mo><mi>v</mi><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">(</mo><mi>n</mi><mo separator=\"true\">⋅</mo><mi>s</mi><mo stretchy=\"false\">)</mo><mi>d</mi><mi>s</mi></mrow><annotation encoding=\"application/x-tex\">R_s = \\int\\limits_{\\Omega}f(l, v)(n·s)ds</annotation></semantics></math></span></span>, if the BRDF is Helmholtz reciprocal then could substitute <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>s</mi></mrow><annotation encoding=\"application/x-tex\">s</annotation></semantics></math></span></span> with <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>l</mi></mrow><annotation encoding=\"application/x-tex\">l</annotation></semantics></math></span></span> or <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>v</mi></mrow><annotation encoding=\"application/x-tex\">v</annotation></semantics></math></span></span> freely.</p>\n<h3 id=\"diffuse-part\" style=\"position:relative;\"><a href=\"#diffuse-part\" aria-label=\"diffuse part permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Diffuse part</h3>\n<h4 id=\"simple-lambert-model\" style=\"position:relative;\"><a href=\"#simple-lambert-model\" aria-label=\"simple lambert model permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Simple Lambert model</h4>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mrow><mi>L</mi><mi>a</mi><mi>m</mi><mi>b</mi><mi>e</mi><mi>r</mi><mi>t</mi></mrow></msub><mo>=</mo><mfrac><mi>ρ</mi><mi>π</mi></mfrac></mrow><annotation encoding=\"application/x-tex\">f_{Lambert} = \\frac{\\rho} {\\pi}</annotation></semantics></math></span></span>, <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>ρ</mi></mrow><annotation encoding=\"application/x-tex\">\\rho</annotation></semantics></math></span></span> as the “color” of the surface, strictly speaking it is the subsurface scattering part of the surface irradiance under a particular lighting circumstance; <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>π</mi></mrow><annotation encoding=\"application/x-tex\">\\pi</annotation></semantics></math></span></span> comes from the fact that we treat the surface as the <a href=\"https://en.wikipedia.org/wiki/Lambertian_reflectance\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Lambertian</a> surface, thus it won’t change due to the view and light direction, then the BRDF integral over the hemisphere yield it.</p>\n<p>Let’s visualize its directional albedo: (BRDF Explorer/Octave WIP)</p>\n<p>This simple Lambert diffuse model would ignore the surface micro scope variation, combines with the Lambert’s cosine law we could already get <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>L</mi><mi>o</mi></msub><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo><mo>=</mo><munder><mo>∫</mo><mi mathvariant=\"normal\">Ω</mi></munder><mfrac><mi>ρ</mi><mi>π</mi></mfrac><msub><mi>L</mi><mi>i</mi></msub><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>i</mi></msub><mo stretchy=\"false\">)</mo><mi>cos</mi><mo>⁡</mo><msub><mi>θ</mi><mi>i</mi></msub><mi>d</mi><msub><mi>ω</mi><mi>i</mi></msub></mrow><annotation encoding=\"application/x-tex\">L_o(\\omega_o) = \\int\\limits_{\\Omega}\\frac{\\rho} {\\pi}L_i(\\omega_i)\\cos\\theta_i d\\omega_i</annotation></semantics></math></span></span>, since the integral of direction <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>ω</mi><mi>i</mi></msub></mrow><annotation encoding=\"application/x-tex\">\\omega_i</annotation></semantics></math></span></span> over the hemisphere is <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>π</mi></mrow><annotation encoding=\"application/x-tex\">\\pi</annotation></semantics></math></span></span>, then it would cancel the <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>π</mi></mrow><annotation encoding=\"application/x-tex\">\\pi</annotation></semantics></math></span></span> in the BRDF, so finally we would just get <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>L</mi><mi>o</mi></msub><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo><mo>=</mo><mi>ρ</mi><mi>cos</mi><mo>⁡</mo><msub><mi>θ</mi><mi>i</mi></msub></mrow><annotation encoding=\"application/x-tex\">L_o(\\omega_o) = \\rho \\cos\\theta_i</annotation></semantics></math></span></span>, exactly the same as what we learned first in the real-time rendering class 101!</p>\n<h4 id=\"cook-torrance-model\" style=\"position:relative;\"><a href=\"#cook-torrance-model\" aria-label=\"cook torrance model permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Cook-Torrance model</h4>\n<p>The lack of micro scope detail of the simple Lambert model limits us to get further realistic results, luckily as the researchers and scientists work on it for decades, we’ve already had some advanced replacements of the simple Lambert model, one of them which is used most commonly today in real-time rendering community is the microgeometry theory, we’d refer it as <em>microfacet</em> theory here.</p>\n<p>R.L. Cook and K. E. Torrance [CT82] wrote a paper in 80’s which is the root of the most popular adopted microfacet model today, with the other nice references [Hei14][LR14] we could conclude the general Cook-Torrance model as <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mrow><mi>C</mi><mi>o</mi><mi>o</mi><mi>k</mi><mo>−</mo><mi>T</mi><mi>o</mi><mi>r</mi><mi>r</mi><mi>a</mi><mi>n</mi><mi>c</mi><mi>e</mi></mrow></msub><mo>=</mo><mfrac><mn>1</mn><mrow><mi mathvariant=\"normal\">∣</mi><mi>n</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>o</mi></msub><mi mathvariant=\"normal\">∣</mi><mi mathvariant=\"normal\">∣</mi><mi>n</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>i</mi></msub><mi mathvariant=\"normal\">∣</mi></mrow></mfrac><munder><mo>∫</mo><mi mathvariant=\"normal\">Ω</mi></munder><msub><mi>f</mi><mi>m</mi></msub><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>o</mi></msub><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">,</mo><mi>m</mi><mo stretchy=\"false\">)</mo><mi>G</mi><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>o</mi></msub><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">,</mo><mi>m</mi><mo stretchy=\"false\">)</mo><mi>D</mi><mo stretchy=\"false\">(</mo><mi>m</mi><mo separator=\"true\">,</mo><mi>α</mi><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">⟨</mo><msub><mi>ω</mi><mi>o</mi></msub><mo separator=\"true\">⋅</mo><mi>m</mi><mo stretchy=\"false\">⟩</mo><mo stretchy=\"false\">⟨</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">⋅</mo><mi>m</mi><mo stretchy=\"false\">⟩</mo><mi>d</mi><mi>m</mi></mrow><annotation encoding=\"application/x-tex\">f_{Cook-Torrance}=\\frac{1}{|n·\\omega_o||n·\\omega_i|}\\int\\limits_{\\Omega}f_m(\\omega_o,\\omega_i,m)G(\\omega_o,\\omega_i,m) D(m,\\alpha)\\langle \\omega_o·m\\rangle \\langle \\omega_i·m\\rangle dm</annotation></semantics></math></span></span>. It emphasizes that the macro BRDF is correlated with the micro BRDF, and it could be calculated through the integral over the microfacet <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>m</mi></mrow><annotation encoding=\"application/x-tex\">m</annotation></semantics></math></span></span>, with the additional weight functions <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>G</mi></mrow><annotation encoding=\"application/x-tex\">G</annotation></semantics></math></span></span> and <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>D</mi></mrow><annotation encoding=\"application/x-tex\">D</annotation></semantics></math></span></span> to help keeping the micro-macro mapping relationship stay <strong>correct</strong>.</p>\n<p>The <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>D</mi></mrow><annotation encoding=\"application/x-tex\">D</annotation></semantics></math></span></span> function is called <em>Distribution function</em> or <em>Normal Distribution Function</em>(abbr. NDF), gives the spatial/statical distribution of the micro normal <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>m</mi></mrow><annotation encoding=\"application/x-tex\">m</annotation></semantics></math></span></span> over the macro normal <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>n</mi></mrow><annotation encoding=\"application/x-tex\">n</annotation></semantics></math></span></span>, the <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>α</mi></mrow><annotation encoding=\"application/x-tex\">\\alpha</annotation></semantics></math></span></span> here is a user-controlled variable which describes how “rough” the surface it is, so we call it <em>roughness</em> or <em>smoothness</em> in practice (typically we’d like to build a non-linear mapping between the user-controlled roughness and the real <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>α</mi></mrow><annotation encoding=\"application/x-tex\">\\alpha</annotation></semantics></math></span></span>). We would use statical functions in practice since it’s the only possible way to calculate in real-time, about how to mapping from spatial function to statical function I recommend to read this paper [Hei14] for detail understanding.</p>\n<p>The <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>G</mi></mrow><annotation encoding=\"application/x-tex\">G</annotation></semantics></math></span></span> function is called <em>Geometry function</em> or <em>Masking-shadowing function</em>, but strictly speaking, we would better call it <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>V</mi></mrow><annotation encoding=\"application/x-tex\">V</annotation></semantics></math></span></span> as <em>Visibility function</em>, since the Geometry function is usually used to compose the Visibility function actually, but in literal it is used exchangeably often. It gives a weight about how the microfacets influence themselves by masking each other along the view direction and shadowing each other along the incident light direction, it should be deduced accordingly with the <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>D</mi></mrow><annotation encoding=\"application/x-tex\">D</annotation></semantics></math></span></span> function we chose.</p>\n<p>I’ll list some common used <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>D</mi></mrow><annotation encoding=\"application/x-tex\">D</annotation></semantics></math></span></span> and <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>G</mi></mrow><annotation encoding=\"application/x-tex\">G</annotation></semantics></math></span></span> functions below:</p>\n<h5 id=\"d-function\" style=\"position:relative;\"><a href=\"#d-function\" aria-label=\"d function permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>D</mi></mrow><annotation encoding=\"application/x-tex\">D</annotation></semantics></math></span></span> function</h5>\n<h6 id=\"gaussian-d-function-ct82\" style=\"position:relative;\"><a href=\"#gaussian-d-function-ct82\" aria-label=\"gaussian d function ct82 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Gaussian <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>D</mi></mrow><annotation encoding=\"application/x-tex\">D</annotation></semantics></math></span></span> function [CT82]</h6>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>D</mi><mrow><mi>G</mi><mi>a</mi><mi>u</mi><mi>s</mi><mi>s</mi><mi>i</mi><mi>a</mi><mi>n</mi></mrow></msub><mo>=</mo><mi>c</mi><msup><mi>e</mi><mrow><mo stretchy=\"false\">(</mo><mo>−</mo><mi>α</mi><mi mathvariant=\"normal\">/</mi><mi>m</mi><msup><mo stretchy=\"false\">)</mo><mn>2</mn></msup></mrow></msup></mrow><annotation encoding=\"application/x-tex\">D_{Gaussian}=ce^{(-\\alpha/m)^2}</annotation></semantics></math></span></span></p>\n<h6 id=\"beckmann-d-function-ct82\" style=\"position:relative;\"><a href=\"#beckmann-d-function-ct82\" aria-label=\"beckmann d function ct82 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Beckmann <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>D</mi></mrow><annotation encoding=\"application/x-tex\">D</annotation></semantics></math></span></span> function [CT82]</h6>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>D</mi><mrow><mi>B</mi><mi>e</mi><mi>c</mi><mi>k</mi><mi>m</mi><mi>a</mi><mi>n</mi><mi>n</mi></mrow></msub><mo>=</mo><mfrac><mn>1</mn><mrow><msup><mi>m</mi><mn>2</mn></msup><msup><mrow><mi>cos</mi><mo>⁡</mo></mrow><mn>4</mn></msup><mi>α</mi></mrow></mfrac><msup><mi>e</mi><mrow><mo>−</mo><mo stretchy=\"false\">[</mo><mtext> </mtext><mo stretchy=\"false\">(</mo><mi>tan</mi><mo>⁡</mo><mi>α</mi><mo stretchy=\"false\">)</mo><mi mathvariant=\"normal\">/</mi><mi>m</mi><mo stretchy=\"false\">]</mo><msup><mtext> </mtext><mn>2</mn></msup></mrow></msup></mrow><annotation encoding=\"application/x-tex\">D_{Beckmann}=\\frac{1}{m^2\\cos^4\\alpha}e^{-[ \\,(\\tan\\alpha)/m ] \\,^2}</annotation></semantics></math></span></span></p>\n<p>For these two <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>D</mi></mrow><annotation encoding=\"application/x-tex\">D</annotation></semantics></math></span></span> functions, <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>c</mi></mrow><annotation encoding=\"application/x-tex\">c</annotation></semantics></math></span></span> is an optional scaling factor, <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>α</mi></mrow><annotation encoding=\"application/x-tex\">\\alpha</annotation></semantics></math></span></span> as the angle between <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>n</mi></mrow><annotation encoding=\"application/x-tex\">n</annotation></semantics></math></span></span> and <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>h</mi></mrow><annotation encoding=\"application/x-tex\">h</annotation></semantics></math></span></span>, <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>m</mi></mrow><annotation encoding=\"application/x-tex\">m</annotation></semantics></math></span></span> as the RMS of the slope of the microfacet. Since they are computationally expensive, it’s rare to see them in real products, but we’d like to treat them as the offline reference sometimes.</p>\n<h6 id=\"berry-d-function-bur12\" style=\"position:relative;\"><a href=\"#berry-d-function-bur12\" aria-label=\"berry d function bur12 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Berry <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>D</mi></mrow><annotation encoding=\"application/x-tex\">D</annotation></semantics></math></span></span> function [Bur12]</h6>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>D</mi><mrow><mi>B</mi><mi>e</mi><mi>r</mi><mi>r</mi><mi>y</mi></mrow></msub><mo>=</mo><mfrac><mi>c</mi><mrow><mo stretchy=\"false\">(</mo><mo stretchy=\"false\">(</mo><mi>n</mi><mo separator=\"true\">⋅</mo><mi>h</mi><msup><mo stretchy=\"false\">)</mo><mn>2</mn></msup><mo stretchy=\"false\">(</mo><msup><mi>α</mi><mn>2</mn></msup><mo>−</mo><mn>1</mn><mo stretchy=\"false\">)</mo><mo>+</mo><mn>1</mn><mo stretchy=\"false\">)</mo></mrow></mfrac></mrow><annotation encoding=\"application/x-tex\">D_{Berry}=\\frac{c}{((n·h)^2(\\alpha^2-1)+1)}</annotation></semantics></math></span></span></p>\n<h6 id=\"ggxtrowbridge-reitz-d-function-bur12\" style=\"position:relative;\"><a href=\"#ggxtrowbridge-reitz-d-function-bur12\" aria-label=\"ggxtrowbridge reitz d function bur12 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>GGX/Trowbridge-Reitz <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>D</mi></mrow><annotation encoding=\"application/x-tex\">D</annotation></semantics></math></span></span> function [Bur12]</h6>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>D</mi><mrow><mi>T</mi><mi>R</mi></mrow></msub><mo>=</mo><mfrac><mi>c</mi><mrow><mo stretchy=\"false\">(</mo><mo stretchy=\"false\">(</mo><mi>n</mi><mo separator=\"true\">⋅</mo><mi>h</mi><msup><mo stretchy=\"false\">)</mo><mn>2</mn></msup><mo stretchy=\"false\">(</mo><msup><mi>α</mi><mn>2</mn></msup><mo>−</mo><mn>1</mn><mo stretchy=\"false\">)</mo><mo>+</mo><mn>1</mn><msup><mo stretchy=\"false\">)</mo><mn>2</mn></msup></mrow></mfrac></mrow><annotation encoding=\"application/x-tex\">D_{TR}=\\frac{c}{((n·h)^2(\\alpha^2-1)+1)^2}</annotation></semantics></math></span></span></p>\n<h6 id=\"generalized-ggxtrowbridge-reitz-d-function-bur12\" style=\"position:relative;\"><a href=\"#generalized-ggxtrowbridge-reitz-d-function-bur12\" aria-label=\"generalized ggxtrowbridge reitz d function bur12 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Generalized GGX/Trowbridge-Reitz <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>D</mi></mrow><annotation encoding=\"application/x-tex\">D</annotation></semantics></math></span></span> function [Bur12]</h6>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>D</mi><mrow><mi>G</mi><mi>T</mi><mi>R</mi></mrow></msub><mo>=</mo><mfrac><mi>c</mi><mrow><mo stretchy=\"false\">(</mo><mo stretchy=\"false\">(</mo><mi>n</mi><mo separator=\"true\">⋅</mo><mi>h</mi><msup><mo stretchy=\"false\">)</mo><mn>2</mn></msup><mo stretchy=\"false\">(</mo><msup><mi>α</mi><mn>2</mn></msup><mo>−</mo><mn>1</mn><mo stretchy=\"false\">)</mo><mo>+</mo><mn>1</mn><msup><mo stretchy=\"false\">)</mo><mi>γ</mi></msup></mrow></mfrac></mrow><annotation encoding=\"application/x-tex\">D_{GTR}=\\frac{c}{((n·h)^2(\\alpha^2-1)+1)^\\gamma}</annotation></semantics></math></span></span></p>\n<p>For these three <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>D</mi></mrow><annotation encoding=\"application/x-tex\">D</annotation></semantics></math></span></span> functions, <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>c</mi></mrow><annotation encoding=\"application/x-tex\">c</annotation></semantics></math></span></span> is an optional scaling factor, <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>α</mi></mrow><annotation encoding=\"application/x-tex\">\\alpha</annotation></semantics></math></span></span> is the roughness, <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>γ</mi></mrow><annotation encoding=\"application/x-tex\">\\gamma</annotation></semantics></math></span></span> is an optional exponential factor. If we choose <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>γ</mi><mo>=</mo><mn>10</mn></mrow><annotation encoding=\"application/x-tex\">\\gamma=10</annotation></semantics></math></span></span> it is fairly close to the Beckmann <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>D</mi></mrow><annotation encoding=\"application/x-tex\">D</annotation></semantics></math></span></span> function. They are most commonly used <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>D</mi></mrow><annotation encoding=\"application/x-tex\">D</annotation></semantics></math></span></span> functions as far as I know, gives a “long-tailed” visual appearance.</p>\n<h5 id=\"g-function\" style=\"position:relative;\"><a href=\"#g-function\" aria-label=\"g function permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>G</mi></mrow><annotation encoding=\"application/x-tex\">G</annotation></semantics></math></span></span> function</h5>\n<h6 id=\"cook-torrance-g-function-ct82\" style=\"position:relative;\"><a href=\"#cook-torrance-g-function-ct82\" aria-label=\"cook torrance g function ct82 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Cook-Torrance <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>G</mi></mrow><annotation encoding=\"application/x-tex\">G</annotation></semantics></math></span></span> function [CT82]</h6>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>G</mi><mrow><mi>c</mi><mi>o</mi><mi>o</mi><mi>k</mi><mo>−</mo><mi>t</mi><mi>o</mi><mi>r</mi><mi>r</mi><mi>a</mi><mi>n</mi><mi>c</mi><mi>e</mi></mrow></msub><mo>=</mo><mi>min</mi><mo>⁡</mo><mo stretchy=\"false\">{</mo><mn>1</mn><mo separator=\"true\">,</mo><mfrac><mrow><mn>2</mn><mo stretchy=\"false\">(</mo><mi>n</mi><mo separator=\"true\">⋅</mo><mi>h</mi><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">(</mo><mi>n</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo></mrow><mrow><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>o</mi></msub><mo separator=\"true\">⋅</mo><mi>h</mi><mo stretchy=\"false\">)</mo></mrow></mfrac><mo separator=\"true\">,</mo><mfrac><mrow><mn>2</mn><mo stretchy=\"false\">(</mo><mi>n</mi><mo separator=\"true\">⋅</mo><mi>h</mi><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">(</mo><mi>n</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>i</mi></msub><mo stretchy=\"false\">)</mo></mrow><mrow><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>o</mi></msub><mo separator=\"true\">⋅</mo><mi>h</mi><mo stretchy=\"false\">)</mo></mrow></mfrac><mo stretchy=\"false\">}</mo></mrow><annotation encoding=\"application/x-tex\">G_{cook-torrance} = \\min\\{1,\\frac{2(n·h)(n·\\omega_o)}{(\\omega_o·h)},\\frac{2(n·h)(n·\\omega_i)}{(\\omega_o·h)}\\}</annotation></semantics></math></span></span></p>\n<p>This one comes from the original paper itself but I haven’t seen it in any product level shader yet since it could be deduced to other more optimal versions.</p>\n<h6 id=\"smith-g-function-smith67-hei14\" style=\"position:relative;\"><a href=\"#smith-g-function-smith67-hei14\" aria-label=\"smith g function smith67 hei14 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Smith <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>G</mi></mrow><annotation encoding=\"application/x-tex\">G</annotation></semantics></math></span></span> function [Smith67] [Hei14]</h6>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>G</mi><mrow><mi>S</mi><mi>m</mi><mi>i</mi><mi>t</mi><mi>h</mi></mrow></msub><mo>=</mo><mfrac><mrow><msup><mi>χ</mi><mo>+</mo></msup><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>o</mi></msub><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>m</mi></msub><mo stretchy=\"false\">)</mo></mrow><mrow><mn>1</mn><mo>+</mo><mi mathvariant=\"normal\">Λ</mi><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo></mrow></mfrac></mrow><annotation encoding=\"application/x-tex\">G_{Smith}=\\frac{\\chi^+(\\omega_o·\\omega_m)}{1 + \\Lambda(\\omega_o)}</annotation></semantics></math></span></span></p>\n<p>The original paper is not publicly available, so I list the deduced version from a later reference. Here the nominator <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msup><mi>χ</mi><mo>+</mo></msup><mo stretchy=\"false\">(</mo><mi>u</mi><mo stretchy=\"false\">)</mo></mrow><annotation encoding=\"application/x-tex\">\\chi^+(u)</annotation></semantics></math></span></span> is a heavy-side function, when <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>u</mi><mo>></mo><mn>0</mn></mrow><annotation encoding=\"application/x-tex\">u>0</annotation></semantics></math></span></span> then <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msup><mi>χ</mi><mo>+</mo></msup><mo stretchy=\"false\">(</mo><mi>u</mi><mo stretchy=\"false\">)</mo><mo>=</mo><mn>1</mn></mrow><annotation encoding=\"application/x-tex\">\\chi^+(u)=1</annotation></semantics></math></span></span>, otherwise <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msup><mi>χ</mi><mo>+</mo></msup><mo stretchy=\"false\">(</mo><mi>u</mi><mo stretchy=\"false\">)</mo><mo>=</mo><mn>0</mn></mrow><annotation encoding=\"application/x-tex\">\\chi^+(u)=0</annotation></semantics></math></span></span>, it ensures the sidedness effect, while the <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi mathvariant=\"normal\">Λ</mi><mo stretchy=\"false\">(</mo><mo stretchy=\"false\">)</mo></mrow><annotation encoding=\"application/x-tex\">\\Lambda()</annotation></semantics></math></span></span> function is an integral over the slopes of the microsurface, which gives the masking probability. So, unless we provide a possible <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi mathvariant=\"normal\">Λ</mi><mo stretchy=\"false\">(</mo><mo stretchy=\"false\">)</mo></mrow><annotation encoding=\"application/x-tex\">\\Lambda()</annotation></semantics></math></span></span> function, this formula can’t be translated to a shader.</p>\n<h6 id=\"schlick-g-function-sch94\" style=\"position:relative;\"><a href=\"#schlick-g-function-sch94\" aria-label=\"schlick g function sch94 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Schlick <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>G</mi></mrow><annotation encoding=\"application/x-tex\">G</annotation></semantics></math></span></span> function [Sch94]</h6>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>G</mi><mrow><mi>S</mi><mi>c</mi><mi>h</mi><mi>l</mi><mi>i</mi><mi>c</mi><mi>k</mi></mrow></msub><mo>=</mo><mfrac><mrow><mi>n</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>o</mi></msub></mrow><mrow><mo stretchy=\"false\">(</mo><mi>n</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">(</mo><mn>1</mn><mo>−</mo><mi>k</mi><mo stretchy=\"false\">)</mo><mo>+</mo><mi>k</mi></mrow></mfrac><mo separator=\"true\">⋅</mo><mfrac><mrow><mi>n</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>i</mi></msub></mrow><mrow><mo stretchy=\"false\">(</mo><mi>n</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>i</mi></msub><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">(</mo><mn>1</mn><mo>−</mo><mi>k</mi><mo stretchy=\"false\">)</mo><mo>+</mo><mi>k</mi></mrow></mfrac></mrow><annotation encoding=\"application/x-tex\">G_{Schlick}=\\frac{n·\\omega_o}{(n·\\omega_o)(1-k)+k}·\\frac{n·\\omega_i}{(n·\\omega_i)(1-k)+k}</annotation></semantics></math></span></span></p>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>k</mi></mrow><annotation encoding=\"application/x-tex\">k</annotation></semantics></math></span></span> is the user-controlled roughness, in practice we could remapping roughness to <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>α</mi><mo>=</mo><mfrac><mrow><mi>R</mi><mi>o</mi><mi>u</mi><mi>g</mi><mi>h</mi><mi>n</mi><mi>e</mi><mi>s</mi><mi>s</mi><mn>1</mn></mrow><mn>2</mn></mfrac></mrow><annotation encoding=\"application/x-tex\">\\alpha=\\frac{Roughness 1}{2}</annotation></semantics></math></span></span> [Bur12], <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>k</mi><mo>=</mo><msup><mi>α</mi><mn>2</mn></msup><mi mathvariant=\"normal\">/</mi><mn>2</mn></mrow><annotation encoding=\"application/x-tex\">k=\\alpha^2/2</annotation></semantics></math></span></span> [Kar13] to get a better non-linearity result. Schlick <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>G</mi></mrow><annotation encoding=\"application/x-tex\">G</annotation></semantics></math></span></span> function is the approximation of Smith <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>G</mi></mrow><annotation encoding=\"application/x-tex\">G</annotation></semantics></math></span></span> function in <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mo stretchy=\"false\">[</mo><mtext> </mtext><mn>0</mn><mo separator=\"true\">,</mo><mn>1</mn><mo stretchy=\"false\">]</mo><mtext> </mtext></mrow><annotation encoding=\"application/x-tex\">[ \\,0,1] \\,</annotation></semantics></math></span></span>, which is kind friendly for our application scene because its parameter requirement is acceptable.</p>\n<h6 id=\"height-correlated-smith-g-function-hei14-lr14\" style=\"position:relative;\"><a href=\"#height-correlated-smith-g-function-hei14-lr14\" aria-label=\"height correlated smith g function hei14 lr14 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Height correlated Smith <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>G</mi></mrow><annotation encoding=\"application/x-tex\">G</annotation></semantics></math></span></span> function [Hei14] [LR14]</h6>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>G</mi><mrow><mi>C</mi><mi>o</mi><mi>r</mi><mi>r</mi><mi>e</mi><mi>l</mi><mi>a</mi><mi>t</mi><mi>e</mi><mi>d</mi><mi>S</mi><mi>c</mi><mi>h</mi><mi>l</mi><mi>i</mi><mi>c</mi><mi>k</mi></mrow></msub><mo>=</mo><mfrac><mrow><msup><mi>χ</mi><mo>+</mo></msup><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>o</mi></msub><mo separator=\"true\">⋅</mo><mi>h</mi><mo stretchy=\"false\">)</mo><msup><mi>χ</mi><mo>+</mo></msup><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">⋅</mo><mi>h</mi><mo stretchy=\"false\">)</mo></mrow><mrow><mn>1</mn><mo>+</mo><mi mathvariant=\"normal\">Λ</mi><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo><mo>+</mo><mi mathvariant=\"normal\">Λ</mi><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>i</mi></msub><mo stretchy=\"false\">)</mo></mrow></mfrac></mrow><annotation encoding=\"application/x-tex\">G_{CorrelatedSchlick}=\\frac{\\chi^+(\\omega_o·h)\\chi^+(\\omega_i·h)}{1+\\Lambda(\\omega_o)+\\Lambda(\\omega_i)}</annotation></semantics></math></span></span></p>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi mathvariant=\"normal\">Λ</mi><mo stretchy=\"false\">(</mo><mi>m</mi><mo stretchy=\"false\">)</mo><mo>=</mo><mfrac><mrow><mo>−</mo><mn>1</mn><mo>+</mo><msqrt><mrow><mn>1</mn><mo>+</mo><msup><mi>α</mi><mn>2</mn></msup><msup><mrow><mi>tan</mi><mo>⁡</mo></mrow><mn>2</mn></msup><mo stretchy=\"false\">(</mo><msub><mi>θ</mi><mi>m</mi></msub><mo stretchy=\"false\">)</mo></mrow></msqrt></mrow><mn>2</mn></mfrac><mo>=</mo><mfrac><mrow><mo>−</mo><mn>1</mn><mo>+</mo><msqrt><mrow><mn>1</mn><mo>+</mo><mfrac><mrow><msup><mi>α</mi><mn>2</mn></msup><mo stretchy=\"false\">(</mo><mn>1</mn><mo>−</mo><msup><mrow><mi>cos</mi><mo>⁡</mo></mrow><mn>2</mn></msup><mo stretchy=\"false\">(</mo><msub><mi>θ</mi><mi>m</mi></msub><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">)</mo></mrow><mrow><msup><mrow><mi>cos</mi><mo>⁡</mo></mrow><mn>2</mn></msup><mo stretchy=\"false\">(</mo><msub><mi>θ</mi><mi>m</mi></msub><mo stretchy=\"false\">)</mo></mrow></mfrac></mrow></msqrt></mrow><mn>2</mn></mfrac></mrow><annotation encoding=\"application/x-tex\">\\Lambda(m)=\\frac{-1+\\sqrt{1+\\alpha^2\\tan^2(\\theta_m)}}{2}=\\frac{-1+\\sqrt{1+\\frac{\\alpha^2(1-\\cos^2(\\theta_m))}{\\cos^2(\\theta_m)}}}{2}</annotation></semantics></math></span></span>, because the microfacet would mask and shadow at the same time, then if we correlate the masking and shadowing parts with the respect of its height would bring some energy loss back. The detailed deduction is math heavily, I’d recommend reading the corresponding papers for further understanding.</p>\n<h6 id=\"multi-scattering-smith-g-function-hhed16\" style=\"position:relative;\"><a href=\"#multi-scattering-smith-g-function-hhed16\" aria-label=\"multi scattering smith g function hhed16 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Multi-scattering Smith <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>G</mi></mrow><annotation encoding=\"application/x-tex\">G</annotation></semantics></math></span></span> function [HHED16]</h6>\n<p>All of the <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>G</mi></mrow><annotation encoding=\"application/x-tex\">G</annotation></semantics></math></span></span> functions I listed above only take care of a single-scattering phenomenon, while in reality, the rougher surface would have more possibility to bounce light around different microfacets, it’s important to count these part of the energy. The paper [HHED16] gives a stochastic method based ground truth, and later [IW17] gives an implementable compensation way to achieve it, an alternative version of the general formula is given by <span style=\"color: #ff9800; background-color: rgba(255 , 152 , 0 , 0.1); border: 0; padding-top: 2px; padding-right: 4px; padding-bottom: 2px; padding-left: 4px;\">the book</span> as:</p>\n<blockquote>\n<p>“… <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mrow><mi>m</mi><mi>s</mi></mrow></msub><mo stretchy=\"false\">(</mo><mi>l</mi><mo separator=\"true\">,</mo><mi>v</mi><mo stretchy=\"false\">)</mo><mo>=</mo><mfrac><mrow><mover accent=\"true\"><mi>F</mi><mo stretchy=\"true\">‾</mo></mover><mover accent=\"true\"><mrow><mi>R</mi><msub><mi>s</mi><msub><mi>F</mi><mn>1</mn></msub></msub></mrow><mo stretchy=\"true\">‾</mo></mover></mrow><mrow><mi>π</mi><mo stretchy=\"false\">(</mo><mn>1</mn><mo>−</mo><mover accent=\"true\"><mrow><mi>R</mi><msub><mi>s</mi><msub><mi>F</mi><mn>1</mn></msub></msub></mrow><mo stretchy=\"true\">‾</mo></mover><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">(</mo><mn>1</mn><mo>−</mo><mover accent=\"true\"><mi>F</mi><mo stretchy=\"true\">‾</mo></mover><mo stretchy=\"false\">(</mo><mn>1</mn><mo>−</mo><mover accent=\"true\"><mrow><mi>R</mi><msub><mi>s</mi><msub><mi>F</mi><mn>1</mn></msub></msub></mrow><mo stretchy=\"true\">‾</mo></mover><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">)</mo></mrow></mfrac><mo stretchy=\"false\">(</mo><mn>1</mn><mo>−</mo><mi>R</mi><msub><mi>s</mi><msub><mi>F</mi><mn>1</mn></msub></msub><mo stretchy=\"false\">(</mo><mi>l</mi><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">(</mo><mn>1</mn><mo>−</mo><mi>R</mi><msub><mi>s</mi><msub><mi>F</mi><mn>1</mn></msub></msub><mo stretchy=\"false\">(</mo><mi>v</mi><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">)</mo></mrow><annotation encoding=\"application/x-tex\">f_{ms}(l, v) = \\frac{\\overline F \\overline {Rs_{F_1}}}{\\pi(1-\\overline {Rs_{F_1}})(1-\\overline F(1-\\overline {Rs_{F_1}}))}(1-Rs_{F_1}(l))(1-Rs_{F_1}(v))</annotation></semantics></math></span></span> …” - pg. 346, ”<strong>Real-Time Rendering</strong>”, 4th Edition.</p>\n</blockquote>\n<p>Let’s start to decompose this formula from the <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>F</mi></mrow><annotation encoding=\"application/x-tex\">F</annotation></semantics></math></span></span> Fresnel function. As we discussed before, the Snell’s law could give us the direction of the transmitted light, and the ideal mirror reflection could give us the reflected light direction, but we don’t know how much energy is reflected and how much is transmitted, this is quite an annoy problem. But luckily it has been solved (with some restricted conditions) already in 19th century by French scientist Augustin-Jean Fresnel as <a href=\"https://en.wikipedia.org/wiki/Fresnel_equations#Power_(intensity)_reflection_and_transmission_coefficients\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Fresnel equations</a>. Long talk in short, since we only care about the ideal sandbox in our real-time compensations, we would look for a <em>nice</em> enough Fresnel function to simulate this phenomenon. The Schlick Fresnel approximation is widely adopted nowadays, it’s has a form as <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>F</mi><mrow><mi>S</mi><mi>c</mi><mi>h</mi><mi>l</mi><mi>i</mi><mi>c</mi><mi>k</mi></mrow></msub><mo>=</mo><msub><mi>F</mi><mn>0</mn></msub><mo>+</mo><mo stretchy=\"false\">(</mo><msub><mi>F</mi><mn>90</mn></msub><mo>−</mo><msub><mi>F</mi><mn>0</mn></msub><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">(</mo><mn>1</mn><mo>−</mo><mo stretchy=\"false\">(</mo><mi>cos</mi><mo>⁡</mo><mi>θ</mi><mo stretchy=\"false\">)</mo><msup><mo stretchy=\"false\">)</mo><mn>5</mn></msup><mo stretchy=\"false\">)</mo></mrow><annotation encoding=\"application/x-tex\">F_{Schlick}=F_0 + (F_{90} - F_0)(1-(\\cos\\theta))^5)</annotation></semantics></math></span></span>, <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>F</mi><mn>0</mn></msub></mrow><annotation encoding=\"application/x-tex\">F_0</annotation></semantics></math></span></span> is the specular reflectance from normal incidence, it represents the IOR when the view direction is perpendicular with the surface as <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>ω</mi><mi>o</mi></msub><mo>∥</mo><mi>n</mi></mrow><annotation encoding=\"application/x-tex\">\\omega_o \\parallel n</annotation></semantics></math></span></span>; similar <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>F</mi><mn>90</mn></msub></mrow><annotation encoding=\"application/x-tex\">F_{90}</annotation></semantics></math></span></span> is the IOR when <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>ω</mi><mi>o</mi></msub><mo>⊥</mo><mi>n</mi></mrow><annotation encoding=\"application/x-tex\">\\omega_o \\perp n</annotation></semantics></math></span></span>, some of the implementations would assume <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>F</mi><mn>90</mn></msub></mrow><annotation encoding=\"application/x-tex\">F_{90}</annotation></semantics></math></span></span> is always 1, and it could cover most of common conductor/dielectric materials type. Finally <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>cos</mi><mo>⁡</mo><mi>θ</mi><mo>=</mo><mi>n</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>o</mi></msub></mrow><annotation encoding=\"application/x-tex\">\\cos\\theta=n·\\omega_o</annotation></semantics></math></span></span> or <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>cos</mi><mo>⁡</mo><mi>θ</mi><mo>=</mo><mi>n</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>i</mi></msub></mrow><annotation encoding=\"application/x-tex\">\\cos\\theta=n·\\omega_i</annotation></semantics></math></span></span>, it’s another kind of cosine-weighted contribution appears here.</p>\n<p>The <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mover accent=\"true\"><mi>F</mi><mo stretchy=\"true\">‾</mo></mover></mrow><annotation encoding=\"application/x-tex\">\\overline F</annotation></semantics></math></span></span> here means the average of <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>F</mi></mrow><annotation encoding=\"application/x-tex\">F</annotation></semantics></math></span></span> over all the different cosine of angles, if we just use the Schlick Fresnel approximation mentioned above, it could simply be calculated as <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mover accent=\"true\"><mi>F</mi><mo stretchy=\"true\">‾</mo></mover><mo>=</mo><mfrac><mn>20</mn><mn>21</mn></mfrac><msub><mi>F</mi><mn>0</mn></msub><mo>+</mo><mfrac><mn>1</mn><mn>21</mn></mfrac></mrow><annotation encoding=\"application/x-tex\">\\overline F = \\frac{20}{21}F_0 + \\frac{1}{21}</annotation></semantics></math></span></span>.</p>\n<p>Then we’d move on to another average, <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>R</mi><msub><mi>s</mi><msub><mi>F</mi><mn>1</mn></msub></msub></mrow><annotation encoding=\"application/x-tex\">Rs_{F_1}</annotation></semantics></math></span></span>, it <span style=\"color: #ff9800; background-color: rgba(255 , 152 , 0 , 0.1); border: 0; padding-top: 2px; padding-right: 4px; padding-bottom: 2px; padding-left: 4px;\">is the directional albedo of <span><span style=\"color: inherit;\"></span><span style=\"font-size: 100%; display: inline-block;\"><img style=\"vertical-align: middle; max-width: 100%; height: auto; border: 0;\" src=\"https://app.yinxiang.com/shard/s18/res/c89eec6f-bd51-4fe0-bc07-21906cdeda4c/595706026c587d25181c842682d01717.png\" name=\"c89eec6f-bd51-4fe0-bc07-21906cdeda4c\" class=\"en-media\"></span></span>, which is the specular BRDF term with <span><span style=\"color: inherit;\"></span><span style=\"font-size: 100%; display: inline-block;\"><img style=\"vertical-align: middle; max-width: 100%; height: auto; border: 0;\" src=\"https://app.yinxiang.com/shard/s18/res/3f5925c5-2fe3-4448-a6e6-51aa94e2c765/0e48ccc96cd4ee189aa913fbfa33e9d4.png\" name=\"3f5925c5-2fe3-4448-a6e6-51aa94e2c765\" class=\"en-media\"></span></span> set to 1</span>, which could be interpreted as the irradiance of a pure <em>white</em> surface when illuminated by a unit directional light source, and <a href=\"https://blog.selfshadow.com/2018/05/13/multi-faceted-part-1/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Stephen Hill</a> wrote a nice blog series about it. Basically, if we could implement the single-scattering BRDF, then could just use some discrete numerical integral method (like Importance sampling) to calculate it and save it to a look-up table, which exactly similar like what the split-summing technique of IBL applicated in [Kar13].</p>\n<h4 id=\"use-simple-lambert-model-as-the-microfacet-brdf-in-cook-torrance-model-lr14\" style=\"position:relative;\"><a href=\"#use-simple-lambert-model-as-the-microfacet-brdf-in-cook-torrance-model-lr14\" aria-label=\"use simple lambert model as the microfacet brdf in cook torrance model lr14 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Use Simple Lambert model as the microfacet BRDF in Cook-Torrance model [LR14]</h4>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mi>m</mi></msub><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>o</mi></msub><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">,</mo><mi>m</mi><mo stretchy=\"false\">)</mo><mo>=</mo><msub><mi>f</mi><mrow><mi>L</mi><mi>a</mi><mi>m</mi><mi>b</mi><mi>e</mi><mi>r</mi><mi>t</mi></mrow></msub><mo>=</mo><mfrac><mi>ρ</mi><mi>π</mi></mfrac></mrow><annotation encoding=\"application/x-tex\">f_m(\\omega_o,\\omega_i,m) = f_{Lambert} = \\frac{\\rho} {\\pi}</annotation></semantics></math></span></span> and then <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mrow><mi>c</mi><mi>o</mi><mi>o</mi><mi>k</mi><mo>−</mo><mi>t</mi><mi>o</mi><mi>r</mi><mi>r</mi><mi>a</mi><mi>n</mi><mi>c</mi><mi>e</mi></mrow></msub><mo>=</mo><mfrac><mi>ρ</mi><mi>π</mi></mfrac><mfrac><mn>1</mn><mrow><mi mathvariant=\"normal\">∣</mi><mi>n</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>o</mi></msub><mi mathvariant=\"normal\">∣</mi><mi mathvariant=\"normal\">∣</mi><mi>n</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>i</mi></msub><mi mathvariant=\"normal\">∣</mi></mrow></mfrac><munder><mo>∫</mo><mi mathvariant=\"normal\">Ω</mi></munder><mi>G</mi><mo stretchy=\"false\">(</mo><mi>v</mi><mo separator=\"true\">,</mo><mi>l</mi><mo separator=\"true\">,</mo><mi>m</mi><mo stretchy=\"false\">)</mo><mi>D</mi><mo stretchy=\"false\">(</mo><mi>m</mi><mo separator=\"true\">,</mo><mi>α</mi><mo stretchy=\"false\">)</mo><mi>max</mi><mo>⁡</mo><mo stretchy=\"false\">(</mo><mn>0</mn><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>o</mi></msub><mo separator=\"true\">⋅</mo><mi>m</mi><mo stretchy=\"false\">)</mo><mi>max</mi><mo>⁡</mo><mo stretchy=\"false\">(</mo><mn>0</mn><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">⋅</mo><mi>m</mi><mo stretchy=\"false\">)</mo><mi>d</mi><mi>m</mi></mrow><annotation encoding=\"application/x-tex\">f_{cook-torrance}=\\frac{\\rho}{\\pi}\\frac{1}{|n·\\omega_o||n·\\omega_i|}\\int\\limits_{\\Omega}G(v,l,m) D(m,\\alpha)\\max(0,\\omega_o·m)\\max(0,\\omega_i·m)dm</annotation></semantics></math></span></span></p>\n<p>Still, no analysis solution, but gives a theoretical fundamental about the problem we need to solve, and unified all the problem inside one microsurface theory.</p>\n<h4 id=\"oren-nayar-model-on94\" style=\"position:relative;\"><a href=\"#oren-nayar-model-on94\" aria-label=\"oren nayar model on94 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Oren-Nayar model [ON94]</h4>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mrow><mi>o</mi><mi>r</mi><mi>e</mi><mi>n</mi><mo>−</mo><mi>n</mi><mi>a</mi><mi>y</mi><mi>a</mi><mi>r</mi></mrow></msub><mo>=</mo><mfrac><mi>ρ</mi><mi>π</mi></mfrac><mo stretchy=\"false\">(</mo><mi>A</mi><mo>+</mo><mo stretchy=\"false\">(</mo><mi>B</mi><mo separator=\"true\">⋅</mo><mi>max</mi><mo>⁡</mo><mo stretchy=\"false\">(</mo><mn>0</mn><mo separator=\"true\">,</mo><mi>cos</mi><mo>⁡</mo><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>i</mi></msub><mo>−</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">)</mo><mo separator=\"true\">⋅</mo><mi>sin</mi><mo>⁡</mo><mo stretchy=\"false\">(</mo><mi>max</mi><mo>⁡</mo><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">)</mo><mo separator=\"true\">⋅</mo><mi>t</mi><mi>a</mi><mi>n</mi><mo stretchy=\"false\">(</mo><mi>min</mi><mo>⁡</mo><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">)</mo></mrow><annotation encoding=\"application/x-tex\">f_{oren-nayar}=\\frac{\\rho} {\\pi}(A+(B·\\max(0, \\cos (\\omega_i - \\omega_o))·\\sin(\\max(\\omega_i, \\omega_o))·tan(\\min(\\omega_i,\\omega_o))))</annotation></semantics></math></span></span>\n<span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>A</mi><mo>=</mo><mn>1</mn><mo>−</mo><mfrac><mi>α</mi><mrow><mn>2</mn><mi>α</mi><mo>+</mo><mn>0.66</mn></mrow></mfrac></mrow><annotation encoding=\"application/x-tex\">A=1-\\frac{\\alpha}{2\\alpha+0.66}</annotation></semantics></math></span></span>, <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>B</mi><mo>=</mo><mn>0.45</mn><mfrac><mi>α</mi><mrow><mi>α</mi><mo>+</mo><mn>0.09</mn></mrow></mfrac></mrow><annotation encoding=\"application/x-tex\">B=0.45\\frac{\\alpha}{\\alpha+0.09}</annotation></semantics></math></span></span> and <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>α</mi></mrow><annotation encoding=\"application/x-tex\">\\alpha</annotation></semantics></math></span></span> is the roughness, it’s an approximation of the general Cook-Torrance model, when <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>α</mi><mo>=</mo><mn>0</mn></mrow><annotation encoding=\"application/x-tex\">\\alpha = 0</annotation></semantics></math></span></span> we’ll get the Simple Lambert model. Could treat Oren-Nayar model as a kind of generalization of Simple Lambert model.</p>\n<h4 id=\"disney-model-bur12\" style=\"position:relative;\"><a href=\"#disney-model-bur12\" aria-label=\"disney model bur12 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Disney model [Bur12]</h4>\n<p>Another advanced Lambert-based diffuse model which considers about Fresnel effect, <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mrow><mi>d</mi><mi>i</mi><mi>s</mi><mi>n</mi><mi>e</mi><mi>y</mi></mrow></msub><mo>=</mo><mfrac><mi>ρ</mi><mi>π</mi></mfrac><mo stretchy=\"false\">(</mo><mn>1</mn><mo>+</mo><mo stretchy=\"false\">(</mo><msub><mi>F</mi><mrow><mi>d</mi><mn>90</mn></mrow></msub><mo>−</mo><mn>1</mn><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">(</mo><mn>1</mn><mo>−</mo><mo stretchy=\"false\">(</mo><mi>n</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>i</mi></msub><mo stretchy=\"false\">)</mo><msup><mo stretchy=\"false\">)</mo><mn>5</mn></msup><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">(</mo><mn>1</mn><mo>+</mo><mo stretchy=\"false\">(</mo><msub><mi>F</mi><mrow><mi>d</mi><mn>90</mn></mrow></msub><mo>−</mo><mn>1</mn><mo stretchy=\"false\">)</mo><mo stretchy=\"false\">(</mo><mn>1</mn><mo>−</mo><mo stretchy=\"false\">(</mo><mi>n</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo><msup><mo stretchy=\"false\">)</mo><mn>5</mn></msup><mo stretchy=\"false\">)</mo></mrow><annotation encoding=\"application/x-tex\">f_{disney}=\\frac{\\rho} {\\pi}(1+(F_{d90}-1)(1-(n · \\omega_i))^5)(1+(F_{d90}-1)(1-(n · \\omega_o))^5)</annotation></semantics></math></span></span>,\nor written as <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mrow><mi>D</mi><mi>i</mi><mi>s</mi><mi>n</mi><mi>e</mi><mi>y</mi></mrow></msub><mo>=</mo><mfrac><mi>ρ</mi><mi>π</mi></mfrac><msub><mi>F</mi><mrow><mi>S</mi><mi>c</mi><mi>h</mi><mi>l</mi><mi>i</mi><mi>c</mi><mi>k</mi></mrow></msub><mo stretchy=\"false\">(</mo><mn>1</mn><mo separator=\"true\">,</mo><msub><mi>F</mi><mrow><mi>d</mi><mn>90</mn></mrow></msub><mo separator=\"true\">,</mo><mi>n</mi><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo><mo separator=\"true\">⋅</mo><msub><mi>F</mi><mrow><mi>S</mi><mi>c</mi><mi>h</mi><mi>l</mi><mi>i</mi><mi>c</mi><mi>k</mi></mrow></msub><mo stretchy=\"false\">(</mo><mn>1</mn><mo separator=\"true\">,</mo><msub><mi>F</mi><mrow><mi>d</mi><mn>90</mn></mrow></msub><mo separator=\"true\">,</mo><mi>n</mi><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>i</mi></msub><mo stretchy=\"false\">)</mo></mrow><annotation encoding=\"application/x-tex\">f_{Disney}=\\frac{\\rho} {\\pi}F_{Schlick}(1, F_{d90}, n, \\omega_o)·F_{Schlick}(1, F_{d90}, n, \\omega_i)</annotation></semantics></math></span></span>, here <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>F</mi><mrow><mi>d</mi><mn>90</mn></mrow></msub><mo>=</mo><mn>0.5</mn><mo>+</mo><mn>2</mn><mo stretchy=\"false\">(</mo><mi>h</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>i</mi></msub><msup><mo stretchy=\"false\">)</mo><mn>2</mn></msup><mi>α</mi></mrow><annotation encoding=\"application/x-tex\">F_{d90}=0.5+2(h·\\omega_i)^2\\alpha</annotation></semantics></math></span></span>, <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>α</mi></mrow><annotation encoding=\"application/x-tex\">\\alpha</annotation></semantics></math></span></span> is roughness.</p>\n<h4 id=\"normalized-disney-model-lr14\" style=\"position:relative;\"><a href=\"#normalized-disney-model-lr14\" aria-label=\"normalized disney model lr14 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Normalized Disney model [LR14]</h4>\n<p>For the sake of energy conservation, we could remapping the original Disney model to <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mo stretchy=\"false\">[</mo><mtext> </mtext><mn>0</mn><mo separator=\"true\">,</mo><mn>1</mn><mo stretchy=\"false\">]</mo><mtext> </mtext></mrow><annotation encoding=\"application/x-tex\">[ \\,0,1] \\,</annotation></semantics></math></span></span>, then <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mrow><mi>n</mi><mi>o</mi><mi>r</mi><mi>m</mi><mi>a</mi><mi>l</mi><mi>i</mi><mi>z</mi><mi>e</mi><mi>d</mi><mi>D</mi><mi>i</mi><mi>s</mi><mi>n</mi><mi>e</mi><mi>y</mi></mrow></msub><mo>=</mo><mi>c</mi><mo separator=\"true\">⋅</mo><mfrac><mi>ρ</mi><mi>π</mi></mfrac><msub><mi>F</mi><mrow><mi>S</mi><mi>c</mi><mi>h</mi><mi>l</mi><mi>i</mi><mi>c</mi><mi>k</mi></mrow></msub><mo stretchy=\"false\">(</mo><mn>1</mn><mo separator=\"true\">,</mo><msub><mi>F</mi><mrow><mi>d</mi><mn>90</mn></mrow></msub><mo separator=\"true\">,</mo><mi>n</mi><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>o</mi></msub><mo stretchy=\"false\">)</mo><mo separator=\"true\">⋅</mo><msub><mi>F</mi><mrow><mi>S</mi><mi>c</mi><mi>h</mi><mi>l</mi><mi>i</mi><mi>c</mi><mi>k</mi></mrow></msub><mo stretchy=\"false\">(</mo><mn>1</mn><mo separator=\"true\">,</mo><msub><mi>F</mi><mrow><mi>d</mi><mn>90</mn></mrow></msub><mo separator=\"true\">,</mo><mi>n</mi><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>i</mi></msub><mo stretchy=\"false\">)</mo></mrow><annotation encoding=\"application/x-tex\">f_{normalizedDisney}=c·\\frac{\\rho} {\\pi}F_{Schlick}(1, F_{d90}, n, \\omega_o)·F_{Schlick}(1, F_{d90}, n, \\omega_i)</annotation></semantics></math></span></span>, <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>c</mi><mo>=</mo><mfrac><mn>1</mn><mn>1.51</mn></mfrac><mo>+</mo><mfrac><mn>0.51</mn><mn>1.51</mn></mfrac><mi>α</mi></mrow><annotation encoding=\"application/x-tex\">c=\\frac{1}{1.51}+\\frac{0.51}{1.51}\\alpha</annotation></semantics></math></span></span> it’s a scaling factor, I deduced it here for to better compare with the original version, and now <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>F</mi><mrow><mi>d</mi><mn>90</mn></mrow></msub><mo>=</mo><mn>0.5</mn><mo>+</mo><mo stretchy=\"false\">(</mo><mn>2</mn><mo stretchy=\"false\">(</mo><mi>h</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>i</mi></msub><msup><mo stretchy=\"false\">)</mo><mn>2</mn></msup><mo>−</mo><mn>0.5</mn><mo stretchy=\"false\">)</mo><mi>α</mi></mrow><annotation encoding=\"application/x-tex\">F_{d90}=0.5+(2(h·\\omega_i)^2-0.5)\\alpha</annotation></semantics></math></span></span>, <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>α</mi><mo>=</mo><mi>R</mi><mi>o</mi><mi>u</mi><mi>g</mi><mi>h</mi><mi>n</mi><mi>e</mi><mi>s</mi><msup><mi>s</mi><mi>γ</mi></msup></mrow><annotation encoding=\"application/x-tex\">\\alpha=Roughness^\\gamma</annotation></semantics></math></span></span>, in practice the original paper chooses <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>γ</mi><mo>=</mo><mn>2</mn></mrow><annotation encoding=\"application/x-tex\">\\gamma=2</annotation></semantics></math></span></span>, and it find when <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>γ</mi><mo>=</mo><mn>4</mn></mrow><annotation encoding=\"application/x-tex\">\\gamma=4</annotation></semantics></math></span></span> it’s almost near the result in [Sch14] where <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>α</mi><mo>=</mo><mo stretchy=\"false\">(</mo><mn>0.3</mn><mo>+</mo><mn>0.7</mn><mi>R</mi><mi>o</mi><mi>u</mi><mi>g</mi><mi>h</mi><mi>n</mi><mi>e</mi><mi>s</mi><mi>s</mi><msup><mo stretchy=\"false\">)</mo><mn>6</mn></msup></mrow><annotation encoding=\"application/x-tex\">\\alpha=(0.3+0.7Roughness)^6</annotation></semantics></math></span></span>.</p>\n<h3 id=\"specular-part\" style=\"position:relative;\"><a href=\"#specular-part\" aria-label=\"specular part permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Specular part</h3>\n<h4 id=\"phong-model\" style=\"position:relative;\"><a href=\"#phong-model\" aria-label=\"phong model permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Phong model</h4>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mrow><mi>P</mi><mi>h</mi><mi>o</mi><mi>n</mi><mi>g</mi></mrow></msub><mo>=</mo><mo stretchy=\"false\">(</mo><mi>r</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>o</mi></msub><msup><mo stretchy=\"false\">)</mo><mi>α</mi></msup></mrow><annotation encoding=\"application/x-tex\">f_{Phong} = (r·\\omega_o)^\\alpha</annotation></semantics></math></span></span>, <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>r</mi></mrow><annotation encoding=\"application/x-tex\">r</annotation></semantics></math></span></span> is the reflection direction of <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>ω</mi><mi>i</mi></msub></mrow><annotation encoding=\"application/x-tex\">\\omega_i</annotation></semantics></math></span></span>, it’s the most famous and commonly used specular model in last few decades, and even programmed inside the graphics hardware, it needs the exponential factor <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>α</mi></mrow><annotation encoding=\"application/x-tex\">\\alpha</annotation></semantics></math></span></span> as the user-controlled parameter.</p>\n<h4 id=\"normalized-phong-model\" style=\"position:relative;\"><a href=\"#normalized-phong-model\" aria-label=\"normalized phong model permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Normalized Phong model</h4>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mrow><mi>n</mi><mi>o</mi><mi>r</mi><mi>m</mi><mi>a</mi><mi>l</mi><mi>i</mi><mi>z</mi><mi>e</mi><mi>d</mi><mi>P</mi><mi>h</mi><mi>o</mi><mi>n</mi><mi>g</mi></mrow></msub><mo>=</mo><mi>c</mi><mo separator=\"true\">⋅</mo><mo stretchy=\"false\">(</mo><mi>r</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>o</mi></msub><msup><mo stretchy=\"false\">)</mo><mi>α</mi></msup></mrow><annotation encoding=\"application/x-tex\">f_{normalizedPhong} = c·(r·\\omega_o)^\\alpha</annotation></semantics></math></span></span>, <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>c</mi><mo>=</mo><mfrac><mrow><mi>α</mi><mo>+</mo><mn>1</mn></mrow><mrow><mn>2</mn><mi>π</mi></mrow></mfrac></mrow><annotation encoding=\"application/x-tex\">c=\\frac{\\alpha+1}{2\\pi}</annotation></semantics></math></span></span>, actually Phong model gives a <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>D</mi></mrow><annotation encoding=\"application/x-tex\">D</annotation></semantics></math></span></span> function in a microsurface view of point, here <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>α</mi></mrow><annotation encoding=\"application/x-tex\">\\alpha</annotation></semantics></math></span></span> thus could be thought as the roughness.</p>\n<h4 id=\"blinn-phong-model\" style=\"position:relative;\"><a href=\"#blinn-phong-model\" aria-label=\"blinn phong model permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Blinn-Phong model</h4>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mrow><mi>B</mi><mi>l</mi><mi>i</mi><mi>n</mi><mi>n</mi><mo>−</mo><mi>P</mi><mi>h</mi><mi>o</mi><mi>n</mi><mi>g</mi></mrow></msub><mo>=</mo><mo stretchy=\"false\">(</mo><mi>n</mi><mo separator=\"true\">⋅</mo><mi>h</mi><msup><mo stretchy=\"false\">)</mo><mi>α</mi></msup></mrow><annotation encoding=\"application/x-tex\">f_{Blinn-Phong} = (n·h)^\\alpha</annotation></semantics></math></span></span>, an optimization of Phong model, in practice if we choose mapping <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>α</mi><mrow><mi>b</mi><mi>l</mi><mi>i</mi><mi>n</mi><mi>n</mi><mo>−</mo><mi>p</mi><mi>h</mi><mi>o</mi><mi>n</mi><mi>g</mi></mrow></msub><mo>=</mo><mn>4</mn><msub><mi>α</mi><mrow><mi>p</mi><mi>h</mi><mi>o</mi><mi>n</mi><mi>g</mi></mrow></msub></mrow><annotation encoding=\"application/x-tex\">\\alpha_{blinn-phong}=4\\alpha_{phong}</annotation></semantics></math></span></span> then Blinn-Phong model would looks like Phong model [Wiki1].</p>\n<h4 id=\"normalized-blinn-phong-model\" style=\"position:relative;\"><a href=\"#normalized-blinn-phong-model\" aria-label=\"normalized blinn phong model permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Normalized Blinn-Phong model</h4>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mrow><mi>n</mi><mi>o</mi><mi>r</mi><mi>m</mi><mi>a</mi><mi>l</mi><mi>i</mi><mi>z</mi><mi>e</mi><mi>d</mi><mi>B</mi><mi>l</mi><mi>i</mi><mi>n</mi><mi>n</mi><mo>−</mo><mi>P</mi><mi>h</mi><mi>o</mi><mi>n</mi><mi>g</mi></mrow></msub><mo>=</mo><mi>c</mi><mo separator=\"true\">⋅</mo><mo stretchy=\"false\">(</mo><mi>n</mi><mo separator=\"true\">⋅</mo><mi>h</mi><msup><mo stretchy=\"false\">)</mo><mi>α</mi></msup></mrow><annotation encoding=\"application/x-tex\">f_{normalizedBlinn-Phong} = c·(n·h)^\\alpha</annotation></semantics></math></span></span>, <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><mi>c</mi><mo>=</mo><mfrac><mrow><mi>α</mi><mo>+</mo><mn>2</mn></mrow><mrow><mn>4</mn><mi>π</mi><mo stretchy=\"false\">(</mo><mn>2</mn><mo>−</mo><msup><mn>2</mn><mfrac><mrow><mo>−</mo><mi>α</mi></mrow><mn>2</mn></mfrac></msup><mo stretchy=\"false\">)</mo></mrow></mfrac></mrow><annotation encoding=\"application/x-tex\">c=\\frac{\\alpha+2}{4\\pi(2-2^{\\frac{-\\alpha}{2}})}</annotation></semantics></math></span></span>.</p>\n<h4 id=\"cook-torrance-model-ct82-hei14\" style=\"position:relative;\"><a href=\"#cook-torrance-model-ct82-hei14\" aria-label=\"cook torrance model ct82 hei14 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Cook-Torrance model [CT82] [Hei14]</h4>\n<p><span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>f</mi><mrow><mi>c</mi><mi>o</mi><mi>o</mi><mi>k</mi><mo>−</mo><mi>t</mi><mi>o</mi><mi>r</mi><mi>r</mi><mi>a</mi><mi>n</mi><mi>c</mi><mi>e</mi></mrow></msub><mo>=</mo><mfrac><mrow><mi>F</mi><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>o</mi></msub><mo separator=\"true\">,</mo><mi>h</mi><mo separator=\"true\">,</mo><msub><mi>f</mi><mn>0</mn></msub><mo separator=\"true\">,</mo><msub><mi>f</mi><mn>90</mn></msub><mo stretchy=\"false\">)</mo><mi>D</mi><mo stretchy=\"false\">(</mo><mi>h</mi><mo separator=\"true\">,</mo><mi>α</mi><mo stretchy=\"false\">)</mo><mi>G</mi><mo stretchy=\"false\">(</mo><msub><mi>ω</mi><mi>o</mi></msub><mo separator=\"true\">,</mo><msub><mi>ω</mi><mi>i</mi></msub><mo separator=\"true\">,</mo><mi>h</mi><mo stretchy=\"false\">)</mo></mrow><mrow><mn>4</mn><mi mathvariant=\"normal\">∣</mi><mi>n</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>o</mi></msub><mi mathvariant=\"normal\">∣</mi><mi mathvariant=\"normal\">∣</mi><mi>n</mi><mo separator=\"true\">⋅</mo><msub><mi>ω</mi><mi>i</mi></msub><mi mathvariant=\"normal\">∣</mi></mrow></mfrac></mrow><annotation encoding=\"application/x-tex\">f_{cook-torrance} = \\frac{F(\\omega_o, h , f_0, f_{90})D(h, \\alpha)G(\\omega_o, \\omega_i, h)}{4|n·\\omega_o||n·\\omega_i|}</annotation></semantics></math></span></span>, the new kids (popular from ~2012) in town! Everything we’ve talked before, the denominator is deduced from the Jacobian Matrix when we change the space from the microfacet space to macro and makes it’s quite elegant, we use the microfacet theory but calculate in macro!</p>\n<h3 id=\"some-sample-codes\" style=\"position:relative;\"><a href=\"#some-sample-codes\" aria-label=\"some sample codes permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Some sample codes</h3>\n<p>a. Simple Lambert model + Blinn-Phong model</p>\n<div class=\"gatsby-highlight\" data-language=\"glsl\"><pre class=\"language-glsl\"><code class=\"language-glsl\"><span class=\"token keyword\">vec3</span> <span class=\"token function\">CalcDirectionalLight</span><span class=\"token punctuation\">(</span>dirLight light<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> normal<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> diffuse<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> specular<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> viewPos<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> fragPos<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>    \n    <span class=\"token keyword\">vec3</span> N <span class=\"token operator\">=</span> <span class=\"token function\">normalize</span><span class=\"token punctuation\">(</span>normal<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> L <span class=\"token operator\">=</span> <span class=\"token function\">normalize</span><span class=\"token punctuation\">(</span><span class=\"token operator\">-</span>light<span class=\"token punctuation\">.</span>direction<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> V <span class=\"token operator\">=</span> <span class=\"token function\">normalize</span><span class=\"token punctuation\">(</span>viewPos <span class=\"token operator\">-</span> fragPos<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> H <span class=\"token operator\">=</span> <span class=\"token function\">normalize</span><span class=\"token punctuation\">(</span>V <span class=\"token operator\">+</span> L<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">float</span> NdotH <span class=\"token operator\">=</span> <span class=\"token function\">max</span><span class=\"token punctuation\">(</span><span class=\"token function\">dot</span><span class=\"token punctuation\">(</span>N <span class=\"token punctuation\">,</span> H<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0.0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> NdotL <span class=\"token operator\">=</span> <span class=\"token function\">max</span><span class=\"token punctuation\">(</span><span class=\"token function\">dot</span><span class=\"token punctuation\">(</span>N <span class=\"token punctuation\">,</span> L<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0.0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token comment\">// ambient color</span>\n    <span class=\"token keyword\">vec3</span> ambientColor <span class=\"token operator\">=</span> diffuse <span class=\"token operator\">*</span> light<span class=\"token punctuation\">.</span>color <span class=\"token operator\">*</span> <span class=\"token number\">0.04</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token comment\">// diffuse color</span>\n    <span class=\"token keyword\">vec3</span> diffuseColor <span class=\"token operator\">=</span> diffuse <span class=\"token operator\">*</span> NdotL <span class=\"token operator\">*</span> light<span class=\"token punctuation\">.</span>color<span class=\"token punctuation\">;</span>\n    \n    <span class=\"token comment\">// specular color</span>\n    <span class=\"token keyword\">float</span> alpha <span class=\"token operator\">=</span> <span class=\"token number\">32</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> specularColor <span class=\"token operator\">=</span> specular <span class=\"token operator\">*</span> <span class=\"token function\">pow</span><span class=\"token punctuation\">(</span>NdotH<span class=\"token punctuation\">,</span> alpha<span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> light<span class=\"token punctuation\">.</span>color<span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>ambientColor <span class=\"token operator\">+</span> diffuseColor <span class=\"token operator\">+</span> specularColor<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>b. Oren-Nayar model + Normalized Blinn-Phong model</p>\n<div class=\"gatsby-highlight\" data-language=\"glsl\"><pre class=\"language-glsl\"><code class=\"language-glsl\"><span class=\"token comment\">// Oren-Nayar diffuse BRDF</span>\n<span class=\"token comment\">// ----------------------------------------------------------------------------</span>\n<span class=\"token keyword\">float</span> <span class=\"token function\">orenNayarDiffuse</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">float</span> LdotV<span class=\"token punctuation\">,</span>  <span class=\"token keyword\">float</span> NdotL<span class=\"token punctuation\">,</span> <span class=\"token keyword\">float</span> NdotV<span class=\"token punctuation\">,</span> <span class=\"token keyword\">float</span> roughness<span class=\"token punctuation\">)</span> \n<span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">float</span> s <span class=\"token operator\">=</span> LdotV <span class=\"token operator\">-</span> NdotL <span class=\"token operator\">*</span> NdotV<span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">float</span> t <span class=\"token operator\">=</span> <span class=\"token function\">mix</span><span class=\"token punctuation\">(</span><span class=\"token number\">1.0</span><span class=\"token punctuation\">,</span> <span class=\"token function\">max</span><span class=\"token punctuation\">(</span>NdotL<span class=\"token punctuation\">,</span> NdotV<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token function\">step</span><span class=\"token punctuation\">(</span><span class=\"token number\">0.0</span><span class=\"token punctuation\">,</span> s<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token keyword\">float</span> sigma2 <span class=\"token operator\">=</span> roughness <span class=\"token operator\">*</span> roughness<span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">float</span> A <span class=\"token operator\">=</span> <span class=\"token number\">1.0</span> <span class=\"token operator\">-</span> <span class=\"token punctuation\">(</span><span class=\"token number\">0.5</span> <span class=\"token operator\">*</span> sigma2 <span class=\"token operator\">/</span> <span class=\"token punctuation\">(</span>sigma2 <span class=\"token operator\">+</span> <span class=\"token number\">0.33</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">float</span> B <span class=\"token operator\">=</span> <span class=\"token number\">0.45</span> <span class=\"token operator\">*</span> sigma2 <span class=\"token operator\">/</span> <span class=\"token punctuation\">(</span>sigma2 <span class=\"token operator\">+</span> <span class=\"token number\">0.09</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token function\">max</span><span class=\"token punctuation\">(</span><span class=\"token number\">0.0</span><span class=\"token punctuation\">,</span> NdotL<span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> <span class=\"token punctuation\">(</span>A <span class=\"token operator\">+</span> B <span class=\"token operator\">*</span> s <span class=\"token operator\">/</span> t<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">vec3</span> <span class=\"token function\">CalcDirectionalLight</span><span class=\"token punctuation\">(</span>dirLight light<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> normal<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> diffuse<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> specular<span class=\"token punctuation\">,</span> <span class=\"token keyword\">float</span> roughness<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> viewPos<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> fragPos<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>    \n    <span class=\"token keyword\">vec3</span> N <span class=\"token operator\">=</span> <span class=\"token function\">normalize</span><span class=\"token punctuation\">(</span>normal<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> L <span class=\"token operator\">=</span> <span class=\"token function\">normalize</span><span class=\"token punctuation\">(</span><span class=\"token operator\">-</span>light<span class=\"token punctuation\">.</span>direction<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> V <span class=\"token operator\">=</span> <span class=\"token function\">normalize</span><span class=\"token punctuation\">(</span>viewPos <span class=\"token operator\">-</span> fragPos<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> H <span class=\"token operator\">=</span> <span class=\"token function\">normalize</span><span class=\"token punctuation\">(</span>V <span class=\"token operator\">+</span> L<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> LdotV <span class=\"token operator\">=</span> <span class=\"token function\">max</span><span class=\"token punctuation\">(</span><span class=\"token function\">dot</span><span class=\"token punctuation\">(</span>L <span class=\"token punctuation\">,</span> V<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0.0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> NdotH <span class=\"token operator\">=</span> <span class=\"token function\">max</span><span class=\"token punctuation\">(</span><span class=\"token function\">dot</span><span class=\"token punctuation\">(</span>N <span class=\"token punctuation\">,</span> H<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0.0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><span class=\"token comment\">// ambient color</span>\n    <span class=\"token keyword\">vec3</span> ambientColor <span class=\"token operator\">=</span> diffuse <span class=\"token operator\">*</span> light<span class=\"token punctuation\">.</span>color <span class=\"token operator\">*</span> <span class=\"token number\">0.04</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token comment\">// diffuse color</span>\n    <span class=\"token keyword\">float</span> Fd <span class=\"token operator\">=</span> <span class=\"token function\">orenNayarDiffuse</span><span class=\"token punctuation\">(</span>LdotV<span class=\"token punctuation\">,</span> NdotL<span class=\"token punctuation\">,</span> NdotV<span class=\"token punctuation\">,</span> roughness<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> diffuseColor <span class=\"token operator\">=</span> diffuse <span class=\"token operator\">*</span> Fd <span class=\"token operator\">*</span> light<span class=\"token punctuation\">.</span>color<span class=\"token punctuation\">;</span>\n    \n    <span class=\"token comment\">// specular color</span>\n    <span class=\"token keyword\">float</span> alpha <span class=\"token operator\">=</span> <span class=\"token number\">32</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> normalizedScaleFactor <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>alpha <span class=\"token operator\">+</span> <span class=\"token number\">2</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">/</span> <span class=\"token punctuation\">(</span><span class=\"token number\">4</span> <span class=\"token operator\">*</span> PI <span class=\"token operator\">*</span> <span class=\"token punctuation\">(</span><span class=\"token number\">2</span> <span class=\"token operator\">-</span> <span class=\"token function\">pow</span><span class=\"token punctuation\">(</span><span class=\"token number\">2</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">-</span>alpha <span class=\"token operator\">/</span> <span class=\"token number\">2</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> specularColor <span class=\"token operator\">=</span> specular <span class=\"token operator\">*</span> <span class=\"token punctuation\">(</span><span class=\"token number\">1</span> <span class=\"token operator\">-</span> Fd<span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> <span class=\"token function\">pow</span><span class=\"token punctuation\">(</span>NdotH<span class=\"token punctuation\">,</span> alpha<span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> normalizedScaleFactor <span class=\"token operator\">*</span> light<span class=\"token punctuation\">.</span>color<span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>ambientColor <span class=\"token operator\">+</span> diffuseColor <span class=\"token operator\">+</span> specularColor<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>c. Normalized Disney model + Cook-Torrance (specular) model, use <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>D</mi><mrow><mi>T</mi><mi>R</mi></mrow></msub></mrow><annotation encoding=\"application/x-tex\">D_{TR}</annotation></semantics></math></span></span>+<span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>G</mi><mrow><mi>C</mi><mi>o</mi><mi>r</mi><mi>r</mi><mi>e</mi><mi>l</mi><mi>a</mi><mi>t</mi><mi>e</mi><mi>d</mi><mi>S</mi><mi>c</mi><mi>h</mi><mi>l</mi><mi>i</mi><mi>c</mi><mi>k</mi></mrow></msub></mrow><annotation encoding=\"application/x-tex\">G_{CorrelatedSchlick}</annotation></semantics></math></span></span>+<span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>F</mi><mrow><mi>S</mi><mi>c</mi><mi>h</mi><mi>l</mi><mi>i</mi><mi>c</mi><mi>k</mi></mrow></msub></mrow><annotation encoding=\"application/x-tex\">F_{Schlick}</annotation></semantics></math></span></span> combination</p>\n<p>(reference Frostbite Engine [LR14])</p>\n<div class=\"gatsby-highlight\" data-language=\"glsl\"><pre class=\"language-glsl\"><code class=\"language-glsl\"><span class=\"token comment\">// Frostbite Engine model</span>\n<span class=\"token comment\">// ----------------------------------------------------------------------------</span>\n<span class=\"token comment\">// Specular/Diffuse BRDF Fresnel Component</span>\n<span class=\"token comment\">// ----------------------------------------------------------------------------</span>\n<span class=\"token keyword\">vec3</span> <span class=\"token function\">Frostbite_fresnelSchlick</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">vec3</span> f0<span class=\"token punctuation\">,</span> <span class=\"token keyword\">float</span> f90<span class=\"token punctuation\">,</span> <span class=\"token keyword\">float</span> u<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> f0 <span class=\"token operator\">+</span> <span class=\"token punctuation\">(</span>f90 <span class=\"token operator\">-</span> f0<span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> <span class=\"token function\">pow</span><span class=\"token punctuation\">(</span><span class=\"token number\">1.0</span> <span class=\"token operator\">-</span> u<span class=\"token punctuation\">,</span> <span class=\"token number\">5.0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token comment\">// Diffuse BRDF</span>\n<span class=\"token comment\">// ----------------------------------------------------------------------------</span>\n<span class=\"token keyword\">float</span> <span class=\"token function\">Frostbite_DisneyDiffuse</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">float</span> NdotV<span class=\"token punctuation\">,</span> <span class=\"token keyword\">float</span> NdotL<span class=\"token punctuation\">,</span> <span class=\"token keyword\">float</span> LdotH<span class=\"token punctuation\">,</span> <span class=\"token keyword\">float</span> earRoughness<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>    \n    <span class=\"token keyword\">float</span> energyBias <span class=\"token operator\">=</span> <span class=\"token function\">mix</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0.5</span><span class=\"token punctuation\">,</span> linearRoughness<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> energyFactor <span class=\"token operator\">=</span> <span class=\"token function\">mix</span><span class=\"token punctuation\">(</span><span class=\"token number\">1.0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">1.0</span><span class=\"token operator\">/</span><span class=\"token number\">1.51</span><span class=\"token punctuation\">,</span> linearRoughness<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> fd90 <span class=\"token operator\">=</span> energyBias <span class=\"token operator\">+</span> <span class=\"token number\">2.0</span> <span class=\"token operator\">*</span> LdotH <span class=\"token operator\">*</span> LdotH <span class=\"token operator\">*</span> linearRoughness<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> f0 <span class=\"token operator\">=</span> <span class=\"token keyword\">vec3</span> <span class=\"token punctuation\">(</span><span class=\"token number\">1.0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">1.0</span><span class=\"token punctuation\">,</span> <span class=\"token number\">1.0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> lightScatter <span class=\"token operator\">=</span> <span class=\"token function\">Frostbite_fresnelSchlick</span><span class=\"token punctuation\">(</span>f0<span class=\"token punctuation\">,</span> fd90<span class=\"token punctuation\">,</span> NdotL<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>r<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> viewScatter <span class=\"token operator\">=</span> <span class=\"token function\">Frostbite_fresnelSchlick</span><span class=\"token punctuation\">(</span>f0<span class=\"token punctuation\">,</span> fd90<span class=\"token punctuation\">,</span> NdotV<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>r<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">return</span> lightScatter <span class=\"token operator\">*</span> viewScatter <span class=\"token operator\">*</span> energyFactor<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token comment\">// Specular BRDF Geometry Component</span>\n<span class=\"token comment\">// ----------------------------------------------------------------------------</span>\n<span class=\"token keyword\">float</span> <span class=\"token function\">Frostbite_V_SmithGGXCorrelated</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">float</span> NdotL <span class=\"token punctuation\">,</span> <span class=\"token keyword\">float</span> NdotV <span class=\"token punctuation\">,</span> <span class=\"token keyword\">float</span> alphaG<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">float</span> alphaG2 <span class=\"token operator\">=</span> alphaG <span class=\"token operator\">*</span> alphaG<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> Lambda_GGXV <span class=\"token operator\">=</span> NdotL <span class=\"token operator\">*</span> <span class=\"token function\">sqrt</span><span class=\"token punctuation\">(</span>NdotV <span class=\"token operator\">*</span> NdotV <span class=\"token operator\">*</span> <span class=\"token punctuation\">(</span><span class=\"token number\">1.0</span> <span class=\"token operator\">-</span> alphaG2<span class=\"token punctuation\">)</span> <span class=\"token operator\">+</span> alphaG2<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> Lambda_GGXL <span class=\"token operator\">=</span> NdotV <span class=\"token operator\">*</span> <span class=\"token function\">sqrt</span><span class=\"token punctuation\">(</span>NdotL <span class=\"token operator\">*</span> NdotL <span class=\"token operator\">*</span> <span class=\"token punctuation\">(</span><span class=\"token number\">1.0</span> <span class=\"token operator\">-</span> alphaG2<span class=\"token punctuation\">)</span> <span class=\"token operator\">+</span> alphaG2<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">return</span> <span class=\"token number\">0.5</span> <span class=\"token operator\">/</span> <span class=\"token function\">max</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>Lambda_GGXV <span class=\"token operator\">+</span> Lambda_GGXL<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0.00001</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token comment\">// Specular BRDF Distribution Component</span>\n<span class=\"token comment\">// ----------------------------------------------------------------------------</span>\n<span class=\"token keyword\">float</span> <span class=\"token function\">Frostbite_D_GGX</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">float</span> NdotH <span class=\"token punctuation\">,</span> <span class=\"token keyword\">float</span> roughness<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// remapping to Quadratic curve</span>\n    <span class=\"token keyword\">float</span> m <span class=\"token operator\">=</span> roughness <span class=\"token operator\">*</span> roughness<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> m2 <span class=\"token operator\">=</span> m <span class=\"token operator\">*</span> m<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> f <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>NdotH <span class=\"token operator\">*</span> m2 <span class=\"token operator\">-</span> NdotH<span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> NdotH <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">return</span> m2 <span class=\"token operator\">/</span> <span class=\"token punctuation\">(</span>f <span class=\"token operator\">*</span> f<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token comment\">// ----------------------------------------------------------------------------</span>\n<span class=\"token keyword\">vec3</span> <span class=\"token function\">Frostbite_CalcDirectionalLightRadiance</span><span class=\"token punctuation\">(</span>dirLight light<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> albedo<span class=\"token punctuation\">,</span> <span class=\"token keyword\">float</span> metallic<span class=\"token punctuation\">,</span> <span class=\"token keyword\">float</span> roughness<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> normal<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> viewPos<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> fragPos<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> F0<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">vec3</span> N <span class=\"token operator\">=</span> <span class=\"token function\">normalize</span><span class=\"token punctuation\">(</span>normal<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> L <span class=\"token operator\">=</span> <span class=\"token function\">normalize</span><span class=\"token punctuation\">(</span><span class=\"token operator\">-</span>light<span class=\"token punctuation\">.</span>direction<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> V <span class=\"token operator\">=</span> <span class=\"token function\">normalize</span><span class=\"token punctuation\">(</span>viewPos <span class=\"token operator\">-</span> fragPos<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> H <span class=\"token operator\">=</span> <span class=\"token function\">normalize</span><span class=\"token punctuation\">(</span>V <span class=\"token operator\">+</span> L<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">float</span> NdotV <span class=\"token operator\">=</span> <span class=\"token function\">max</span><span class=\"token punctuation\">(</span><span class=\"token function\">dot</span><span class=\"token punctuation\">(</span>N <span class=\"token punctuation\">,</span> V<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0.0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> LdotH <span class=\"token operator\">=</span> <span class=\"token function\">max</span><span class=\"token punctuation\">(</span><span class=\"token function\">dot</span><span class=\"token punctuation\">(</span>L <span class=\"token punctuation\">,</span> H<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0.0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> NdotH <span class=\"token operator\">=</span> <span class=\"token function\">max</span><span class=\"token punctuation\">(</span><span class=\"token function\">dot</span><span class=\"token punctuation\">(</span>N <span class=\"token punctuation\">,</span> H<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0.0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> NdotL <span class=\"token operator\">=</span> <span class=\"token function\">max</span><span class=\"token punctuation\">(</span><span class=\"token function\">dot</span><span class=\"token punctuation\">(</span>N <span class=\"token punctuation\">,</span> L<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0.0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token comment\">// Specular BRDF</span>\n    <span class=\"token keyword\">float</span> f90 <span class=\"token operator\">=</span> <span class=\"token number\">1.0</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> F <span class=\"token operator\">=</span> <span class=\"token function\">Frostbite_fresnelSchlick</span><span class=\"token punctuation\">(</span>F0<span class=\"token punctuation\">,</span> f90<span class=\"token punctuation\">,</span> LdotH<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> G <span class=\"token operator\">=</span> <span class=\"token function\">Frostbite_V_SmithGGXCorrelated</span><span class=\"token punctuation\">(</span>NdotV<span class=\"token punctuation\">,</span> NdotL<span class=\"token punctuation\">,</span> roughness<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> D <span class=\"token operator\">=</span> <span class=\"token function\">Frostbite_D_GGX</span> <span class=\"token punctuation\">(</span>NdotH<span class=\"token punctuation\">,</span> roughness<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> Fr <span class=\"token operator\">=</span> F <span class=\"token operator\">*</span> G <span class=\"token operator\">*</span> D<span class=\"token punctuation\">;</span>\n\n    <span class=\"token comment\">// Diffuse BRDF</span>\n    <span class=\"token keyword\">float</span> Fd <span class=\"token operator\">=</span> <span class=\"token function\">Frostbite_DisneyDiffuse</span><span class=\"token punctuation\">(</span>NdotV<span class=\"token punctuation\">,</span> NdotL<span class=\"token punctuation\">,</span> LdotH <span class=\"token punctuation\">,</span>roughness <span class=\"token operator\">*</span> roughness<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> \n    \n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>Fd <span class=\"token operator\">*</span> albedo <span class=\"token operator\">+</span> Fr<span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> light<span class=\"token punctuation\">.</span>color <span class=\"token operator\">*</span> NdotL <span class=\"token operator\">/</span> PI<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>d.Simple Lambert model + Cook-Torrance (specular) model, use <span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>D</mi><mrow><mi>T</mi><mi>R</mi></mrow></msub></mrow><annotation encoding=\"application/x-tex\">D_{TR}</annotation></semantics></math></span></span>+<span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>G</mi><mrow><mi>S</mi><mi>c</mi><mi>h</mi><mi>l</mi><mi>i</mi><mi>c</mi><mi>k</mi></mrow></msub></mrow><annotation encoding=\"application/x-tex\">G_{Schlick}</annotation></semantics></math></span></span>+<span class=\"math math-inline\"><span class=\"katex\"><math xmlns=\"http://www.w3.org/1998/Math/MathML\"><semantics><mrow><msub><mi>F</mi><mrow><mi>S</mi><mi>c</mi><mi>h</mi><mi>l</mi><mi>i</mi><mi>c</mi><mi>k</mi></mrow></msub></mrow><annotation encoding=\"application/x-tex\">F_{Schlick}</annotation></semantics></math></span></span> combination</p>\n<p>(reference from Unreal Engine 4[Kar13])</p>\n<div class=\"gatsby-highlight\" data-language=\"glsl\"><pre class=\"language-glsl\"><code class=\"language-glsl\"><span class=\"token comment\">// Unreal Engine model</span>\n<span class=\"token comment\">// ----------------------------------------------------------------------------</span>\n<span class=\"token comment\">// Specular BRDF Distribution Component</span>\n<span class=\"token comment\">// ----------------------------------------------------------------------------</span>\n<span class=\"token keyword\">float</span> <span class=\"token function\">Unreal_DistributionGGX</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">float</span> NdotH<span class=\"token punctuation\">,</span> <span class=\"token keyword\">float</span> roughness<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">float</span> a <span class=\"token operator\">=</span> roughness<span class=\"token operator\">*</span>roughness<span class=\"token punctuation\">;</span>\n    <span class=\"token comment\">// remapping to Quadratic curve</span>\n    <span class=\"token keyword\">float</span> a2 <span class=\"token operator\">=</span> a <span class=\"token operator\">*</span> a<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> NdotH2 <span class=\"token operator\">=</span> NdotH<span class=\"token operator\">*</span>NdotH<span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">float</span> nom   <span class=\"token operator\">=</span> a2<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> denom <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>NdotH2 <span class=\"token operator\">*</span> <span class=\"token punctuation\">(</span>a2 <span class=\"token operator\">-</span> <span class=\"token number\">1.0</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">+</span> <span class=\"token number\">1.0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    denom <span class=\"token operator\">=</span> denom <span class=\"token operator\">*</span> denom<span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">return</span> nom <span class=\"token operator\">/</span> denom<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token comment\">// Specular BRDF Geometry Component</span>\n<span class=\"token comment\">// ----------------------------------------------------------------------------</span>\n<span class=\"token keyword\">float</span> <span class=\"token function\">Unreal_GeometrySchlickGGX</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">float</span> NdotV<span class=\"token punctuation\">,</span> <span class=\"token keyword\">float</span> roughness<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">float</span> r <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>roughness <span class=\"token operator\">+</span> <span class=\"token number\">1.0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> k <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>r<span class=\"token operator\">*</span>r<span class=\"token punctuation\">)</span> <span class=\"token operator\">/</span> <span class=\"token number\">8.0</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">float</span> nom   <span class=\"token operator\">=</span> NdotV<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> denom <span class=\"token operator\">=</span> NdotV <span class=\"token operator\">*</span> <span class=\"token punctuation\">(</span><span class=\"token number\">1.0</span> <span class=\"token operator\">-</span> k<span class=\"token punctuation\">)</span> <span class=\"token operator\">+</span> k<span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">return</span> nom <span class=\"token operator\">/</span> denom<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token comment\">// ----------------------------------------------------------------------------</span>\n<span class=\"token keyword\">float</span> <span class=\"token function\">Unreal_GeometrySmith</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">float</span> NdotV<span class=\"token punctuation\">,</span> <span class=\"token keyword\">float</span> NdotL<span class=\"token punctuation\">,</span> <span class=\"token keyword\">float</span> roughness<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">float</span> ggx2 <span class=\"token operator\">=</span> <span class=\"token function\">Unreal_GeometrySchlickGGX</span><span class=\"token punctuation\">(</span>NdotV<span class=\"token punctuation\">,</span> roughness<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> ggx1 <span class=\"token operator\">=</span> <span class=\"token function\">Unreal_GeometrySchlickGGX</span><span class=\"token punctuation\">(</span>NdotL<span class=\"token punctuation\">,</span> roughness<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">return</span> ggx1 <span class=\"token operator\">*</span> ggx2<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token comment\">// Specular BRDF Fresnel Component</span>\n<span class=\"token comment\">// ----------------------------------------------------------------------------</span>\n<span class=\"token keyword\">vec3</span> <span class=\"token function\">Unreal_fresnelSchlick</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">float</span> cosTheta<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> F0<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> F0 <span class=\"token operator\">+</span> <span class=\"token punctuation\">(</span><span class=\"token number\">1.0</span> <span class=\"token operator\">-</span> F0<span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> <span class=\"token function\">pow</span><span class=\"token punctuation\">(</span><span class=\"token number\">1.0</span> <span class=\"token operator\">-</span> cosTheta<span class=\"token punctuation\">,</span> <span class=\"token number\">5.0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token comment\">// ----------------------------------------------------------------------------</span>\n<span class=\"token keyword\">vec3</span> <span class=\"token function\">Unreal_CalcDirectionalLightRadiance</span><span class=\"token punctuation\">(</span>dirLight light<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> albedo<span class=\"token punctuation\">,</span> <span class=\"token keyword\">float</span> metallic<span class=\"token punctuation\">,</span> <span class=\"token keyword\">float</span> roughness<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> normal<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> viewPos<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> fragPos<span class=\"token punctuation\">,</span> <span class=\"token keyword\">vec3</span> F0<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">vec3</span> N <span class=\"token operator\">=</span> <span class=\"token function\">normalize</span><span class=\"token punctuation\">(</span>normal<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> L <span class=\"token operator\">=</span> <span class=\"token function\">normalize</span><span class=\"token punctuation\">(</span><span class=\"token operator\">-</span>light<span class=\"token punctuation\">.</span>direction<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> V <span class=\"token operator\">=</span> <span class=\"token function\">normalize</span><span class=\"token punctuation\">(</span>viewPos <span class=\"token operator\">-</span> fragPos<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> H <span class=\"token operator\">=</span> <span class=\"token function\">normalize</span><span class=\"token punctuation\">(</span>V <span class=\"token operator\">+</span> L<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">float</span> NdotV <span class=\"token operator\">=</span> <span class=\"token function\">max</span><span class=\"token punctuation\">(</span><span class=\"token function\">dot</span><span class=\"token punctuation\">(</span>N <span class=\"token punctuation\">,</span> V<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0.0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> NdotH <span class=\"token operator\">=</span> <span class=\"token function\">max</span><span class=\"token punctuation\">(</span><span class=\"token function\">dot</span><span class=\"token punctuation\">(</span>N<span class=\"token punctuation\">,</span>  H<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0.0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> HdotV <span class=\"token operator\">=</span> <span class=\"token function\">max</span><span class=\"token punctuation\">(</span><span class=\"token function\">dot</span><span class=\"token punctuation\">(</span>H <span class=\"token punctuation\">,</span> V<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0.0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> NdotL <span class=\"token operator\">=</span> <span class=\"token function\">max</span><span class=\"token punctuation\">(</span><span class=\"token function\">dot</span><span class=\"token punctuation\">(</span>N <span class=\"token punctuation\">,</span> L<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0.0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n    <span class=\"token comment\">// Specular BRDF</span>\n    <span class=\"token keyword\">vec3</span> F <span class=\"token operator\">=</span> <span class=\"token function\">Unreal_fresnelSchlick</span><span class=\"token punctuation\">(</span>HdotV<span class=\"token punctuation\">,</span> F0<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">float</span> G <span class=\"token operator\">=</span> <span class=\"token function\">Unreal_GeometrySmith</span><span class=\"token punctuation\">(</span>N<span class=\"token punctuation\">,</span> V<span class=\"token punctuation\">,</span> L<span class=\"token punctuation\">,</span> roughness<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>      \n    <span class=\"token keyword\">float</span> D <span class=\"token operator\">=</span> <span class=\"token function\">Unreal_DistributionGGX</span><span class=\"token punctuation\">(</span>N<span class=\"token punctuation\">,</span> H<span class=\"token punctuation\">,</span> roughness<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>  \n           \n    <span class=\"token keyword\">vec3</span> nominator <span class=\"token operator\">=</span> D <span class=\"token operator\">*</span> G <span class=\"token operator\">*</span> F<span class=\"token punctuation\">;</span> \n    <span class=\"token keyword\">float</span> denominator <span class=\"token operator\">=</span> <span class=\"token number\">4</span> <span class=\"token operator\">*</span> NdotV <span class=\"token operator\">*</span> NdotL<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> specular <span class=\"token operator\">=</span> nominator <span class=\"token operator\">/</span> <span class=\"token function\">max</span><span class=\"token punctuation\">(</span>denominator<span class=\"token punctuation\">,</span> <span class=\"token number\">0.00001</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token comment\">// for energy conservation       </span>\n    <span class=\"token keyword\">vec3</span> kS <span class=\"token operator\">=</span> F<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">vec3</span> kD <span class=\"token operator\">=</span> <span class=\"token keyword\">vec3</span><span class=\"token punctuation\">(</span><span class=\"token number\">1.0</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span> kS<span class=\"token punctuation\">;</span>  \n    kD <span class=\"token operator\">*=</span> <span class=\"token number\">1.0</span> <span class=\"token operator\">-</span> metallic<span class=\"token punctuation\">;</span>      \n   \n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>kD <span class=\"token operator\">*</span> albedo <span class=\"token operator\">+</span> specular<span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> light<span class=\"token punctuation\">.</span>color <span class=\"token operator\">*</span> NdotL<span class=\"token punctuation\">)</span> <span class=\"token operator\">/</span> PI<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>To be continued.</p>\n<p>Bibliography：</p>\n<p>[Bur12] B. Burley. “Physically Based Shading at Disney”. In: Physically Based Shading in Film and Game Production, ACM SIGGRAPH 2012 Courses. SIGGRAPH ’12. Los Angeles, California: ACM, 2012, 10:1–7. isbn: 978-1-4503-1678-1. doi: 10.1145/2343483.2343493. url: <a href=\"http://selfshadow.com/publications/s2012-shading-course/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">http://selfshadow.com/publications/s2012-shading-course/</a>.</p>\n<p>[CT82] R. L. Cook and K. E. Torrance. “A Reﬂectance Model for Computer Graphics”. In: ACM Trans. Graph. 1.1 (Jan. 1982), pp. 7–24. issn: 0730-0301. doi: 10.1145/357290.357293. url: <a href=\"http://graphics.pixar.com/library/ReflectanceModel/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">http://graphics.pixar.com/library/ReflectanceModel/</a>.</p>\n<p>[Hei14] E. Heitz. “Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs”. In: Journal of Computer Graphics Techniques (JCGT) 3.2 (June 2014), pp. 32–91. issn: 2331-7418. url: <a href=\"http://jcgt.org/published/0003/02/03/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">http://jcgt.org/published/0003/02/03/</a>.</p>\n<p>[HHED16] E. Heitz, J. Hanika, E. d’Eon, C. Dachsbacher,  “Multiple-Scattering Microfacet BSDFs with the Smith Model”. In: ACM Transactions on Graphics (TOG) - Proceedings of ACM SIGGRAPH 2016, Volume 35 Issue 4, July 2016,  ISSN: 0730-0301 E, ISSN: 1557-7368 doi>10.1145/2897824.2925943, url: <a href=\"https://eheitzresearch.wordpress.com/240-2/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://eheitzresearch.wordpress.com/240-2/</a></p>\n<p>[HTSG91] Xiao D. He, Kenneth E, Torrance, Frangois X. Sillion and Donald P. Greenberg. “A Comprehensive Physical Model for Light Reflection”. In: ACM SIGGRAPH Computer Graphics Homepage, Volume 25 Issue 4, July 1991, Pages 175-186, ACM New York, NY, USA, doi>10.1145/127719.122738, url: <a href=\"https://www.graphics.cornell.edu/pubs/1991/HTSG91.pdf\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://www.graphics.cornell.edu/pubs/1991/HTSG91.pdf</a></p>\n<p>[Kar13] B. Karis. “Real Shading in Unreal Engine 4”. In: Physically Based Shading in Theory and Practice, ACM SIGGRAPH 2013 Courses. SIGGRAPH ’13. Anaheim, California: ACM, 2013, 22:1–22:8. isbn: 978-1-4503-2339-0. doi: 10.1145/2504435.2504457. url: <a href=\"http://selfshadow.com/publications/s2013-shading-course/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">http://selfshadow.com/publications/s2013-shading-course/</a>.</p>\n<p>[LR14]  S. Lagarde and C. de Rousiers. “Moving Frostbite to PBR”. In: Physically Based Shading in Theory and Practice, ACM SIGGRAPH 2014 Courses. SIGGRAPH ’14. Vancouver, Canada: ACM, 2014, 23:1–23:8. isbn: 978-1-4503-2962-0. doi: 10.1145/2614028.2615431. url: <a href=\"http://www.frostbite.com/2014/11/moving-frostbite-to-pbr/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">http://www.frostbite.com/2014/11/moving-frostbite-to-pbr/</a>.</p>\n<p>[Sch94] Schlick, Christophe, “An Inexpensive BRDF Model for Physically-based Rendering”, Computer Graphics Forum, vol.13, no.3, Sept.1994, pp.149–162. <a href=\"http://dept-info.labri.u-bordeaux.fr/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">http://dept-info.labri.u-bordeaux.fr/</a> ~Schlick/DOC/eur2.html</p>\n<p>[Sch14] N. Schulz. “Moving to the Next Generation - The Rendering Technology of Ryse”. In: Game Developers Conference. 2014.</p>\n<p>[Wiki1] <a href=\"https://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_shading_model\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_shading_model</a></p>","fields":{"slug":"/posts/physically-based-rendering-material","tagSlugs":["/tag//"]},"frontmatter":{"date":"2018-08-12T17:36","description":"","tags":[""],"title":"Physically Based Rendering - Material"}}},"pageContext":{"slug":"/posts/physically-based-rendering-material"}},"staticQueryHashes":["251939775","2764776372","401334301"]}