- Substance 3D home
- Home
- Getting Started
- Getting Started overview
- Activation and licenses
- System requirements
- Project creation
- Export
- Export overview
- Export window
- Export presets
- Export overview
- Glossary
- Performance
- Getting Started overview
- 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
- Assets
- 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
- Creating custom effects
- 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
- 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 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 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 ); }