Spatial shaders

Spatial shaders are used for shading 3D objects. They are the most complex type of shader Godot offers. Spatial shaders are highly configurable with different render modes and different rendering options (e.g. Subsurface Scattering, Transmission, Ambient Occlusion, Rim lighting etc). Users can optionally write vertex, fragment, and light processor functions to affect how objects are drawn.

Render modes

Render modeDescription
blend_mixMix blend mode (alpha is transparency), default.
blend_addAdditive blend mode.
blend_subSubtractive blend mode.
blend_mulMultiplicative blend mode.
depth_draw_opaqueOnly draw depth for opaque geometry (not transparent).
depth_draw_alwaysAlways draw depth (opaque and transparent).
depth_draw_neverNever draw depth.
depth_draw_alpha_prepassDo opaque depth pre-pass for transparent geometry.
depth_test_disableDisable depth testing.
cull_frontCull front-faces.
cull_backCull back-faces (default).
cull_disabledCulling disabled (double sided).
unshadedResult is just albedo. No lighting/shading happens in material.
diffuse_lambertLambert shading for diffuse (default).
diffuse_lambert_wrapLambert wrapping (roughness dependent) for diffuse.
diffuse_oren_nayarOren Nayar for diffuse.
diffuse_burleyBurley (Disney PBS) for diffuse.
diffuse_toonToon shading for diffuse.
specular_schlick_ggxSchlick-GGX for specular (default).
specular_blinnBlinn for specular (compatibility).
specular_phongPhong for specular (compatibility).
specular_toonToon for specular.
specular_disabledDisable specular.
skip_vertex_transformVERTEX/NORMAL/etc. need to be transformed manually in vertex function.
world_vertex_coordsVERTEX/NORMAL/etc. are modified in world coordinates instead of local.
ensure_correct_normalsUse when non-uniform scale is applied to mesh.
vertex_lightingUse vertex-based lighting.
shadows_disabledDisable computing shadows in shader.
ambient_light_disabledDisable contribution from ambient light and radiance map.

Vertex built-ins

Values marked as “in” are read-only. Values marked as “out” are for optional writing and will not necessarily contain sensible values. Values marked as “inout” provide a sensible default value, and can optionally be written to. Samplers are not subjects of writing and they are not marked.

Vertex data (VERTEX, NORMAL, TANGENT, BITANGENT) are presented in local model space. If not written to, these values will not be modified and be passed through as they came.

They can optionally be presented in world space by using the world_vertex_coords render mode.

