Skip to content

Pipeline Dynamic Properties

spiralhalo edited this page Jul 24, 2022 · 15 revisions

Dynamic Properties v1.0

Since https://github.com/vram-guild/canvas/pull/389, pipeline configuration can now have dynamic properties that are based on user configuration!

What it is

Dynamic properties are values that are resolved when compiling the pipeline, based on user configuration. Dynamic properties can be applied to any part of the pipeline configuration of certain types, in particular: Integers, Floats, Booleans, Strings (names, resource locations, and GL enums), as well as framebuffer attachments.

How to use it

Replace a constant value with a dynamic property object. There are two types of dynamic property objects: single option source and option map. Take a look at the following example.

Example A: Single option source

sky: {
	defaultZenithAngle: 15
},

Using dynamic properties, we can change these config on the fly based on user choices:

sky: {
	// single option source
	// default is used when the named option can't be found or is incompatible
	defaultZenithAngle: { default: 15, option: "sky_zenith_angle" }
},

The name of the option being used for its value is referenced using the option field of the dynamic property object. The value of default field is used when the referenced option can't be found or when the referenced option has incompatible type.

Example B: Option map

In a more advanced example, option map can be used to switch between different samplers. The following is possible:

fabulous: {
	passes: [
		{
			name: "color",
			program: "color",
			framebuffer: "color",
			samplerImages: [
				"gbuffer",
				"minecraft:textures/environment/sun.png",
				{
					// default choice
					default: "minecraft:textures/environment/moon_phases.png",
					optionMap: {
						// mapping an enum option `moon_texture` to texture location
						moon_texture: [
							{ from: "hd", to: "example_pipeline:textures/environment/moon_phases_hd.png" },
							{ from: "toon", to: "example_pipeline:textures/environment/moon_phases_toon.png" }
						]
					}
				}
			]
		},
	]
}

In case of option maps, the value of the referenced option are compared against a map in order to resolve the final value. Multiple options can be used in a single map. If the map couldn't resolve any value, the default value is used.

Note that defining a default in either cases is optional, but it's recommended to do so as a safety precaution. If a value resolution failed but no default value is defined, the pipeline might fail to compile in the worst case scenario.

Format

Single option source

{
	default: <default_value>,
	option: "<option_reference>"
}

Option map

{
	default: <default_value>,
	optionMap: {
		<option_reference_a>: [
			{
				from: <condition_a1>,
				to: <result_a1>
			},
			{
				from: <condition_a2>,
				to: <result_a2>
			},
			// <...>
		],
		<OPTIONAL_option_reference_b>: [
			{
				from: <condition_b1>,
				to: <result_b1>
			},
			{
				from: <condition_b2>,
				to: <result_b2>
			},
			// <...>
		],
		<OPTIONAL_option_reference_c>: [
			{
				from: <condition_c1>,
				to: <result_c1>
			},
			{
				from: <condition_c2>,
				to: <result_c2>
			},
			// <...>
		],
		// <...>
	}
}

Both single option source and option map can't be used at the same time. If both are present, the result is undefined.

Supported types

The following property types are supported:

Primitives:

  • Int
  • Float
  • Boolean
  • String types:
    • Named configuration reference (framebuffers, images, programs, and so on)
    • Resource location (shader and texture locations)
    • Sampler uniform names
    • GL Enums

Special types:

  • Framebuffer attachment objects

The following option types are supported:

  • Int
  • Float
  • Boolean
  • Enum (value is treated as String)

Precaution for string types

Despite enum options being treated as String, it is recommended to map their values instead of using them directly. This is because enum types are technically case-sensitive, but they are always presented as ALL CAPS in the GUI and shader result. Therefore using an enum option value directly may result in undefined or inconsistent behavior.

This rule does not apply to GL Enum types as GL Enum are converted to ALL CAPS during lookup.

Framebuffer attachment object support

Framebuffer attachment objects' properties are typically inseparable. For example, an image with LOD is always tied to its LOD, and an array image is always tied to a specific layer. For this purpose, it is possible to map an option directly into whole framebuffer attachment objects. Take a look at the following example where an array texture is used in place of normal texture when certain option is enabled:

Example C: Selecting framebuffer attachment using a map

{
	name: "solid",
	depthAttachment: {image: "vanilla_depth", clearDepth: 1.0},
	colorAttachments: [
		{image: "vanilla_color", clearColor: 0x00000000},
		{
			default: {image: "gbuffer_solid_light", clearColor: 0x00000000},
			optionMap: {
				render_reflection: [
					{ from: true, to: {image: "gbuffer_lightnormal", layer: 0, clearColor: 0x00000000}}
				]
			}
		}
	]
}

Supported properties

The following properties are supported:

  • All top level pipeline configuration properties
  • Draw targets properties
  • Image properties
  • Material program properties
  • Framebuffer properties
    • Framebuffer attachment object within the colorAttachments array
    • Individual framebuffer attachment properties
  • Pass properties
    • Sampler images within the samplerImages array
  • Sky properties
  • Sky shadow properties

The following properties are NOT supported:

  • Option properties
  • Dynamic properties within dynamic properties
  • Json file inclusions (include arrays)

Backwards compatibility

Older version of Canvas before dynamic properties can't understand pipelines that use dynamic properties. For pipeline developers: please inform the users of your pipeline to use the correct version of Canvas.