Last updated on
Jul 13, 2023
- 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
PBR Material Layering - Shader API
Import from libraries.
import lib-pbr.glsl import lib-emissive.glsl import lib-sampler.glsl import lib-utils.glsl #define NB_MATERIALS 4 #define NB_MASKS (NB_MATERIALS - 1) //: metadata { //: "custom-ui": "material-layering/custom-ui.qml" //: } //: materials [ //: { //: "id": "Material1", //: "label": "Material 1", //: "default": "", //: "size": 1024, //: "default_color": [0.5, 0.5, 0.5] //: }, //: { //: "id": "Material2", //: "label": "Material 2", //: "default": "", //: "size": 1024, //: "default_color": [0.5, 0.5, 0.5] //: }, //: { //: "id": "Material3", //: "label": "Material 3", //: "default": "", //: "size": 1024, //: "default_color": [0.5, 0.5, 0.5] //: }, //: { //: "id": "Material4", //: "label": "Material 4", //: "default": "", //: "size": 1024, //: "default_color": [0.5, 0.5, 0.5] //: } //: ] //: stacks [ //: { //: "id": "Mask", //: "channels": //: [ //: {"id": "blendingmask"} //: ] //: }, //: { //: "id": "Mask2", //: "channels": //: [ //: {"id": "blendingmask"} //: ] //: }, //: { //: "id": "Mask3", //: "channels": //: [ //: {"id": "blendingmask"} //: ] //: } //: ] //: param custom { "default": false, "label": "Debug Mode" } uniform bool DebugMode; //: param custom { //: "default": 0, //: "label": "Debug channel", //: "widget": "combobox", //: "values": { //: "BaseColor": 0, //: "Roughness": 1, //: "Metallic": 2, //: "Normal (Material)": 3, //: "Normal (Masks)": 4, //: "Normal (Combined)": 5, //: "Mask 1": 6, //: "Mask 2": 7, //: "Mask 3": 8 //: } //: } uniform int DebugChannel; //: param custom { "default": false, "label": "Normal from Masks" } uniform bool UseNormalFromMask;
Channels needed for metal/rough workflow are bound here.
//: param auto texture_normal; uniform sampler2D mesh_normal_texture; //: param custom { "default": 5, "label": "Material 1 coords", "min": 0.01, "max": 128.0, "group" : "Material 1" } uniform float u_coords1; //: param custom { "default": 5, "label": "Material 2 coords", "min": 0.01, "max": 128.0, "group" : "Material 2" } uniform float u_coords2; //: param custom { "default": 5, "label": "Material 3 coords", "min": 0.01, "max": 128.0, "group" : "Material 3" } uniform float u_coords3; //: param custom { "default": 5, "label": "Material 4 coords", "min": 0.01, "max": 128.0, "group" : "Material 4" } uniform float u_coords4; //: param custom { "default": 1, "label": "Normal Intensity 1", "min": 0.0, "max": 1.0, "group" : "Material 1" } uniform float normal_intensity1; //: param custom { "default": 1, "label": "Normal Intensity 2", "min": 0.0, "max": 1.0, "group" : "Material 2" } uniform float normal_intensity2; //: param custom { "default": 1, "label": "Normal Intensity 3", "min": 0.0, "max": 1.0, "group" : "Material 3" } uniform float normal_intensity3; //: param custom { "default": 1, "label": "Normal Intensity 4", "min": 0.0, "max": 1.0, "group" : "Material 4" } uniform float normal_intensity4; //: param custom { "default": 0, "label": "Normal from Mask Intensity 2", "min": -10.0, "max": 10.0, "group" : "Material 2" } uniform float mask_normal_intensity1; //: param custom { "default": 0, "label": "Normal from Mask Intensity 3", "min": -10.0, "max": 10.0, "group" : "Material 3" } uniform float mask_normal_intensity2; //: param custom { "default": 0, "label": "Normal from Mask Intensity 4", "min": -10.0, "max": 10.0, "group" : "Material 4" } uniform float mask_normal_intensity3; //: param custom { "default": 0.1, "label": "Normal from Mask 1 Offset", "min": 0.0, "max": 1, "group" : "Material 2" } uniform float mask_normal_offset1; //: param custom { "default": 0.1, "label": "Normal from Mask 2 Offset", "min": 0.0, "max": 1, "group" : "Material 3" } uniform float mask_normal_offset2; //: param custom { "default": 0.1, "label": "Normal from Mask 3 Offset", "min": 0.0, "max": 1, "group" : "Material 4" } uniform float mask_normal_offset3; //: param auto Material1.channel_basecolor uniform sampler2D color1; //: param auto Material1.channel_roughness uniform sampler2D rough1; //: param auto Material1.channel_metallic uniform sampler2D metal1; //: param auto Material1.channel_normal uniform sampler2D normal1; //: param auto Material2.channel_basecolor uniform sampler2D color2; //: param auto Material2.channel_roughness uniform sampler2D rough2; //: param auto Material2.channel_metallic uniform sampler2D metal2; //: param auto Material2.channel_normal uniform sampler2D normal2; //: param auto Material3.channel_basecolor uniform sampler2D color3; //: param auto Material3.channel_roughness uniform sampler2D rough3; //: param auto Material3.channel_metallic uniform sampler2D metal3; //: param auto Material3.channel_normal uniform sampler2D normal3; //: param auto Material4.channel_basecolor uniform sampler2D color4; //: param auto Material4.channel_roughness uniform sampler2D rough4; //: param auto Material4.channel_metallic uniform sampler2D metal4; //: param auto Material4.channel_normal uniform sampler2D normal4; //: param auto Mask.channel_blendingmask uniform SamplerSparse mask; //: param auto Mask2.channel_blendingmask uniform SamplerSparse mask2; //: param auto Mask3.channel_blendingmask uniform SamplerSparse mask3; ///////////////////////////////////////// ////////// BLENDING FUNCTIONS /////////// ///////////////////////////////////////// float mixGrayscale( float channelSampled[NB_MATERIALS], float Masks[NB_MASKS]) { float result = channelSampled[0]; for (int i = 0; i < NB_MASKS; i++) result = mix(result, channelSampled[i + 1], Masks[i]); return result; } vec3 mixColor( vec3 channelSampled[NB_MATERIALS], float Masks[NB_MASKS]) { vec3 result = channelSampled[0]; for (int i = 0; i < NB_MASKS; i++) result = mix(result, channelSampled[i + 1], Masks[i]); return result; } vec3 mixNormal( vec3 channelSampled[NB_MATERIALS], float Masks[NB_MASKS], float NormalIntensity[NB_MATERIALS]) { vec3 result = NormalIntensity[0] * channelSampled[0]; for (int i = 0; i < NB_MASKS; i++) result = mix(result, NormalIntensity[i + 1] * channelSampled[i + 1], Masks[i]); return result; } vec3 NormalFromMask(SamplerSparse Mask, float Offset, float Intensity, SparseCoord UVs, float refMask) { vec4 results[2]; vec2 offsets[2] = vec2[2]( vec2(Offset * 0.001, 0.0), vec2(0.0, Offset * 0.001) ); textureSparseOffsets(Mask, UVs, offsets, results); float Channel1 = results[0].r - refMask; float Channel2 = results[1].r - refMask; return vec3(-Intensity * Channel1, -Intensity * Channel2, 1.0); } vec3 NormalFromMasks( vec3 normalFromMaskSampled[NB_MASKS], float Masks[NB_MASKS]) { vec3 result = normalFromMaskSampled[0]; for (int i = 1; i < NB_MASKS; i++) result = mix(result, normalFromMaskSampled[i], Masks[i]); return result; } void shade(V2F inputs) {
//Global textures
// Get detail (ambient occlusion) and global (shadow) occlusion factors float occlusion = getAO(inputs.sparse_coord) * getShadowFactor(); vec3 mesh_normal = normalUnpack(textureSparse(base_normal_texture, inputs.sparse_coord), base_normal_y_coeff);
//Materials Masks
float UVscale[NB_MATERIALS] = float[NB_MATERIALS]( u_coords1, u_coords2, u_coords3, u_coords4); float NormalIntensity[NB_MATERIALS] = float[NB_MATERIALS]( normal_intensity1, normal_intensity2, normal_intensity3, normal_intensity4); float MaskNormalOffset[NB_MASKS] = float[NB_MASKS]( mask_normal_offset1, mask_normal_offset2, mask_normal_offset3); float MaskNormalIntensity[NB_MASKS] = float[NB_MASKS]( mask_normal_intensity1, mask_normal_intensity2, mask_normal_intensity3); float Masks[NB_MASKS] = float[NB_MASKS]( textureSparse(mask , inputs.sparse_coord).r, textureSparse(mask2, inputs.sparse_coord).r, textureSparse(mask3, inputs.sparse_coord).r); float roughSampled[NB_MATERIALS] = float[NB_MATERIALS]( getRoughness(rough1, inputs.tex_coord*UVscale[0]), getRoughness(rough2, inputs.tex_coord*UVscale[1]), getRoughness(rough3, inputs.tex_coord*UVscale[2]), getRoughness(rough4, inputs.tex_coord*UVscale[3]) ); float metallicSampled[NB_MATERIALS] = float[NB_MATERIALS]( getMetallic(metal1, inputs.tex_coord*UVscale[0]), getMetallic(metal2, inputs.tex_coord*UVscale[1]), getMetallic(metal3, inputs.tex_coord*UVscale[2]), getMetallic(metal4, inputs.tex_coord*UVscale[3]) ); vec3 basecolorSampled[NB_MATERIALS] = vec3[NB_MATERIALS]( getBaseColor(color1, inputs.tex_coord*UVscale[0]), getBaseColor(color2, inputs.tex_coord*UVscale[1]), getBaseColor(color3, inputs.tex_coord*UVscale[2]), getBaseColor(color4, inputs.tex_coord*UVscale[3]) ); vec3 normalSampled[NB_MATERIALS] = vec3[NB_MATERIALS]( normalUnpack(texture(normal1, inputs.tex_coord*UVscale[0])), normalUnpack(texture(normal2, inputs.tex_coord*UVscale[1])), normalUnpack(texture(normal3, inputs.tex_coord*UVscale[2])), normalUnpack(texture(normal4, inputs.tex_coord*UVscale[3])) );
//Mixing
float roughness = mixGrayscale(roughSampled, Masks); float metallic = mixGrayscale(metallicSampled, Masks); vec3 basecolor = mixColor(basecolorSampled, Masks); vec3 diffColor = generateDiffuseColor(basecolor, metallic); vec3 specColor = generateSpecularColor(basecolor, metallic); float specOcclusion = specularOcclusionCorrection(occlusion, metallic, roughness); //Normal channel vec3 normal = mixNormal(normalSampled, Masks, NormalIntensity); normal = normalize( vec3(normal.xy + mesh_normal.xy, mesh_normal.z) ); //UDN combine method vec3 finalNormal = normal; vec3 normalMask = vec3(0.0, 0.0, 1.0); if( UseNormalFromMask ) { vec3 normalFromMaskSampled[NB_MASKS] = vec3[NB_MASKS]( NormalFromMask(mask , MaskNormalOffset[0], MaskNormalIntensity[0], inputs.sparse_coord, Masks[0]), NormalFromMask(mask2, MaskNormalOffset[1], MaskNormalIntensity[1], inputs.sparse_coord, Masks[1]), NormalFromMask(mask3, MaskNormalOffset[2], MaskNormalIntensity[2], inputs.sparse_coord, Masks[2]) ); normalMask = NormalFromMasks(normalFromMaskSampled, Masks); finalNormal = normalize( vec3(finalNormal.xy + normalMask.xy, finalNormal.z) ); //UDN combine method }
//Final
//Debug mode display result of combined channels or Masks if( !DebugMode ) { vec3 finalNormalWorldSpace = normalize( finalNormal.x * inputs.tangent + finalNormal.y * inputs.bitangent + finalNormal.z * inputs.normal); // Feed parameters for a physically based BRDF integration. LocalVectors vectors = computeLocalFrame(inputs, finalNormalWorldSpace, 0.0); emissiveColorOutput(pbrComputeEmissive(emissive_tex, inputs.sparse_coord)); diffuseShadingOutput(occlusion * pbrComputeDiffuse(vectors.normal, diffColor)); specularShadingOutput(specOcclusion * pbrComputeSpecular(vectors, specColor, roughness)); } else { vec3 result; //BaseColor combined if( DebugChannel == 0 ) { result = basecolor; } //Roughness combined else if( DebugChannel == 1 ) { result = vec3(roughness); } //Metallic combined else if( DebugChannel == 2 ) { result = vec3(metallic); } //Normal combined else if( DebugChannel == 3) { normal = 0.5 * normal + vec3(0.5); result = sRGB2linear(normal); } //Combined masks as Normal else if( DebugChannel == 4 ) { normalMask = 0.5 * normalMask + vec3(0.5); result = sRGB2linear(normalMask); } //Final Normal else if( DebugChannel == 5 ) { finalNormal = 0.5 * finalNormal + vec3(0.5); result = sRGB2linear(finalNormal); } //Mask(s) else { result = vec3(sRGB2linear(Masks[DebugChannel - 6])); } diffuseShadingOutput(result); } }