Shaders - Development#

Shaders add a powerful system of rendering light, the elements of the world, and more.

_images/icon22.png

Sparkling sunshine on water#

Danger

This document is exceedingly long.

Caution

This document assumes good knowledge of how shaders work. If not, see below.

See also

See https://www.seas.upenn.edu/~cis565/fbo.htm for an in-depth, advanced tutorial on OpenGL
See https://open.gl/ for an intermediate, medium-length tutorial on OpenGL

Overview#

The Shaders mod makes use of a deferred rendering pipeline.

The gbuffer shaders come first in the pipeline. They render data to textures that will be sent to the composite shaders. Optional composite shaders can be added after the shadow map (shadowcomp), before terrain (prepare) and before water rendering (deferred). The composite shaders then render to textures that will be sent to the final shader.

The final shader renders directly to the screen.

Dimension shaders#

Shaders can be separated by world dimension by placing them in folder /shaders/world<id>, where id is the world dimension. When the world folder is present, the shaders will be loaded only from there; they ignores the default folder. Creating an empty world folder effectively disables the shaders for that world dimension. Mod world dimensions should also work.

Only .vsh and .fsh files are loaded from the dimension folder.

Example:

  • /shaders: default shaders

  • /shaders/world-1: nether shaders

  • /shaders/world1: end shaders

Dimension folders are also scanned for options. The options in dimension folders may be given different names to avoid conflict with default values.

The #include directive found in .vsh and .fsh files is replaced with the contents of the included file:

#include "const.inc"
#include "/world-55/lib.inc"

Included files may include other files.

Caution

The maximum include depth is limited to 10.

To avoid code duplication on nested inclusions, the following can be used:

// File A

#ifndef INCLUDE_A
#define INCLUDE_A
...
#endif

Note

When Minecraft is started with argument, -Dshaders.debug.save=true, then the final shaders will be saved in shaderpacks/debug/.

Files#

All shader files are placed in the folder shaders/ of the shader pack. The shader source files use the name of the program in which they are to be used with extension depending on their type.

Extension

Type

.csh

Compute shader

.vsh

Vertex shader

.gsh

Geometry shader

.fsh

Fragment shader

Geometry shaders need either OpenGL 3.2 with layout qualifiers or the extension GL_ARB_geometry_shader4 (GL_EXT_geometry_shader4) with configuration “maxVerticesOut”.

Compute shaders#

A list of compute shaders can be attached to every program except gbuffers programs. They are named like the program with optional suffix, for example “composite.csh”, “composite_a.csh” … “composite_z.csh”.

Compute shaders run before the program and can read from all buffers using texture samplers. They can read and write to colortex0-5 and shadowcolor0-1 buffers as images using the aliases colorimg0-5 and shadowcolorimg0-1, for example: layout (rgba8) uniform image2D colorimg0;.

Compute shaders need at least “#version 430” and local size definition, for example: layout (local_size_x = 16, local_size_y = 16) in;. Work groups are defined either fixed via const ivec3 workGroups = ivec3(50, 30, 1); or relative to render size via const vec2 workGroupsRender = vec2(0.5f, 0.5f);. The default configuration is const vec2 workGroupsRender = vec2(1.0f, 1.0f);, which executes the compute shader once per pixel.

Image access#

All programs can read and write to colorimg0-5 and shadowcolorimg0-1 using imageLoad() and imageStore().

Attributes#

Source

Value

Comment

in vec3 vaPosition;

position (x, y, z)

1.17+, for terrain it is relative to the chunk origin, see ‘chunkOffset’

in vec4 vaColor;

color (r, g, b, a)

1.17+

in vec2 vaUV0;

texture (u, v)

1.17+

in ivec2 vaUV1;

overlay (u, v)

1.17+

in ivec2 vaUV2;

lightmap (u, v)

1.17+

in vec3 vaNormal;

normal (x, y, z)

1.17+

in vec3 mc_Entity;

xy = blockId, renderType

‘blockId’ is used only for blocks specified in ‘block.properties’

in vec2 mc_midTexCoord;

st = midTexU, midTexV

Sprite middle UV coordinates

in vec4 at_tangent;

xyz = tangent vector, w = handedness

in vec3 at_velocity;

vertex offset to previous frame

In view space, only for entities and block entities

in vec3 at_midBlock;

offset to block center in 1/64m units

Only for blocks

Block render layers#

See Block Render Layers.


🆚️ This documentation assumes the latest OptiFine version. Notes are not made for legacy versions (1.8).
🔙️ This documentation is updated to commit 8410499f.
©️ This file is offered without any copyright restrictions. Please copy and modify it to suit your needs. Credit is optional, but appreciated.