User Tools

Site Tools


specular_lys

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
specular_lys [2017/04/14 08:55]
adavies
specular_lys [2017/05/23 03:49] (current)
Line 21: Line 21:
   * **Default:​** The standard ramp used by Lys. This ramp is the inverse of the one found within Marmoset Toolbag 2 with adjusted constants.   * **Default:​** The standard ramp used by Lys. This ramp is the inverse of the one found within Marmoset Toolbag 2 with adjusted constants.
   * **Log2:** A user configurable ramp that allows variable distribution of specular power values across MIP levels.   * **Log2:** A user configurable ramp that allows variable distribution of specular power values across MIP levels.
 +  * **Burley:** The square root of true roughness (inverted smoothness) distributed across a perceptually linear curve.
  
 **Use Specular Power/Use Roughness:​** Check this to enable Lys to work with specular power rather than roughness & vice versa. **Use Specular Power/Use Roughness:​** Check this to enable Lys to work with specular power rather than roughness & vice versa.
Line 46: Line 46:
 ---- ----
  
 +
 +==== Image Based Lighting Sample Shader ====
 +
 +In the following we describe how to use cube maps generated with Lys in a shader for image based lighting. We also provide a free, complete IBL sample shader & associated source files.
 +
 +Please see the [[ibl_sample_shader_lys|Image Based Lighting Sample Shader]] page for more details.
  
 ==== Computing MIP Levels From Specular Power/​Roughness ==== ==== Computing MIP Levels From Specular Power/​Roughness ====
Line 75: Line 81:
  
  
-In the following, the power drops of Lys will be explained and we describe how to map specular power to the correct floating point MIP entry. Be sure to enable trilinear filtering when using cube maps for image based lighting to achieve continuous ​specular powers.+In the following, the roughness/​specular ​power drops of Lys will be explained and we describe how to map to the correct floating point MIP entry. 
 +Be sure to enable trilinear filtering when using cube maps for image based lighting to achieve continuous ​roughness.
  
 +It has become very common to use "​roughness texture maps" to describe the specular reflection of a material. Note that these are not equivalent to
 +actual academic roughness which is defined as the root mean square slope of the profile.
 +Roughness texture maps in computer graphics have for practical reasons been defined as a more even distribution of blurriness. In the following we will refer to the roughness in texture maps as "​perceptual roughness"​ and when we refer to roughness we are referring to academic roughness.
  
 +Perceptual roughness, roughness and specular power can all be thought of as different parametrizations for the same parameter and it is possible to convert back and forth. For instance the conversions from roughness to perceptual roughness and back again are:
  
-If your shader uses roughness and not specular power then you should remap using the following function:+<code glsl>​float RoughnessFromPerceptualRoughness(float fPerceptualRoughness) 
 +
 +   ​return fPerceptualRoughness*fPerceptualRoughness;​ 
 +
 +</​code>​
  
-<code glsl>​float ​RoughToSPow(float fRoughness) ​// convert to specular power+<code glsl>​float ​PerceptualRoughnessFromRoughness(float fRoughness)
 { {
-   ​return (2.0/​(fRoughness*fRoughness))-2.0;+   ​return ​sqrt(max(0.0,fRoughness));​
 } }
 </​code>​ </​code>​
  
 +Similarly we can also convert from perceptual roughness to specular power and back again.
  
 +<code glsl>​float SpecularPowerFromPerceptualRoughness(float fPerceptualRoughness)
 +{
 +   float fRoughness = RoughnessFromPerceptualRoughness(fPerceptualRoughness);​
 +   ​return (2.0/​max(FLT_EPSILON,​ fRoughness*fRoughness))-2.0;​
 +}
 +</​code>​
  
 +<code glsl>​float PerceptualRoughnessFromSpecularPower(float fSpecPower)
 +{
 +   float fRoughness = sqrt(2.0/​(fSpecPower + 2.0));
 +   ​return PerceptualRoughnessFromRoughness(fRoughness);​
 +}
 +</​code>​
  
-=== The Log2 Power Drop ===+Thus we should not think of perceptual roughness as specifically for GGX or specular power as specifically for Blinn-Phong BRDFs. 
 +Finally for those using "​smoothness texture maps". These are simply equal to one minus the perceptual roughness and vice versa.
  
  
