vram-guild / canvas

Shader-Based Minecraft Renderer for Fabric
GNU Lesser General Public License v3.0
415 stars 40 forks source link

Dynamic properties in pipeline configuration #389

Closed spiralhalo closed 1 year ago

spiralhalo commented 1 year ago

Definition

Dynamic properties are properties of pipeline (sub-)configuration that may be derived from the state of the user's pipeline options. For example, previously the size of an image config is always a constant, but now it may be derived from an int option.

Usage

Since this PR, there are 3 ways to define a property (examples are in json5 format):

  1. Constant value
size: 128
  1. Use option value
size: {
  default: 128,
  useOption: "texture_size"
}

Notes:

  1. Use mapping
size: {
  default: 128,
  useOptionMap: {
    option: "texture_size_selection",
    map: [
      {
        condition: "large",
        value: 256
      },
      {
        condition: "medium",
        value: 128
      },
      {
        condition: "small",
        value: 64
      }
    ]
}

Notes:

Supported uses

Exceptions and Limitations

If there is any property that is otherwise unsupported, it is a bug and please report it.

Backward compatibility

Canvas will stay backward compatible with older pipelines. However, newer pipelines utilizing the dynamic properties won't be compatible with older Canvas. This is for simplicity reason, and not unreasonable as the current standard for "shaderpacks" (i.e. Iris/OF) is to provide support older version manually. Explicit support for 1.18.2 is already planned and prepared for.

Implementation detail

This system works by first loading option configuration and stored option values before anything else in the pipeline, then applying those stored option values while reading the dynamic properties. No extra memory or execution footprint persists after the pipeline is fully loaded and running.

spiralhalo commented 1 year ago

Can't think of anything else to add. Will merge ASAP unless someone gave further reviews, after doing some more rounds of testing.

Tests:

spiralhalo commented 1 year ago

I noticed while testing that the option map can be quite verbose, so I decided to shorten some keywords in order to speed up work on pipelines:

Additionally, option map format is simpler using the json key as option name. This is consistent with option config entry definition, but different enough to differentiate at a glance (and option config uses options and never singular option).

Note that the usage of json element key as the option key value also allows multiple options to be used in the map (because why not), in case anyone needs that for some reason.

Preview of this change:

Before

// single option
{
    useOption: "sky_color"
}

// option map
{
    default: "minecraft:textures/environment/moon_phases.png",
    useOptionMap: {
        option: "vanilla_moon",
        map: [
            {
                condition: false,
                value: "lumi:textures/misc/moon_phases.png"
            }
        ]
    }
},

After

// single option
{
    option: "sky_color"
}

// option map
{
    default: "minecraft:textures/environment/moon_phases.png",
    optionMap: {
        vanilla_moon: [
            { from: false, to: "lumi:textures/misc/moon_phases.png" }
        ]
    }
},
spiralhalo commented 1 year ago

Done testing. Made a documentation for this iteration: https://github.com/vram-guild/canvas/wiki/Pipeline-Dynamic-Properties

spiralhalo commented 1 year ago

UPDATE: Reason why array support is good.

Example of good dynamic array formatting (currently unsupported):

cascadeRadius: {
    default: [48, 16, 4],
    optionMap: {
        shadow_resolution: [
            { from: "256", to: [64, 32, 8] },
            { from: "512", to: [64, 32, 8] },
            { from: "1024", to: [64, 16, 8] },
            { from: "2048", to: [48, 16, 4] },
            { from: "4096", to: [48, 16, 4] },
        ]
    }
}

Actual currently supported formatting to achieve the same function as above:

cascadeRadius: [
    {
        default: 48,
        optionMap: {
            shadow_resolution: [
                { from: "256", to: 64},
                { from: "512", to: 64},
                { from: "1024", to: 64},
                { from: "2048", to: 48},
                { from: "4096", to: 48},
            ]
        }
    },
    {
        default: 16,
        optionMap: {
            shadow_resolution: [
                { from: "256", to: 32 },
                { from: "512", to: 32 },
                { from: "1024", to: 16 },
                { from: "2048", to: 16 },
                { from: "4096", to: 16 },
            ]
        }
    },
    {
        default: 4,
        optionMap: {
            shadow_resolution: [
                { from: "256", to: 8 },
                { from: "512", to: 8 },
                { from: "1024", to: 8 },
                { from: "2048", to: 4 },
                { from: "4096", to: 4 },
            ]
        }
    }
]

Based on example above, supporting dynamic arrays can increase formatting brevity on top of ease of reading and editing (which impacts the ease of development).

Further notes: