Documentation for Substance 3D Painter is now available on Experience League. After March 14th, HelpX pages will automatically redirect to the equivalent Experience League page.
Refer to the FAQ for more information about which documentation is affected.
- Substance 3D home
- Home
- Getting Started
- Getting Started overview
- Activation and licenses
- System requirements
- Project creation
- Export
- Export overview
- Export window
- Output templates
- Export overview
- Glossary
- Getting Started overview
- Interface
- Interface overview
- 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
- Paint tools
- Path tools
- Path tool overview
- Paint along path
- Ribbon path
- Filled path
- Erase along path
- Smudge along path
- Straight line
- Lazy mouse
- Symmetry
- Fill projections
- Presets
- Presets overview
- Creating and saving presets
- Creating particles presets
- Photoshop brush presets
- Dynamic strokes
- Advanced channel painting
- Vector graphic (.svg & .ai)
- Text resource
- Effects
- Baking
- Content
- Creating custom effects
- Importing assets
- Creating custom effects
- Features
- Automatic resource update
- 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
- Scripting and development
- Scripts and plugins
- Shader API Reference
- Shader API overview
- Changelog - Shader API
- Libraries - Shader API
- Lib Alpha - Shader API
- Lib Bayer - Shader API
- Lib Defines - Shader API
- Lib Emissive - Shader API
- Lib Env - Shader API
- Lib Normal - Shader API
- Lib PBR - Shader API
- Lib PBR Aniso - Shader API
- Lib Pom - Shader API
- Lib Random - Shader API
- Lib Sampler - Shader API
- Lib Sparse - Shader API
- Lib SSS - Shader API
- Lib Utils - Shader API
- Lib Vectors - Shader API
- Parameters - Shader API
- Shaders - Shader API
- Release notes
- Release notes overview
- All Changes
- Version 11.1
- Version 11.0
- Version 10.1
- Known issues
- Old versions
- Version 10.0
- Version 9.1
- 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 Normal - Shader API
lib-normal.glsl
Public Functions: normalBlend normalBlendOriented normalFade normalUnpack normalFromBaseNormal normalFromNormal normalFromHeight getTSNormal computeWSBaseNormal computeWSNormal
Import from library
import lib-defines.glsl import lib-sparse.glsl
All engine parameters useful for normal-centric operations.
//: param auto channel_height uniform SamplerSparse height_texture; //: param auto channel_normal uniform SamplerSparse normal_texture; //: param auto texture_normal uniform SamplerSparse base_normal_texture; //: param auto normal_blending_mode uniform int normal_blending_mode;
Used to invert the Y axis of the normal map
//: param auto normal_y_coeff uniform float base_normal_y_coeff;
Empirically determined by our artists...
const float HEIGHT_FACTOR = 400.0;
Perform the blending between 2 normal maps
This is based on Whiteout blending http://blog.selfshadow.com/publications/blending-in-detail/
vec3 normalBlend(vec3 baseNormal, vec3 overNormal)
{
return normalize(vec3(
baseNormal.xy + overNormal.xy,
baseNormal.z * overNormal.z));
}
Perform a detail oriented blending between 2 normal maps
This is based on Detail Oriented blending http://blog.selfshadow.com/publications/blending-in-detail/
vec3 normalBlendOriented(vec3 baseNormal, vec3 overNormal)
{
baseNormal.z += 1.0;
overNormal.xy = -overNormal.xy;
return normalize(baseNormal * dot(baseNormal,overNormal) -
overNormal*baseNormal.z);
}
Returns a normal flattened by an attenuation factor
vec3 normalFade(vec3 normal,float attenuation)
{
if (attenuation<1.0 && normal.z<1.0)
{
float phi = attenuation * acos(normal.z);
normal.xy *= 1.0/sqrt(1.0-normal.z*normal.z) * sin(phi);
normal.z = cos(phi);
}
return normal;
}
Unpack a normal w/ alpha channel
vec3 normalUnpack(vec4 normal_alpha, float y_coeff)
{
if (normal_alpha.a == 0.0 || normal_alpha.xyz == vec3(0.0)) {
return vec3(0.0, 0.0, 1.0);
}
// Attenuation in function of alpha
vec3 normal = normal_alpha.xyz/normal_alpha.a * 2.0 - vec3(1.0);
normal.y *= y_coeff;
normal.z = max(1e-3, normal.z);
normal = normalize(normal);
normal = normalFade(normal, normal_alpha.a);
return normal;
}
Unpack a normal w/ alpha channel, no Y invertion
vec3 normalUnpack(vec4 normal_alpha)
{
return normalUnpack(normal_alpha, 1.0);
}
Compute the tangent space normal from document's height channel
vec3 normalFromHeight(SparseCoord coord, float height_force)
{
// Normal computation using height map
// Determine gradient offset in function of derivatives
vec2 dfd = max(coord.dfdx,coord.dfdy);
dfd = max(dfd,height_texture.size.zw);
vec2 dfdx,dfdy;
textureSparseQueryGrad(dfdx, dfdy, height_texture, coord);
float h_r = textureGrad(height_texture.tex, coord.tex_coord+vec2( dfd.x, 0 ), dfdx, dfdy).r;
float h_l = textureGrad(height_texture.tex, coord.tex_coord+vec2(-dfd.x, 0 ), dfdx, dfdy).r;
float h_t = textureGrad(height_texture.tex, coord.tex_coord+vec2( 0, dfd.y), dfdx, dfdy).r;
float h_b = textureGrad(height_texture.tex, coord.tex_coord+vec2( 0, -dfd.y), dfdx, dfdy).r;
float h_rt = textureGrad(height_texture.tex, coord.tex_coord+vec2( dfd.x, dfd.y), dfdx, dfdy).r;
float h_lt = textureGrad(height_texture.tex, coord.tex_coord+vec2(-dfd.x, dfd.y), dfdx, dfdy).r;
float h_rb = textureGrad(height_texture.tex, coord.tex_coord+vec2( dfd.x, -dfd.y), dfdx, dfdy).r;
float h_lb = textureGrad(height_texture.tex, coord.tex_coord+vec2(-dfd.x, -dfd.y), dfdx, dfdy).r;
vec2 dh_dudv = (0.5 * height_force) / dfd * vec2(
2.0*(h_l-h_r)+h_lt-h_rt+h_lb-h_rb,
2.0*(h_b-h_t)+h_rb-h_rt+h_lb-h_lt);
return normalize(vec3(dh_dudv, HEIGHT_FACTOR));
}
Helper to compute the tangent space normal from base normal and a height value, and an optional detail normal.
vec3 getTSNormal(SparseCoord coord, vec3 normalFromHeight)
{
vec3 normal = normalBlendOriented(
normalUnpack(textureSparse(base_normal_texture, coord), base_normal_y_coeff),
normalFromHeight);
if (normal_texture.is_set) {
vec3 channelNormal = normalUnpack(textureSparse(normal_texture, coord));
if (normal_blending_mode == BlendingMode_Replace) {
normal = normalBlendOriented(normalFromHeight, channelNormal);
} else if (normal_blending_mode == BlendingMode_NM_Combine) {
normal = normalBlendOriented(normal, channelNormal);
}
}
return normal;
}
Helper to compute the tangent space normal from base normal and height, and an optional detail normal.
vec3 getTSNormal(SparseCoord coord)
{
float height_force = 1.0;
vec3 normalH = normalFromHeight(coord, height_force);
return getTSNormal(coord, normalH);
}
Helper to compute the world space normal from tangent space base normal.
vec3 computeWSBaseNormal(SparseCoord coord, vec3 tangent, vec3 bitangent, vec3 normal)
{
vec3 normal_vec = normalUnpack(textureSparse(normal_texture, coord), base_normal_y_coeff);
return normalize(
normal_vec.x * tangent +
normal_vec.y * bitangent +
normal_vec.z * normal
);
}
Helper to compute the world space normal from tangent space normal given by getTSNormal helpers, and local frame of the mesh.
vec3 computeWSNormal(SparseCoord coord, vec3 tangent, vec3 bitangent, vec3 normal)
{
vec3 normal_vec = getTSNormal(coord);
return normalize(
normal_vec.x * tangent +
normal_vec.y * bitangent +
normal_vec.z * normal
);
}