-In Lys we currently support ​two power drops. Default and Log2.+[{{https://​s3.amazonaws.com/​docs.knaldtech.com/​docuwiki/​perceptual_vs_rdq_plot.png?​nolink|Perceptual roughness vs academic roughness (Rdq).}}] 
 + 
 +=== Burley === 
 + 
 +In Lys we currently support ​three ways to distribute blurriness across MIP levelsBurley((Brent Burley. Physically-Based Shading at Disney. https://​disney-animation.s3.amazonaws.com/​library/​s2012_pbs_disney_brdf_notes_v2.pdf)), ​Default and Log2. 
 + 
 +Burley is the most straight forward and the one we recommend using for image based lighting. 
 +The top MIP level will always be used for a 100% sharp reflection (roughness 0.0) and the offset from the bottom MIP level specified using “MIP Offset” in the specular group determines where we have 100% blurriness (roughness 1.0). The default offset of 3 corresponds to MIP level 8x8. Checking “Coarse Irradiance” in the 3D Preview will enable using the MIP level at your chosen offset for diffuse lighting in the viewport. 
 + 
 +Note that our implementation of BurleyToMip() below differs from the more typical form as cube maps convolved in Lys are based on RdotL and not NdotH. You can find a more detailed description in [[specular_lys#​pre-convolved_cube_maps_vs_path_tracers|Pre-convolved Cube Maps vs Path Tracers]]. 
 + 
 +Despite the difference in distribution of MIPs the lit specular response resulting from the “roughness texture” will be identical to existing PBR based game engines and tools. 
 + 
 +<code glsl>​float BurleyToMip(float fPerceptualRoughness,​ int nMips, float NdotR) 
 +
 +   float fSpecPower = SpecularPowerFromPerceptualRoughness(fPerceptualRoughness);​ 
 +   ​fSpecPower /= (4*max(NdotR,​ FLT_EPSILON));​ //​ see section "​Pre-convolved Cube Maps vs Path Tracers"​ 
 +   float fScale = PerceptualRoughnessFromSpecularPower(fSpecPower);​ 
 +   ​return fScale*(nMips-1-nMipOffset);​ 
 +
 +</​code>​ 
 + 
 +As we can see this implementation has an intermediate step which is explained in section "​[[specular_lys#​pre-convolved_cube_maps_vs_path_tracers|Pre-convolved Cube Maps vs Path Tracers]]"​. 
 +If this is considered too expensive then a cheaper close alternative is to use the following replacement. 
 + 
 +<code glsl>​float BurleyToMipSimple(float fPerceptualRoughness,​ int nMips) 
 +
 +   float fScale = fPerceptualRoughness*(1.7 - 0.7*fPerceptualRoughness); ​   // approximate remap from LdotR based distribution to NdotH 
 +   ​return fScale*(nMips-1-nMipOffset);​ 
 +
 +</​code>​ 
 + 
 +=== The Log2 Power Drop ===
  
 The goal when designing your drop curve is to get a distribution of specular power values across MIP levels that fit the needs of your application. The first thing to do is to decide at which MIP level to place the specular power of 1, which in Lys corresponds to the highest roughness. The goal when designing your drop curve is to get a distribution of specular power values across MIP levels that fit the needs of your application. The first thing to do is to decide at which MIP level to place the specular power of 1, which in Lys corresponds to the highest roughness.
  
 You do this by specifying the "MIP Offset"​ in the specular group. This value represents an offset from the bottom 1x1 cube map MIP level. You do this by specifying the "MIP Offset"​ in the specular group. This value represents an offset from the bottom 1x1 cube map MIP level.
-The default value of 3 corresponds to assigning a specular power of 1 to level 8x8. To help you make the right choice you can check "​Coarse Irradiance"​ in the 3D Preview which will then use the MIP level at your chosen offset for diffuse lighting.+The default value of 3 corresponds to assigning a specular power of 1 to level 8x8.
  
 Next you need to distribute the remaining specular power values. For the Log2 distribution this is done using the "User Scale"​. Next you need to distribute the remaining specular power values. For the Log2 distribution this is done using the "User Scale"​.
Line 108: Line 169:
 The code to convert the specular power to a MIP entry is as follows: The code to convert the specular power to a MIP entry is as follows:
  
-<code glsl>​float GetSpecPowToMip(float ​fSpecPow, int nMips) // log2 distribution+<code glsl>​float GetSpecPowToMip(float ​fSpecPower_in, int nMips, float NdotR) // log2 distribution
 { {
-   ​return (nMips-1-nMipOffset) - log2(fSpecPow)*fUserScale;​+   float fSpecPower = fSpecPower_in / (4*max(NdotR,​ FLT_EPSILON)); ​ // see section "​Pre-convolved Cube Maps vs Path Tracers"​ 
 +   return (nMips-1-nMipOffset) - log2(fSpecPower)*fUserScale;​
 } }
 </​code>​ </​code>​
Line 164: Line 226:
  
  
-float GetSpecPowToMip(float ​fSpecPow, int nMips)+float GetSpecPowToMip(float ​fSpecPower_in, int nMips, float NdotR)
 { {
 +   float fSpecPower = fSpecPower_in / (4*max(NdotR,​ FLT_EPSILON)); ​ // see section "​Pre-convolved Cube Maps vs Path Tracers"​
    // Default curve - Inverse of TB2 curve with adjusted constants    // Default curve - Inverse of TB2 curve with adjusted constants
-   float fSmulMaxT = ( exp2(-10.0/​sqrt( ​fSpecPow ​)) - k0)/k1;+   float fSmulMaxT = ( exp2(-10.0/​sqrt( ​fSpecPower ​)) - k0)/k1;
  
    ​return float(nMips-1-nMipOffset)*(1.0 - clamp( fSmulMaxT/​g_fMaxT,​ 0.0, 1.0 ));    ​return float(nMips-1-nMipOffset)*(1.0 - clamp( fSmulMaxT/​g_fMaxT,​ 0.0, 1.0 ));
Line 194: Line 257:
 [{{https://​s3.amazonaws.com/​docs.knaldtech.com/​docuwiki/​reflected_beam_new.png?​nolink&​1075 |The view direction v reflected by dH will result in dR. Given the existing symmetry the central direction r of dR will result in dV when reflected by dH.}}] [{{https://​s3.amazonaws.com/​docs.knaldtech.com/​docuwiki/​reflected_beam_new.png?​nolink&​1075 |The view direction v reflected by dH will result in dR. Given the existing symmetry the central direction r of dR will result in dV when reflected by dH.}}]
  
 +\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ 
  
- +\\ \\ As an approximation we can correlate size of solid angle with "blur strength"​and replace ''​h_dot_r''​ with ''​n_dot_r''​. So ultimately what we do is adjust our specular power in the following way:
-\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ +
- +
-As an approximation we can correlate size of solid angle with "blur strength"​and replace ''​h_dot_r''​ with ''​n_dot_r''​. So ultimately what we do is adjust our specular power in the following way:+
  
 <code glsl>​fSpecPow /= (4*max(dot(vN,​ vR), FLT_EPSILON));</​code>​ <code glsl>​fSpecPow /= (4*max(dot(vN,​ vR), FLT_EPSILON));</​code>​
- 
- 
- 
  
 This works because the specular power is roughly inversely proportional to the amount of blur. This works because the specular power is roughly inversely proportional to the amount of blur.
  
- +Note we perform this correction inside ​the functions ​GetSpecPowToMip() ​and BurleyToMip() given above. This adjustment is of course just for the cube maps and should NOT be applied to the specular power used with ordinary lights since for these we simply use an n_dot_h based formulation as opposed to l_dot_r.
- +
-We then use the adjusted ''​fSpecPow''​ to find our MIP level with ''​GetSpecPowToMip()''​. This adjustment is of course just for the cube maps and should NOT be applied to the specular power used with ordinary lights since for these we simply use an n_dot_h based formulation as opposed to l_dot_r.+
 This approach will work with both normalized Blinn-Phong((Morten S. Mikkelsen. Microfacet Based Bidirectional Reflectance Distribution Function. https://​dl.dropboxusercontent.com/​u/​55891920/​papers/​mm_brdf.pdf)) ((Bruce Walter, Stephen R. Marschner, Hongsong & LiKenneth E. Torrance. Microfacet Models for Refraction through Rough Surfaces. https://​www.cs.cornell.edu/​~srm/​publications/​EGSR07-btdf.pdf)) and GGX. In the former case use cosine weighted convolution in Lys. Though it is an approximation it gives results that are close to what the path tracer will provide for the same specular power. The approach will also harden the reflection as we approach the silhouette which is more physically correct. This approach will work with both normalized Blinn-Phong((Morten S. Mikkelsen. Microfacet Based Bidirectional Reflectance Distribution Function. https://​dl.dropboxusercontent.com/​u/​55891920/​papers/​mm_brdf.pdf)) ((Bruce Walter, Stephen R. Marschner, Hongsong & LiKenneth E. Torrance. Microfacet Models for Refraction through Rough Surfaces. https://​www.cs.cornell.edu/​~srm/​publications/​EGSR07-btdf.pdf)) and GGX. In the former case use cosine weighted convolution in Lys. Though it is an approximation it gives results that are close to what the path tracer will provide for the same specular power. The approach will also harden the reflection as we approach the silhouette which is more physically correct.
  
specular_lys.1492160149.txt.gz · Last modified: 2017/05/23 03:49 (external edit)