Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Colored flood fill lighting #428

Open
wants to merge 76 commits into
base: 1.20
Choose a base branch
from

Conversation

spiralhalo
Copy link
Collaborator

@spiralhalo spiralhalo commented Jun 23, 2023

Overview

This PR adds client-side colored lights that works via flood fill propagation. The light source data is gathered from the Block Light API, which falls back to Item Light API, then finally vanilla MC light level.

Light propagation hooks to region (chunk) building for block updates, which was already optimized through occlusion culling. This ensures minimal memory usage.

The actual propagation and texture uploads are done in the Render Thread. Only queued regions are updated to minimize impact on frame time.

API

Below is the description of the API. You may also find a basic implementation of the API in this PR's files and by turning on the Abstract pipeline.

Block Light API

Is described as .json files located in namespace:lights/block and namespace:lights/fluid paths.

The design of the json API is based on both Material Map and Item Light APIs.

There are two root objects: "defaultLight", which specifies the default light values, and "variants" which specifies light values for each block state variant.

The light values are described with "red", "green", and "blue", but with one main difference which is that light intensity is specified as "lightLevel" and uses values of 0-15. Each field is optional and will fall back to the "defaultLight" value when absent. If "lightLevel" is absent from "defaultLight", it will fall back to the server-side value.

Example json:

{
  "defaultLight": {
    "red": 0.2,
    "green": 0.2,
    "blue": 0.2
  },
  "variants": {
    "color=red": {
      "lightLevel": 14.0,
      "red": 1.0
    },
    "color=green": {
      "lightLevel": 14.0,
      "green": 1.0
    },
    "color=blue": {
      "lightLevel": 14.0,
      "blue": 1.0
    }
  }
}

Note that as this feature is client-side, it obviously won't affect server-side light levels. To achieve harmony between visuals and gameplay, mods need to synchronize server-side light level via other means. Care needs to be taken as luminance is perceived differently in colored lights than vanilla lighting.

Pipeline API

To enable colored lights, the pipeline needs to contain a coloredLights json object. It may have one optional field useOcclusionData to declare whether the pipeline intends to use occlusion data. Note that occlusion data isn't guaranteed to be available, see the Shader API section for the specifics.

Example json:

  coloredLights: {
    useOcclusionData: false
  }

Pipeline pass shaders may access the light data by passing "frex:textures/auto/colored_lights" to a Sampler2D sampler. For material shaders, see the Shader API section.

Shader API

TODO: explain

frex:shaders/api/sampler.glsl

For material and pipeline write shaders:

#ifdef COLORED_LIGHTS_ENABLED

uniform sampler2D frxs_lightData;

vec4 frx_getLightFiltered(worldPos);
vec4 frx_getLightRaw(worldPos);
vec3 frx_getLight(worldPos, fallback);

#endif

frex:shaders/api/light.glsl

For pipeline pass shaders:

#ifdef COLORED_LIGHTS_ENABLED

vec4 frx_getLightFiltered(sampler2D lightSampler, vec3 worldPos);

vec4 frx_getLightRaw(sampler2D lightSampler, vec3 worldPos);

vec3 frx_getLight(sampler2D lightSampler, vec3 worldPos, vec3 fallback);

bool frx_lightDataExists(sampler2D lightSampler, vec3 worldPos);

#ifdef LIGHT_DATA_HAS_OCCLUSION
struct frx_LightData {
	vec4 light;
	bool isLightSource;
	bool isOccluder;
	bool isFullCube;
};

frx_LightData frx_getLightOcclusionData(sampler2D lightSampler, vec3 worldPos);
#endif

#endif

Pipeline pass shaders may access the light data by passing "frex:textures/auto/colored_lights" to a Sampler2D sampler.

Shader usage technical limitations

  • Due to the nature of rendering, surfaces need to sample the light volume at a tiny offset based on surface normal (e.g. fragPos + normal * 0.05). Volumetric sampling should be unaffected

Technical Details

TBA (Grondag mostly knows these already as he came up with some of it)

Region building hook

Sparse allocation

Propagation / Region light updates

Future Performance Considerations

The following are features that are not part of this PR, but may be implemented in the future:

Using swap texture to prevent pipeline stalling

Currently not considered due to the rarity of light texture update. This could be beneficial however in situations where light is changed very often, e.g. TNT explosion or multiplayer with many on-screen players.

Doing light propagation in a separate thread

This could help with initial chunk building time by not committing texture update until light propagation finishes in a background thread. Texture and uniform updates still need to happen in the Render thread, naturally.

Light data caching on the disk

This might help alleviate long propagation times by saving and loading propagation results. This however could pose a problem as unlike vanilla lighting, colored lights is client-side and is easily changed through resource packs. Therefore, any form of light cache are expected to be invalidated frequently and care needs to be taken to minimize these invalidation as to not defeat the purpose of having a cache.

In addition to that, this requires benchmarks so that caching (specifically the disk read/write part) is actually faster than computing on-the-fly.

Lastly, it's important to note that this system is non-trivial to implement against the current "volatile" data management system.

Additional Changes

In addition to colored flood fill, there are some incidental changes:

  • PipelineDescription now loads every pipeline fully to assess the usage of Fabulous (no purpose, but was there from the beginning), Shadows, and Colored Lights.
    • Necessary to determine whether to reload all chunks when switching pipelines. Fast pipeline switching is good when possible
    • This impacts resource reload times "slightly"
    • Assuming the user don't have many pipelines as active resourcepack, or only has the active pipeline as active resourcepack, then the impact on resource reload is negligible.
  • Added space before folder path in shader compile error log so IntellijIDEA can recognize it and turn it into hyperlink

Light removal is still somewhat broken and
sometimes cause lingering light data
+ Ensure widening cast safety
- Enqueue only occlusion change
- Compare based on pure light
- Skip empty queue (don't upload)
Except for light sources which propagate in every direction.
Bright nodes found while looping through light removal (decrease)
queue are treated as light sources.
- Fix light source restoration; was blocked by occlusion check
Don't use queue since we already have per region queue
Add froglight colors
Rename light data texture to "canvas:alpha/light_data"
Cleanup cruft
- API registry only holds pure RGB
- Always cache all light
- Restructure and separate "API" from internal code
- Remove decrease self occlusion check completely,
  Occluding blocks should be able to propagate decrease
  outwards after all.
- Add more filtering for increase queuing
- Some simplifications
…entity

- Rename VirtualLightManager to LightLevel
- Make item light encoding consistent in LightRegistry and everywhere
- Reformat
- Entity JSON light is a simple light without predicate
- CachedBlockLight -> FloodFillBlockLight, make all values consistent
- `blaze` and `glow_squid` light in canvas/default resource pack
- EntityLightProvider API (unused for now)
- More robust LightLevel and EntityLightTracker reload
- More robust CanvasState requireReload
Our flood fill-based model doesn't support HDR, so it's better to preserve
the color hue instead of clipping to white on high intensity.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant