Last updated on
Jul 13, 2023
- Getting Started overview
- Activation and licenses
- System requirements
- Project creation
-
Export
- Export overview
- Export window
- Export presets
- Glossary
- Performance
- Assets
- Substance 3D Assets
- Color picker
- Display settings
- History
- Layer stack
- Main menu
- Project configuration
- Properties
- Settings
- Shader settings
- Texture Set
- Toolbars
- Viewport
- Miscellaneous
- Painting overview
- Tool list
- Straight line
- Lazy mouse
- Symmetry
- Fill projections
-
Presets
- Presets overview
- Creating and saving presets
- Creating particles presets
- Photoshop brush presets (ABR)
- Dynamic strokes
- Advanced channel painting
- Vector graphic (.svg & .ai)
- Text resource
- Creating custom effects
- Importing assets
- Automatic UV Unwrapping
- Physical size
- Smart Materials and Masks
- Subsurface Scattering
- Dynamic Material Layering
- UV Reprojection
- UV Tiles
- Color Management
- Post Processing
- Iray Renderer
- Plugins
- Sparse Virtual Textures
- Custom Shaders
- SpaceMouse® by 3Dconnexion
- Universal Scene Description (USD)
- Send to
- Performance Guidelines
- Configuring Pens and Tablets
- Exporting the log file
- Exporting a DXDiag
-
Technical issues
-
GPU Issues
- Crash when working with overclocked GPU
- Forcing the external GPU on Mac OS
- GPU drivers compatibility
- GPU drivers crash with long computations (TDR crash)
- GPU has outdated drivers
- GPU is not recognized
- GPU is not recognized and is mentionned as GDI Generic
- Issues with Nvidia GPUs on recent Mac OS versions
- Multi/Bi-GPU
- Running on integrated GPU
- Painter doesn't start on the right GPU
- Startup Issues
- Rendering Issues
- Stability Issues
- Miscellaneous Issues
-
GPU Issues
-
Workflow Issues
- Export Issues
- Tools Issues
- Project Issues
- Library Issues
- Viewport Issues
- Plugins Issues
- License Issues
- Installation and preferences
- Configuration
- Resource management
- Scripts and plugins
- Release notes overview
- All Changes
- Version 10.1
- Version 10.0
- Version 9.1
-
Old versions
- Version 9.0
- Version 8.3
- Version 8.2
- Version 8.1
- Version 7.4
- Version 7.3
- Version 7.2
- Version 2021.1 (7.1.0)
- Version 2020.2 (6.2.0)
- Version 2020.1 (6.1.0)
- Version 2019.3
- Version 2019.2
- Version 2019.1
- Version 2018.3
- Version 2018.2
- Version 2018.1
- Version 2017.4
- Version 2017.3
- Version 2017.2
- Version 2017.1
- Version 2.6
- Version 2.5
- Version 2.4
- Version 2.3
- Version 2.2
- Substance 3D home
- Home
-
Getting Started
- Getting Started overview
- Activation and licenses
- System requirements
- Project creation
-
Export
- Export overview
- Export window
- Export presets
- Glossary
- Performance
-
Interface
- Assets
- Substance 3D Assets
- Color picker
- Display settings
- History
- Layer stack
- Main menu
- Project configuration
- Properties
- Settings
- Shader settings
- Texture Set
- Toolbars
- Viewport
- Miscellaneous
-
Painting
- Painting overview
- Tool list
- Straight line
- Lazy mouse
- Symmetry
- Fill projections
-
Presets
- Presets overview
- Creating and saving presets
- Creating particles presets
- Photoshop brush presets (ABR)
- Dynamic strokes
- Advanced channel painting
- Vector graphic (.svg & .ai)
- Text resource
- Effects
- Baking
-
Content
- Creating custom effects
- Importing assets
-
Features
- Automatic UV Unwrapping
- Physical size
- Smart Materials and Masks
- Subsurface Scattering
- Dynamic Material Layering
- UV Reprojection
- UV Tiles
- Color Management
- Post Processing
- Iray Renderer
- Plugins
- Sparse Virtual Textures
- Custom Shaders
- SpaceMouse® by 3Dconnexion
- Universal Scene Description (USD)
- Send to
-
Technical Support
- Performance Guidelines
- Configuring Pens and Tablets
- Exporting the log file
- Exporting a DXDiag
-
Technical issues
-
GPU Issues
- Crash when working with overclocked GPU
- Forcing the external GPU on Mac OS
- GPU drivers compatibility
- GPU drivers crash with long computations (TDR crash)
- GPU has outdated drivers
- GPU is not recognized
- GPU is not recognized and is mentionned as GDI Generic
- Issues with Nvidia GPUs on recent Mac OS versions
- Multi/Bi-GPU
- Running on integrated GPU
- Painter doesn't start on the right GPU
- Startup Issues
- Rendering Issues
- Stability Issues
- Miscellaneous Issues
-
GPU Issues
-
Workflow Issues
- Export Issues
- Tools Issues
- Project Issues
- Library Issues
- Viewport Issues
- Plugins Issues
- License Issues
-
Pipeline and integration
- Installation and preferences
- Configuration
- Resource management
-
Release notes
- Release notes overview
- All Changes
- Version 10.1
- Version 10.0
- Version 9.1
-
Old versions
- Version 9.0
- Version 8.3
- Version 8.2
- Version 8.1
- Version 7.4
- Version 7.3
- Version 7.2
- Version 2021.1 (7.1.0)
- Version 2020.2 (6.2.0)
- Version 2020.1 (6.1.0)
- Version 2019.3
- Version 2019.2
- Version 2019.1
- Version 2018.3
- Version 2018.2
- Version 2018.1
- Version 2017.4
- Version 2017.3
- Version 2017.2
- Version 2017.1
- Version 2.6
- Version 2.5
- Version 2.4
- Version 2.3
- Version 2.2
Lib PBR Aniso - Shader API
lib-pbr-aniso.glsl
Public Functions: normal_distrib G1 visibility cook_torrance_contrib importanceSampleGGX probabilityGGX pbrComputeSpecularAnisotropic
Import from library
import lib-pbr.glsl
import lib-pbr.glsl
import lib-pbr.glsl
BRDF related functions
float normal_distrib(
vec3 localH,
vec2 alpha)
{
localH.xy /= alpha;
float tmp = dot(localH, localH);
return 1.0 / (M_PI * alpha.x * alpha.y * tmp * tmp);
}
float G1(
vec3 localW,
vec2 alpha)
{
// One generic factor of the geometry function divided by ndw
localW.xy *= alpha;
return 2.0 / (localW.z + length(localW));
}
float visibility(
vec3 localL,
vec3 localV,
vec2 alpha)
{
// visibility is a Cook-Torrance geometry function divided by (n.l)*(n.v)
return G1(localL, alpha) * G1(localV, alpha);
}
vec3 cook_torrance_contrib(
float vdh,
float ndh,
vec3 localL,
vec3 localE,
vec3 Ks,
vec2 alpha)
{
// This is the contribution when using importance sampling with the GGX based
// sample distribution. This means ct_contrib = ct_brdf / ggx_probability
return fresnel(vdh, Ks) * (visibility(localL, localE, alpha) * vdh * localL.z / ndh);
}
vec3 importanceSampleGGX(vec2 Xi, vec2 alpha)
{
float phi = 2.0 * M_PI * Xi.x;
vec2 slope = sqrt(Xi.y / (1.0 - Xi.y)) * alpha * vec2(cos(phi), sin(phi));
return normalize(vec3(slope, 1.0));
}
float probabilityGGX(vec3 localH, float vdh, vec2 alpha)
{
return normal_distrib(localH, alpha) * localH.z / (4.0 * vdh);
}
vec3 pbrComputeSpecularAnisotropic(LocalVectors vectors, vec3 specColor, vec2 roughness)
{
vec3 radiance = vec3(0.0);
vec2 alpha = roughness * roughness;
mat3 TBN = mat3(vectors.tangent, vectors.bitangent, vectors.normal);
vec3 localE = vectors.eye * TBN;
for(int i=0; i<nbSamples; ++i)
{
vec2 Xi = fibonacci2DDitheredTemporal(i, nbSamples);
vec3 localH = importanceSampleGGX(Xi, alpha);
vec3 localL = reflect(-localE, localH);
if (localL.z > 0.0)
{
vec3 Ln = TBN * localL;
float vdh = max(1e-8, dot(localE, localH));
float fade = horizonFading(dot(vectors.vertexNormal, Ln), horizonFade);
float pdf = probabilityGGX(localH, vdh, alpha);
float lodS = max(roughness.x, roughness.y) < 0.01 ? 0.0 : computeLOD(Ln, pdf);
// Offset lodS to trade bias for more noise
lodS -= 1.0;
vec3 preconvolvedSample = envSampleLOD(Ln, lodS);
radiance +=
fade * cook_torrance_contrib(vdh, localH.z, localL, localE, specColor, alpha) *
preconvolvedSample;
}
}
return radiance / float(nbSamples);
}
float normal_distrib(
vec3 localH,
vec2 alpha)
{
localH.xy /= alpha;
float tmp = dot(localH, localH);
return 1.0 / (M_PI * alpha.x * alpha.y * tmp * tmp);
}
float G1(
vec3 localW,
vec2 alpha)
{
// One generic factor of the geometry function divided by ndw
localW.xy *= alpha;
return 2.0 / (localW.z + length(localW));
}
float visibility(
vec3 localL,
vec3 localV,
vec2 alpha)
{
// visibility is a Cook-Torrance geometry function divided by (n.l)*(n.v)
return G1(localL, alpha) * G1(localV, alpha);
}
vec3 cook_torrance_contrib(
float vdh,
float ndh,
vec3 localL,
vec3 localE,
vec3 Ks,
vec2 alpha)
{
// This is the contribution when using importance sampling with the GGX based
// sample distribution. This means ct_contrib = ct_brdf / ggx_probability
return fresnel(vdh, Ks) * (visibility(localL, localE, alpha) * vdh * localL.z / ndh);
}
vec3 importanceSampleGGX(vec2 Xi, vec2 alpha)
{
float phi = 2.0 * M_PI * Xi.x;
vec2 slope = sqrt(Xi.y / (1.0 - Xi.y)) * alpha * vec2(cos(phi), sin(phi));
return normalize(vec3(slope, 1.0));
}
float probabilityGGX(vec3 localH, float vdh, vec2 alpha)
{
return normal_distrib(localH, alpha) * localH.z / (4.0 * vdh);
}
vec3 pbrComputeSpecularAnisotropic(LocalVectors vectors, vec3 specColor, vec2 roughness)
{
vec3 radiance = vec3(0.0);
vec2 alpha = roughness * roughness;
mat3 TBN = mat3(vectors.tangent, vectors.bitangent, vectors.normal);
vec3 localE = vectors.eye * TBN;
for(int i=0; i<nbSamples; ++i)
{
vec2 Xi = fibonacci2DDitheredTemporal(i, nbSamples);
vec3 localH = importanceSampleGGX(Xi, alpha);
vec3 localL = reflect(-localE, localH);
if (localL.z > 0.0)
{
vec3 Ln = TBN * localL;
float vdh = max(1e-8, dot(localE, localH));
float fade = horizonFading(dot(vectors.vertexNormal, Ln), horizonFade);
float pdf = probabilityGGX(localH, vdh, alpha);
float lodS = max(roughness.x, roughness.y) < 0.01 ? 0.0 : computeLOD(Ln, pdf);
// Offset lodS to trade bias for more noise
lodS -= 1.0;
vec3 preconvolvedSample = envSampleLOD(Ln, lodS);
radiance +=
fade * cook_torrance_contrib(vdh, localH.z, localL, localE, specColor, alpha) *
preconvolvedSample;
}
}
return radiance / float(nbSamples);
}
float normal_distrib( vec3 localH, vec2 alpha) { localH.xy /= alpha; float tmp = dot(localH, localH); return 1.0 / (M_PI * alpha.x * alpha.y * tmp * tmp); } float G1( vec3 localW, vec2 alpha) { // One generic factor of the geometry function divided by ndw localW.xy *= alpha; return 2.0 / (localW.z + length(localW)); } float visibility( vec3 localL, vec3 localV, vec2 alpha) { // visibility is a Cook-Torrance geometry function divided by (n.l)*(n.v) return G1(localL, alpha) * G1(localV, alpha); } vec3 cook_torrance_contrib( float vdh, float ndh, vec3 localL, vec3 localE, vec3 Ks, vec2 alpha) { // This is the contribution when using importance sampling with the GGX based // sample distribution. This means ct_contrib = ct_brdf / ggx_probability return fresnel(vdh, Ks) * (visibility(localL, localE, alpha) * vdh * localL.z / ndh); } vec3 importanceSampleGGX(vec2 Xi, vec2 alpha) { float phi = 2.0 * M_PI * Xi.x; vec2 slope = sqrt(Xi.y / (1.0 - Xi.y)) * alpha * vec2(cos(phi), sin(phi)); return normalize(vec3(slope, 1.0)); } float probabilityGGX(vec3 localH, float vdh, vec2 alpha) { return normal_distrib(localH, alpha) * localH.z / (4.0 * vdh); } vec3 pbrComputeSpecularAnisotropic(LocalVectors vectors, vec3 specColor, vec2 roughness) { vec3 radiance = vec3(0.0); vec2 alpha = roughness * roughness; mat3 TBN = mat3(vectors.tangent, vectors.bitangent, vectors.normal); vec3 localE = vectors.eye * TBN; for(int i=0; i<nbSamples; ++i) { vec2 Xi = fibonacci2DDitheredTemporal(i, nbSamples); vec3 localH = importanceSampleGGX(Xi, alpha); vec3 localL = reflect(-localE, localH); if (localL.z > 0.0) { vec3 Ln = TBN * localL; float vdh = max(1e-8, dot(localE, localH)); float fade = horizonFading(dot(vectors.vertexNormal, Ln), horizonFade); float pdf = probabilityGGX(localH, vdh, alpha); float lodS = max(roughness.x, roughness.y) < 0.01 ? 0.0 : computeLOD(Ln, pdf); // Offset lodS to trade bias for more noise lodS -= 1.0; vec3 preconvolvedSample = envSampleLOD(Ln, lodS); radiance += fade * cook_torrance_contrib(vdh, localH.z, localL, localE, specColor, alpha) * preconvolvedSample; } } return radiance / float(nbSamples); }