From b11c1cfbbfd729a216bd0074ab65a6d6eee6aee7 Mon Sep 17 00:00:00 2001
From: pkuzic
Date: Fri, 25 Sep 2026 05:17:50 +0100
Subject: [PATCH] MONKEY (sky): SKY_FX / SKY_FX_CLOUDS pipeline keys so Classic
compiles the reference shader unchanged
Co-Authored-By: Claude Opus 5.5
---
crates/benilla-world/src/clouds/layer.rs | 22 +++++++++++++++++++-
crates/benilla-world/src/shaders/cloud.wgsl | 19 +++++++++++------
crates/benilla-world/src/shaders/sky.wgsl | 7 ++++++-
crates/benilla-world/src/shaders/sky_fx.wgsl | 2 +-
crates/benilla-world/src/sky.rs | 22 +++++++++++++++++++-
5 files changed, 62 insertions(+), 10 deletions(-)
diff --git a/crates/benilla-world/src/clouds/layer.rs b/crates/benilla-world/src/clouds/layer.rs
index b76e8024..fc495faf 100644
--- a/crates/benilla-world/src/clouds/layer.rs
+++ b/crates/benilla-world/src/clouds/layer.rs
@@ -29,6 +29,7 @@ pub type CloudMaterial = ExtendedMaterial;
/// The colored cloud texture. The color math is CPU-side as in the reference, so the texels are
/// raw gamma bytes in a non-sRGB texture.
#[derive(Asset, AsBindGroup, Clone, TypePath)]
+#[bind_group_data(CloudFxKey)]
pub struct CloudExt {
/// The colored tile, alpha the coverage, re-uploaded each regen (`0x58ac70`).
#[texture(100)]
@@ -43,6 +44,19 @@ pub struct CloudExt {
pub(crate) lit: Vec4,
}
+/// MONKEY (sky): the pipeline key: High compiles `SKY_FX_CLOUDS` into `cloud.wgsl`; below High
+/// the reference's code runs with nothing added.
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct CloudFxKey {
+ high: bool,
+}
+
+impl From<&CloudExt> for CloudFxKey {
+ fn from(e: &CloudExt) -> Self {
+ Self { high: e.fx.x >= 1.5 }
+ }
+}
+
impl MaterialExtension for CloudExt {
/// The shared sky vertex stage, which pins every sky vertex to the far depth.
fn vertex_shader() -> ShaderRef {
@@ -57,8 +71,14 @@ impl MaterialExtension for CloudExt {
_pipeline: &MaterialExtensionPipeline,
descriptor: &mut RenderPipelineDescriptor,
_layout: &MeshVertexBufferLayoutRef,
- _key: MaterialExtensionKey,
+ key: MaterialExtensionKey,
) -> Result<(), SpecializedMeshPipelineError> {
+ // MONKEY (sky): the High cloud branch.
+ if key.bind_group_data.high {
+ if let Some(fragment) = descriptor.fragment.as_mut() {
+ fragment.shader_defs.push("SKY_FX_CLOUDS".into());
+ }
+ }
sky_pipeline_state(descriptor);
Ok(())
}
diff --git a/crates/benilla-world/src/shaders/cloud.wgsl b/crates/benilla-world/src/shaders/cloud.wgsl
index 91b18485..d2413618 100644
--- a/crates/benilla-world/src/shaders/cloud.wgsl
+++ b/crates/benilla-world/src/shaders/cloud.wgsl
@@ -7,7 +7,9 @@
// Ported from WarcraftXL (https://github.com/WarcraftXL) by iThorgrim — module wxl-retail-clouds, Clouds.cpp.
#import bevy_pbr::forward_io::VertexOutput
+#ifdef SKY_FX_CLOUDS
#import benilla_world::sky_fx
+#endif
@group(#{MATERIAL_BIND_GROUP}) @binding(100) var cloud_tex: texture_2d;
@group(#{MATERIAL_BIND_GROUP}) @binding(101) var cloud_samp: sampler;
@@ -21,6 +23,7 @@ struct CloudFx {
};
@group(#{MATERIAL_BIND_GROUP}) @binding(102) var cfx: CloudFx;
+#ifdef SKY_FX_CLOUDS
// MONKEY (sky): coverage with detail at a sheet point; `oct` detail octaves.
fn detailed_cover(uv: vec2, oct: i32) -> f32 {
let a = textureSampleLevel(cloud_tex, cloud_samp, uv, 0.0).a;
@@ -29,13 +32,16 @@ fn detailed_cover(uv: vec2, oct: i32) -> f32 {
}
return sky_fx::cloud_erode(a, sky_fx::cloud_detail(uv, cfx.fx.y, oct));
}
+#endif
@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4 {
let texel = textureSample(cloud_tex, cloud_samp, in.uv);
var a = texel.a;
var rgb = texel.rgb;
- // MONKEY (sky): High only; Classic and Enhanced keep the kernel's texels as they are.
+ // MONKEY (sky): High only (the `SKY_FX_CLOUDS` pipeline); Classic and Enhanced keep the
+ // kernel's texels as they are.
+#ifdef SKY_FX_CLOUDS
if (cfx.fx.x >= 1.5) {
let n = sky_fx::cloud_detail(in.uv, cfx.fx.y, 4);
a = sky_fx::cloud_erode(a, n);
@@ -44,19 +50,20 @@ fn fragment(in: VertexOutput) -> @location(0) vec4 {
let strength = cfx.lit.w;
if (a > 0.003 && strength > 0.0) {
let sd = cfx.fx.zw;
- let step = 0.011;
- var occl = detailed_cover(in.uv + sd * step, 2);
- occl += detailed_cover(in.uv + sd * step * 2.0, 2) * 0.75;
- occl += detailed_cover(in.uv + sd * step * 3.5, 2) * 0.5;
+ let stp = 0.011;
+ var occl = detailed_cover(in.uv + sd * stp, 2);
+ occl += detailed_cover(in.uv + sd * stp * 2.0, 2) * 0.75;
+ occl += detailed_cover(in.uv + sd * stp * 3.5, 2) * 0.5;
let transmit = exp(-occl * 1.44 * strength);
// WarcraftXL's ambient floor 0.55, softened toward the painted texel.
let light = 0.62 + 0.38 * transmit;
- let ahead = detailed_cover(in.uv + sd * step * 1.5, 2);
+ let ahead = detailed_cover(in.uv + sd * stp * 1.5, 2);
let rim = max(ahead - a, 0.0) * (1.0 - a) * transmit * strength;
rgb = rgb * mix(1.0, light, strength) + cfx.lit.rgb * rim * 0.9;
rgb = min(rgb, vec3(1.0));
}
}
+#endif
#ifdef VERTEX_COLORS
a *= in.color.a; // the dome's rim fade (ring alphas)
#endif
diff --git a/crates/benilla-world/src/shaders/sky.wgsl b/crates/benilla-world/src/shaders/sky.wgsl
index c1f371f6..702421b5 100644
--- a/crates/benilla-world/src/shaders/sky.wgsl
+++ b/crates/benilla-world/src/shaders/sky.wgsl
@@ -5,8 +5,11 @@
forward_io::VertexOutput,
mesh_view_bindings::view,
}
-// MONKEY (sky): the Enhanced/High library (smooth gradient, sun glow, night sky).
+// MONKEY (sky): the Enhanced/High library (smooth gradient, sun glow, night sky), compiled only
+// into the `SKY_FX` pipeline so Classic keeps the reference's exact code.
+#ifdef SKY_FX
#import benilla_world::sky_fx
+#endif
struct SkyColors {
sky0: vec4, // zenith (90°)
@@ -77,6 +80,7 @@ fn fragment(in: VertexOutput) -> @location(0) vec4 {
// MONKEY (sky): Enhanced/High. The same stops through a monotone cubic in linear light, then
// the sun glow and the night sky added in linear light, back to gamma, dithered.
+#ifdef SKY_FX
if (sky.fx.x >= 0.5) {
let stops = array, 6>(
sky_fx::srgb_to_linear(sky.fog.rgb),
@@ -109,6 +113,7 @@ fn fragment(in: VertexOutput) -> @location(0) vec4 {
let out = sky_fx::linear_to_srgb(lin) + vec3(sky_fx::dither_tri(in.position.xy));
return vec4(clamp(out, vec3(0.0), vec3(1.0)), 1.0);
}
+#endif
// Elevation gradient, linear between rings like the reference's Gouraud-shaded dome.
var col: vec3;
diff --git a/crates/benilla-world/src/shaders/sky_fx.wgsl b/crates/benilla-world/src/shaders/sky_fx.wgsl
index ed74f870..e22f3356 100644
--- a/crates/benilla-world/src/shaders/sky_fx.wgsl
+++ b/crates/benilla-world/src/shaders/sky_fx.wgsl
@@ -183,7 +183,7 @@ fn star_field(dir: vec3, t: f32, px: f32, band: f32) -> vec3 {
let base = floor(p);
let f = p - base;
let o = select(vec3(-1.0), vec3(1.0), f > vec3(0.5));
- let density = 0.035 * (1.0 + 2.5 * band);
+ let density = 0.022 * (1.0 + 2.5 * band);
var acc = vec3(0.0);
for (var i = 0u; i < 8u; i++) {
let off = vec3(f32(i & 1u), f32((i >> 1u) & 1u), f32((i >> 2u) & 1u)) * o;
diff --git a/crates/benilla-world/src/sky.rs b/crates/benilla-world/src/sky.rs
index 661cca7d..a0fef04a 100644
--- a/crates/benilla-world/src/sky.rs
+++ b/crates/benilla-world/src/sky.rs
@@ -32,6 +32,7 @@ pub type SkyMaterial = ExtendedMaterial;
/// The five sky stops, zenith to horizon, and the fog colour on one binding (100); `sky.wgsl`'s
/// struct must match this field order.
#[derive(Asset, AsBindGroup, Clone, TypePath)]
+#[bind_group_data(SkyFxKey)]
pub struct SkyExt {
/// `SkyColor0`: zenith (90°).
#[uniform(100)]
@@ -67,6 +68,19 @@ pub struct SkyExt {
pub(crate) glow: Vec4,
}
+/// MONKEY (sky): the pipeline key: Enhanced/High compile `SKY_FX` into `sky.wgsl`; Classic keeps
+/// the reference's code with nothing added.
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct SkyFxKey {
+ fx: bool,
+}
+
+impl From<&SkyExt> for SkyFxKey {
+ fn from(e: &SkyExt) -> Self {
+ Self { fx: e.fx.x >= 0.5 }
+ }
+}
+
impl MaterialExtension for SkyExt {
/// The shared sky vertex stage, which pins depth to the far plane ([`crate::sky_order`]).
fn vertex_shader() -> ShaderRef {
@@ -83,8 +97,14 @@ impl MaterialExtension for SkyExt {
_pipeline: &MaterialExtensionPipeline,
descriptor: &mut RenderPipelineDescriptor,
_layout: &MeshVertexBufferLayoutRef,
- _key: MaterialExtensionKey,
+ key: MaterialExtensionKey,
) -> Result<(), SpecializedMeshPipelineError> {
+ // MONKEY (sky): the Enhanced/High branch.
+ if key.bind_group_data.fx {
+ if let Some(fragment) = descriptor.fragment.as_mut() {
+ fragment.shader_defs.push("SKY_FX".into());
+ }
+ }
if let Some(depth) = descriptor.depth_stencil.as_mut() {
depth.depth_write_enabled = false;
}