- New Programs
- Enhanced Custom Textures
- Defines / Feature Flags
- Uniforms
- Shader Properties
- Custom Entity ID's
- Item and Armor Detection
- Dimension Folders
- Color Spaces
- Reverse Shadow Culling
- Light Block Voxelization
- Hybrid-Deferred Entities
- Separate Hardware Shadow Samplers
- Shader Storage Buffer Objects
- Custom Images
- Extended Shadowcolor
This program renders all solid terrain, that is terrain with no transparency or cutouts. When using a core profile you can safely avoid using discard
in this program, which preserves early z testing.
gbuffers_terrain_solid
This program renders all cutout terrain, that is terrain with cutouts and no other transparency. When using core profile, discard
should be used below a threshold alpha to achieve the cutout.
gbuffers_terrain_cutout
This program renders all entities that are marked translucent and have blending enabled. If this program is not used, all entities will be rendered with gbuffers_entities
.
gbuffers_entities_translucent
This program renders all block entities that are marked translucent and have blending enabled. If this program is not used, all block entities will be rendered with gbuffers_block
.
gbuffers_block_translucent
This program renders all non-translucent particles. If this program is not used, all particles will be rendered with textured_lit
.
gbuffers_particles
This program renders all translucent particles with blending enabled. If this program is not used, all translucent particles will be rendered with particles
.
This can be combined with Particle Ordering to render translucent particles after the deferred pass.
gbuffers_particles_translucent
The begin program is a new composite pass that runs before the shadow pass, and is intended to be used for setting up any data that is needed for the shadow pass. It can be used as a normal composite.
begin
The setup pass can only be used as a compute pass, and is only run once, during the pack load or when the screen size changes. However, you can use a_z suffixes to have multiple compute passes.
setup.csh
setup_a.csh ... setup_z.csh
Instead of using the OptiFine format of replacing a color texture with a custom texture, you can define entirely custom textures to use in programs. This completely sidesteps the obsolete requirements of sacrificing a color texture. However, this does not change the amount of textures (16/32 depending on machine) you can use in a program at a given time. Enhanced custom textures are avaliable from any program, similar to custom images.
Just like the Optifine format, enhanced custom textures can load textures from the shader pack directory, the resource pack, or dynamic textures such as a texture atlas or lightmap. These follow the same syntax as in Optifine.
customTexture.name = <path> <type> <internalFormat> <dimensions> <pixelFormat> <pixelType>
uniform sampler2D name;
You can check for the define IS_IRIS
to check for Iris support.
Feature flags are a new system in Iris to query the existence of certain features. To activate them use iris.features.required
to show an error if your PC or Iris doesn't support a feature, or use iris.features.optional
to get a define with the feature name IRIS_FEATURE_X
if the feature is supported.
If one wants to activate multiple feature flags, one has to add them in the same line separted by space iris.features.required/optional = FEATURE_FLAG_A FEATURE_FLAG_B
The currently added feature flags are:
SEPARATE_HARDWARE_SAMPLERS
(required for Separate Hardware Shadow Samplers)
PER_BUFFER_BLENDING
COMPUTE_SHADERS
ENTITY_TRANSLUCENT
(recommended, but not required for Entity Translucent)
SSBO
(required for Shader Storage Buffer Objects)
CUSTOM_IMAGES
(required for Custom Images)
HIGHER_SHADOWCOLOR
(required for Extended Shadowcolor)
REVERSED_CULLING
(recommended, but not required for Reverse Shadow Culling)
BLOCK_EMISSION_ATTRIBUTE
(recommended, but not required for [Block Emission: at_midBlock.w] as of [iris-1.7.0-snapshotmc1.20.4-a787322])
This value reads the position of a lightning bolt currently being rendered. If there are none, zero is returned. If there is at least one, w
is set to 1. If there are multiple,
a random one is chosen.
uniform vec4 lightningBoltPosition;
This value controls the "thunder strength", equivalent to Optifine's rainStrength for thunder.
uniform float thunderStrength;
These are multiple declarations to read player health, air, and hunger. Armor was added in 1.6.15.
The uniforms marked with current
are 0-1. To get them as a full value, multiply them by their max
values.
uniform float currentPlayerHealth;
uniform float maxPlayerHealth;
uniform float currentPlayerAir;
uniform float maxPlayerAir;
uniform float currentPlayerHunger;
uniform float maxPlayerHunger;
uniform float currentPlayerArmor;
uniform float maxPlayerArmor;
These uniforms read multiple aspects of the camera.
eyePosition
stores the world space position of the player's head model. When in first person view, this is equivalent to cameraPosition
. However in third person mode the two will differ as the camera and player's head are now in different locations.
uniform bool firstPersonCamera;
uniform bool isSpectator;
uniform vec3 eyePosition;
These uniforms read multiple aspects of the player model and camera.
relativeEyePosition
reads the world space offset from the player model's head position to the camera's position(ie cameraPosition
- eyePosition
).
playerLookVector
reads the world alligned direction the player model's head is facing. This facing direction is not affected by animations such as swimming.
playerBodyVector
reads the world alligned direction the player model's body is facing, although this behavior is currently broken and reads the same value as playerLookVector
.
uniform vec3 relativeEyePosition;
uniform vec3 playerLookVector;
uniform vec3 playerBodyVector;
These uniforms read many aspects of the dimension, such as the minimum/maximum height and ambient lighting.
uniform int bedrockLevel;
uniform int heightLimit;
uniform bool hasCeiling;
uniform bool hasSkylight;
uniform float ambientLight;
This uniform reads the logical height of the current dimension, which refers to the maximum height to which chorus fruits and nether portals can bring players within the dimension.
uniform int logicalHeightLimit;
This uniform reads the height of vanilla clouds in the current dimension in blocks. Value is NaN
for dimensions without clouds.
uniform float cloudHeight;
These boolean uniforms are true
while the condition they are named after is active.
is_hurt
is true
for a short time after the player is hurt for any reason, then returns to false
.
is_invisible
is true
both when using an invisibility potion and when in spectator mode.
uniform bool is_sneaking;
uniform bool is_sprinting;
uniform bool is_hurt;
uniform bool is_invisible;
uniform bool is_burning;
This boolean uniform is true
when the player is not flying and is on the ground, and false
otherwise.
uniform bool is_on_ground;
This value reads the color space used when displaying to the screen. 0 is sRGB, 1 is DCI_P3, 2 is Display P3, 3 is REC2020, 4 is Adobe RGB.
uniform int currentColorSpace;
These uniforms are used to identify and read aspects of the biome the player is currently in. These uniforms are defined the same as when using custom uniforms with these variables.
biome
identifies the biome currently occupied by the player. It's value can be compared with the same predefined constants as custom uniforms using biome, for example: BIOME_PLAINS
, BIOME_RIVER
, BIOME_DESERT
, BIOME_SWAMP
, etc.
biome_category
identifies the biome category currently occupied by the player. It's value can be compared with the same predefined constants as custom uniforms, the following are recognized:
CAT_NONE
, CAT_TAIGA
, CAT_EXTREME_HILLS
, CAT_JUNGLE
, CAT_MESA
, CAT_PLAINS
, CAT_SAVANNA
, CAT_ICY
, CAT_THE_END
, CAT_BEACH
, CAT_FOREST
, CAT_OCEAN
, CAT_DESERT
, CAT_RIVER
, CAT_SWAMP
, CAT_MUSHROOM
, CAT_NETHER
biome_precipitation
tells what type of precipitation occurs in this biome. 0 is no precipitation, 1 is rain, 2 is snow. The following defines can also be used: PPT_NONE
, PPT_RAIN
, PPT_SNOW
.
rainfall
and temperature
measure aspects of the biome as defined by Minecraft internally. In vanilla Minecraft this will range in value from -0.7 to 2.0, however mods may have values outside that range. For more information, see the Minecraft Wiki.
uniform int biome;
uniform int biome_category;
uniform int biome_precipitation;
uniform float rainfall;
uniform float temperature;
These uniforms allow shaders to access the OS reported date and time.
currentDate
is in the following format: ivec3(year, month, day)
currentTime
is in the following format: ivec3(hour, minute, second)
currentYearTime
is in the following format: ivec2(seconds_ellapsed_in_year, seconds_remaining_in_year)
uniform ivec3 currentDate;
uniform ivec3 currentTime;
uniform ivec2 currentYearTime;
This controls how particles will be rendered. There are 3 possible options for this value.
mixed
: Opaque particles are rendered before the deferred pass, and translucent particles are rendered after.
This is the default if no deferred passes are present.
after
: All particles are rendered after the deferred pass.
This is the default if there are any deferred passes.
before
: All particles are rendered before the deferred pass.
particles.ordering = mixed
shaders.properties
Normally Optifine/Iris will check if the shadow buffers are bound and used to determine when to enable/disable the shadow pass. Iris offers an additional explicit control for enabling/disabling the pass. Thic can be useful for voxelization which doesn't write to a shadowtex/shadowcolor buffer (for example SSBOs or custom images).
shadow.enabled = true
shadow.enabled = false
shaders.properties
This value controls the bounds for entity shadows to be rendered. By default, it is the value set for terrain. Any floating point number that is not 1 is multiplied by the terrain distance to get the final shadow distance multiplier.
const float entityShadowDistanceMul = 1.0f;
- Minimum Value: 0.01
- Default Value: Terrain value
- Out-of-range values behavior: Disable
- ❌ Vertex Shader (*.vsh)
- ❌ Geometry Shader (*.gsh)
- ✔️ Fragment Shader (*.fsh)
This value controls if the player should have a shadow rendered. This is forced on if shadowEntities (default true) is enabled. This also controls shadows of any entities the player is riding.
shadowPlayer = true
shaders.properties
This value controls if compute shaders within the same pass are allowed to run concurrently. For more information, reference Concurrency Between Compute Passes.
allowConcurrentCompute = true
shaders.properties
Iris hardcodes some custom entity ID's to detect specific things.
minecraft:entity_shadow
: The circular shadow under an entity when there is no shadow map.minecraft:entity_flame
: The flame when an entity is on fire.minecraft:zombie_villager_converting
: A zombie villager undergoing conversion.minecraft:player_cape
: Player cape (without elytra).minecraft:elytra_with_cape
: Player cape (with elytra).
Iris allows detecting items and armor during rendering on anything.
Using uniform int currentRenderedItemId;
, you can detect items and armor rendered in the level at the point of render.
There are some new ID's that can be detected alongside items and armor:
trim_material
to detect armor trims on armor. (For example, trim_emerald
).
When dimension.properties
is added to the shader pack root, behavior relating to dimensions change.
Iris will no longer resolve any dimensions for you, and you are expected to resolve you own. The syntax for dimension.properties is as follows:
dimension.<folderName> = <dimensionNamespace>:<dimensionPath>
<folderName>
: The name of the folder containing the shaders used for the given dimension.<dimensionNamespace>
: The namespace for the dimension, vanilla shaders will useminecraft
.<dimensionPath>
: The internal name of the dimension.
You can use *
as a value to fallback all dimensions.
The following example sets the shaders for the vanilla Nether dimension to the netherShaders
folder:
dimension.netherShaders = minecraft:the_nether
Iris 1.6.4 added support for additional color spaces beyond sRGB (DCI_P3, Display P3, REC2020, and Adobe RGB). This does not allow for outputting HDR values, it simply applies a tonemapping operation in the given color space instead of sRGB.
By default, Iris will assume all shaders output sRGB, and if a different color spaces is selected it will convert the sRGB output to that color space for display. If supportsColorCorrection = true
is in shaders.properties however, this conversion will be left up to the shader. In all scenarios, the chosen colorspace is avaliable through the uniform currentColorSpace
.
Setting shadow.culling = reversed
in shaders.properties will create an area around the player where geometry in the shadow pass will not be culled. Outside this area, geometry will be culled as if shadow culling was enabled. This "unculled" distance is controled with const float voxelDistance
, and the culled distance is controlled as normal with const float shadowDistance
(and cannot be lower than voxelDistance
). This feature is intended for packs which utilize both voxelization and a shadow map.
Using voxelizeLightBlocks
in shaders.properties, you can now voxelize light blocks in the shadow or main pass.
This only applies to light blocks (Minecraft Wiki), which are a specific block which is invisible but emits a specific level of light. This does not affect any other blocks or geometry.
Light blocks will be rendered as a single (degenerate) invisible quad with all points centered on the middle of the block. (at_midBlock
will be 0.) The ID will correspond as normal to the light block,
and UV will be 0. lmcoord.xy
will both be the value of the light made by the light block.
Using the new gbuffers_entities_translucent
and gbuffers_block_translucent
programs, you can now render entities and blocks in a hybrid deferred manner.
If separateEntityDraws
is true in shaders.properties
, entity draws will behave differently. During the main render, translucent entities and block entities will wait to be drawn until after the deferred pass,
and then will be drawn in the gbuffers_entities_translucent
and gbuffers_block_translucent
programs.
Separate hardware shadow samplers can be enabled using the feature flag for it.
When enabled and shadow hardware filtering is enabled via the hardware constant, shadowtex0
and shadowtex1
will no longer function as hardware samplers.
Instead, you can use shadowtex0HW
and shadowtex1HW
to sample using hardware shadow filtering and software at the same time
If the Feature Flag for extended shadowcolor is set, shadowcolor2
through shadowcolor7
is enabled.
These can be drawn to via DRAWBUFFERS
or RENDERTARGETS
in the shadow pass or shadow composites.
Shader Storage Buffer Objects (or SSBO's) are buffers that can store large amounts of data between shader invocations, and even between frames.
For more information about the limits of SSBO's in OpenGL, read https://www.khronos.org/opengl/wiki/Shader_Storage_Buffer_Object.
SSBO's can hold a guaranteed maximum of 128MB, and on most drivers can hold as much as the GPU physically alllows.
Iris will give an error and fail to load a shader if allocating an SSBO would otherwise use up too much VRAM.
To allocate an SSBO for a shaderpack, put the following in shaders.properties, where index can be between 0 and 8:
bufferObject.<index> = <byteSize> <isRelative> <scaleX> <scaleY>
To define the SSBO as fixed size, simply exclude the last three options and fill <byteSize>
with the size of the SSBO.
SSBOs can also be defined as screen-sized (Iris 1.6.6), where their size is relative to the screen dimensions. This is useful for storing data per-pixel. Fill <isRelative>
with true
, <scaleX>
and <scaleY>
then define the multipliers for the number of "pixels" in the SSBO relative to each screen dimension (i.e. 1.0 would mean the same dimension as the screen), and <byteSize>
defines the number of bytes per "pixel". The total size of the SSBO is calculated as int(viewWidth * scaleX) * int(viewHeight * scaleY) * byteSize
.
To use an SSBO in a shader, you must define it's layout. Here is an example definition of a SSBO, where bufferName can be any name:
This layout must be the same across all shaders, otherwise the data will get corrupted.
layout(std430, binding = index) buffer bufferName {
vec4 someData; // 16 bytes
float someExtraData; // 4 bytes
};
void main() {
someData = vec4(0); // Other shaders will see this
gl_FragColor = vec4(someExtraData); // Read from any previous shaders, or the previous frame if it was never overwritten
}
You can optionally make all the variables of an SSBO local to avoid redefinitions. To do this, declare an accessor for the SSBO, as the following.
layout(std430, binding = index) buffer bufferName {
vec4 someData; // 16 bytes
float someExtraData; // 4 bytes
} bufferAccess;
void main() {
bufferAccess.someData = vec4(0); // Other shaders will see this
gl_FragColor = vec4(bufferAccess.someExtraData); // Read from any previous shaders, or the previous frame if it was never overwritten
}
Custom images allow to write up to 8 custom full images of data.
For more info on allowed formats and restrictions, along for their use in shaders, read https://www.khronos.org/opengl/wiki/Image_Load_Store.
To declare a custom image, use the following in shaders.properties:
image.cimage1 = samplerAccess format internalFormat pixelType <shouldClearOnNewFrame> <isRelative> <relativeX/absoluteX> <relativeY/absoluteY> <absoluteZ>
For example, to declare a RGBA32F custom image half the screen size that does not clear, use the following:
image.cimage1 = cSampler1 rgba rgba32f float false true 0.5 0.5
And to declare a RGBA8 3D custom image with dimensions of 512x512x512 that clears every frame:
image.cimage1 = cSampler1 rgba rgba8 float true false 512 512 512
This image can be accessed in 2 ways:
The image can be written and read per-pixel by declaring it as an image
:
uniform image2D cimage1;
void main() {
vec4 previousValue = imageLoad(cimage1, vec2(0, 0)); // Reads from first pixel in the image
imageStore(cimage1, vec2(0, 0), vec4(1, 0, 0, 1)); // Writes to first pixel in the image
}
Or the image can be read with filtering as a sampler
:
uniform sampler2D cSampler1;
varying float viewWidth;
varying float viewHeight;
void main() {
gl_FragColor = texture2D(cSampler1, gl_FragCoord.xy / vec2(viewWidth, viewHeight)); // Samples the current pixel of the image with smooth linear filtering.
}