Users can disable the built-in modelview transform (projection will still happen later) and do it manually with the following code:

  1. shader_type spatial;
  2. render_mode skip_vertex_transform;
  3. void vertex() {
  4. VERTEX = (MODELVIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
  5. NORMAL = (MODELVIEW_MATRIX * vec4(NORMAL, 0.0)).xyz;
  6. // same as above for binormal and tangent, if normal mapping is used
  7. }

Other built-ins, such as UV, UV2 and COLOR, are also passed through to the fragment function if not modified.

Users can override the modelview and projection transforms using the POSITION built-in. When POSITION is used, the value from VERTEX is ignored and projection does not happen. However, the value passed to the fragment shader still comes from VERTEX.

For instancing, the INSTANCE_CUSTOM variable contains the instance custom data. When using particles, this information is usually:

  • x: Rotation angle in radians.
  • y: Phase during lifetime (0 to 1).
  • z: Animation frame.

This allows you to easily adjust the shader to a particle system using default particles material. When writing a custom particles shader, this value can be used as desired.

Built-inDescription
inout mat4 WORLD_MATRIXModel space to world space transform.
in mat4 INV_CAMERA_MATRIXWorld space to view space transform.
inout mat4 PROJECTION_MATRIXView space to clip space transform.
in mat4 CAMERA_MATRIXView space to world space transform.
inout mat4 MODELVIEW_MATRIXModel space to view space transform (use if possible).
inout mat4 INV_PROJECTION_MATRIXClip space to view space transform.
in float TIMEElapsed total time in seconds.
in vec2 VIEWPORT_SIZESize of viewport (in pixels).
inout vec3 VERTEXVertex in local coordinates.
inout vec3 NORMALNormal in local coordinates.
inout vec3 TANGENTTangent in local coordinates.
inout vec3 BINORMALBinormal in local coordinates.
inout vec2 UVUV main channel.
inout vec2 UV2UV secondary channel.
inout vec4 COLORColor from vertices.
inout float POINT_SIZEPoint size for point rendering.
out vec4 POSITIONIf written to, overrides final vertex position.
in int INSTANCE_IDInstance ID for instancing.
in vec4 INSTANCE_CUSTOMInstance custom data (for particles, mostly).
out float ROUGHNESSRoughness for vertex lighting.
in bool OUTPUT_IS_SRGBTrue when calculations happen in sRGB color space (true in GLES2, false in GLES3).

Fragment built-ins

The default use of a Godot fragment processor function is to set up the material properties of your object and to let the built-in renderer handle the final shading. However, you are not required to use all these properties, and if you don’t write to them, Godot will optimize away the corresponding functionality.

Built-inDescription
in vec4 FRAGCOORDCoordinate of pixel center. In screen space. xy specifies position in window, z specifies fragment depth if DEPTH is not used. Origin is lower-left.
in mat4 WORLD_MATRIXModel space to world space transform.
in mat4 INV_CAMERA_MATRIXWorld space to view space transform.
in mat4 CAMERA_MATRIXView space to world space transform.
in mat4 PROJECTION_MATRIXView space to clip space transform.
in mat4 INV_PROJECTION_MATRIXClip space to view space transform.
in float TIMEElapsed total time in seconds.
in vec2 VIEWPORT_SIZESize of viewport (in pixels).
in vec3 VERTEXVertex that comes from vertex function (default, in view space).
in vec3 VIEWVector from camera to fragment position (in view space).
in bool FRONT_FACINGTrue if current face is front face.
inout vec3 NORMALNormal that comes from vertex function (default, in view space).
inout vec3 TANGENTTangent that comes from vertex function.
inout vec3 BINORMALBinormal that comes from vertex function.
out vec3 NORMALMAPSet normal here if reading normal from a texture instead of NORMAL.
out float NORMALMAP_DEPTHDepth from variable above. Defaults to 1.0.
in vec2 UVUV that comes from vertex function.
in vec2 UV2UV2 that comes from vertex function.
in vec4 COLORCOLOR that comes from vertex function.
out vec3 ALBEDOAlbedo (default white).
out float ALPHAAlpha (0..1); if written to, the material will go to the transparent pipeline.
out float METALLICMetallic (0..1).
out float SPECULARSpecular. Defaults to 0.5, best not to modify unless you want to change IOR.
out float ROUGHNESSRoughness (0..1).
out float RIMRim (0..1). If used, Godot calculates rim lighting.
out float RIM_TINTRim Tint, goes from 0 (white) to 1 (albedo). If used, Godot calculates rim lighting.
out float CLEARCOATSmall added specular blob. If used, Godot calculates Clearcoat.
out float CLEARCOAT_GLOSSGloss of Clearcoat. If used, Godot calculates Clearcoat.
out float ANISOTROPYFor distorting the specular blob according to tangent space.
out vec2 ANISOTROPY_FLOWDistortion direction, use with flowmaps.
out float SSS_STRENGTHStrength of Subsurface Scattering. If used, Subsurface Scattering will be applied to object.
out vec3 TRANSMISSIONTransmission mask (default 0,0,0). Allows light to pass through object. Only applied if used.
out float AOStrength of Ambient Occlusion. For use with pre-baked AO.
out float AO_LIGHT_AFFECTHow much AO affects lights (0..1; default 0).
out vec3 EMISSIONEmission color (can go over 1,1,1 for HDR).
sampler2D SCREEN_TEXTUREBuilt-in Texture for reading from the screen. Mipmaps contain increasingly blurred copies.
sampler2D DEPTH_TEXTUREBuilt-in Texture for reading depth from the screen. Must convert to linear using INV_PROJECTION.
out float DEPTHCustom depth value (0..1).
in vec2 SCREEN_UVScreen UV coordinate for current pixel.
in vec2 POINT_COORDPoint Coordinate for drawing points with POINT_SIZE.
out float ALPHA_SCISSORIf written to, values below a certain amount of alpha are discarded.
in bool OUTPUT_IS_SRGBTrue when calculations happen in sRGB color space (true in GLES2, false in GLES3).

Light built-ins

Writing light processor functions is completely optional. You can skip the light function by setting render_mode to unshaded. If no light function is written, Godot will use the material properties written to in the fragment function to calculate the lighting for you (subject to the render_mode).

To write a light function, assign something to DIFFUSE_LIGHT or SPECULAR_LIGHT. Assigning nothing means no light is processed.

The light function is called for every light in every pixel. It is called within a loop for each light type.

Below is an example of a custom light function using a Lambertian lighting model:

  1. void light() {
  2. DIFFUSE_LIGHT += dot(NORMAL, LIGHT) * ATTENUATION * ALBEDO;
  3. }

If you want the lights to add together, add the light contribution to DIFFUSE_LIGHT using +=, rather than overwriting it.

Built-inDescription
in vec4 FRAGCOORDCoordinate of pixel center. In screen space. xy specifies position in window, z specifies fragment depth if DEPTH is not used. Origin is lower-left.
in mat4 WORLD_MATRIXModel space to world space transform.
in mat4 INV_CAMERA_MATRIXWorld space to view space transform.
in mat4 CAMERA_MATRIXView space to world space transform.
in mat4 PROJECTION_MATRIXView space to clip space transform.
in mat4 INV_PROJECTION_MATRIXClip space to view space transform.
in float TIMEElapsed total time in seconds.
in vec2 VIEWPORT_SIZESize of viewport (in pixels).
in vec3 NORMALNormal vector, in view space.
in vec3 VIEWView vector, in view space.
in vec3 LIGHTLight Vector, in view space.
in vec3 LIGHT_COLORColor of light multiplied by energy.
in vec3 ATTENUATIONAttenuation based on distance or shadow.
in vec3 ALBEDOBase albedo.
in vec3 TRANSMISSIONTransmission mask.
in float ROUGHNESSRoughness.
out vec3 DIFFUSE_LIGHTDiffuse light result.
out vec3 SPECULAR_LIGHTSpecular light result.
in bool OUTPUT_IS_SRGBTrue when calculations happen in sRGB color space (true in GLES2, false in GLES3).