Skip to content

Commit 6f28542

Browse files
authored
Add broad support for texture access (#560)
Add support for accessing most types of WGSL textures, both with filtering (sampler in fragment shader) and without (direct value loading). The former extends the existing `TextureSampleExpr` while the latter adds a new `TextureLoadExpr`. This change forces the `TextureSampleExpr` slot back into a CPU constant. To dynamically switch between texture, use an array texture with a `layer_index` expression instead. Add a new `lut.rs` example showing how to use a `TextureLoadExpr` inside the Update pass to read a 2D array texture used as a look-up table (LUT).
1 parent 2400b0c commit 6f28542

29 files changed

Lines changed: 1959 additions & 658 deletions

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
- Added `HanabiMainCamera`, a component to tag the "main" camera that Hanabi uses
1313
for camera-specific features. Add to exactly one `Camera` to tag it.
1414
- Added `KillFrustumModifier` to kill particles outside of the main camera frustum.
15+
- Added the ability to access the effect's material (the user bound textures) from all passes.
16+
- Added support for 1D and 3D textures, and 2D array textures, as well as cube textures
17+
and depth textures, to the `TextureSampleExpr`. See `SlotDimension` for all supported variants.
18+
- Added a new `TextureLoadExpr` doing a non-sampling texture load (`textureLoad()` in WGSL).
19+
This can be used in all passes (all modifier contexts).
20+
- Added a new `lut.rs` example that demonstrates using a 2D array texture as a look-up table (LUT).
21+
This can be used to approximate any kind of curve or gradient.
1522

1623
### Changed
1724

@@ -22,6 +29,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2229
available for GPU particle spawning.
2330
- Parallelized most of the GPU sort. This dramatically improves performance when using ribbon effects.
2431
- `EvalContext::make_fn()` now takes an optional return token for the function return value.
32+
- Renamed `TextureSampleExpr::image` to `slot_index`, and changed its type to be a `u32` slot index
33+
defined at module build time. Dynamically switching between texture with a slot expression
34+
was broken, and is explicitly not supported anymore. If you want to dynamically switch between textures,
35+
consider using an array texture instead, which is a better way to achieve the same result.
36+
- Added `TextureSlot::dimension` to specify the type of texture that a texture slot accepts.
37+
- Added `TextureSampleExpr::slot_dimension` to specify the type of texture being sampled.
38+
This must match the associated slot's `TextureSlot::dimension` when bound.
39+
- `TextureSamplerExpr` now correctly returns an error if used from any pass but the Render one,
40+
instead of generating invalid WGSL code. This is a restriction of the WGSL language itself
41+
(sampled texture read, via `textureSample()`, can only be used in the fragment shader).
2542

2643
### Fixed
2744

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ name = "puffs"
165165
[[example]]
166166
name = "lightning"
167167

168+
[[example]]
169+
name = "lut"
170+
168171
[[test]]
169172
name = "empty_effect"
170173
path = "gpu_tests/empty_effect.rs"

build_examples_wasm.bat

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ echo Setting RUSTFLAGS to enable unstable web_sys APIs...
66
set RUSTFLAGS=--cfg web_sys_unstable_apis --cfg getrandom_backend="wasm_js"
77

88
echo Build all examples for WASM...
9-
REM 3D
109
cargo b --release --example lightning --target wasm32-unknown-unknown --features="bevy/webgpu"
1110
cargo b --release --example firework --target wasm32-unknown-unknown --features="bevy/webgpu"
1211
cargo b --release --example portal --target wasm32-unknown-unknown --features="bevy/webgpu"
@@ -22,14 +21,13 @@ cargo b --release --example init --target wasm32-unknown-unknown --features="bev
2221
cargo b --release --example lifetime --target wasm32-unknown-unknown --features="bevy/webgpu"
2322
cargo b --release --example ordering --target wasm32-unknown-unknown --features="bevy/webgpu"
2423
cargo b --release --example ribbon --target wasm32-unknown-unknown --features="bevy/webgpu"
25-
REM 3D + PNG
2624
cargo b --release --example gradient --target wasm32-unknown-unknown --features="bevy/webgpu"
2725
cargo b --release --example circle --target wasm32-unknown-unknown --features="bevy/webgpu"
2826
cargo b --release --example billboard --target wasm32-unknown-unknown --features="bevy/webgpu"
2927
cargo b --release --example worms --target wasm32-unknown-unknown --features="bevy/webgpu"
3028
cargo b --release --example instancing --target wasm32-unknown-unknown --features="bevy/webgpu"
3129
cargo b --release --example puffs --target wasm32-unknown-unknown --features="bevy/webgpu"
32-
REM 2D
30+
cargo b --release --example lut --target wasm32-unknown-unknown --features="bevy/webgpu"
3331
cargo b --release --example 2d --target wasm32-unknown-unknown --features="bevy/webgpu"
3432

3533
wasm-bindgen --out-name wasm_lightning --no-typescript --out-dir examples/wasm/target --target web target/wasm32-unknown-unknown/release/examples/lightning.wasm
@@ -53,6 +51,7 @@ wasm-bindgen --out-name wasm_billboard --no-typescript --out-dir examples/wasm/t
5351
wasm-bindgen --out-name wasm_worms --no-typescript --out-dir examples/wasm/target --target web target/wasm32-unknown-unknown/release/examples/worms.wasm
5452
wasm-bindgen --out-name wasm_instancing --no-typescript --out-dir examples/wasm/target --target web target/wasm32-unknown-unknown/release/examples/instancing.wasm
5553
wasm-bindgen --out-name wasm_puffs --out-dir examples/wasm/target --target web target/wasm32-unknown-unknown/release/examples/puffs.wasm
54+
wasm-bindgen --out-name wasm_lut --out-dir examples/wasm/target --target web target/wasm32-unknown-unknown/release/examples/lut.wasm
5655
wasm-bindgen --out-name wasm_2d --no-typescript --out-dir examples/wasm/target --target web target/wasm32-unknown-unknown/release/examples/2d.wasm
5756

5857
echo Done. See docs/wasm.md for help on running the examples locally.

build_examples_wasm.sh

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ echo Setting RUSTFLAGS to enable unstable web_sys APIs...
44
export RUSTFLAGS=--cfg=web_sys_unstable_apis
55

66
echo Build all examples for WASM...
7-
# 3D
87
cargo b --release --example lightning --target wasm32-unknown-unknown
98
cargo b --release --example firework --target wasm32-unknown-unknown
109
cargo b --release --example portal --target wasm32-unknown-unknown
@@ -20,14 +19,13 @@ cargo b --release --example init --target wasm32-unknown-unknown
2019
cargo b --release --example lifetime --target wasm32-unknown-unknown
2120
cargo b --release --example ordering --target wasm32-unknown-unknown
2221
cargo b --release --example ribbon --target wasm32-unknown-unknown
23-
# 3D + PNG
24-
cargo b --release --example
22+
cargo b --release --example gradient --target wasm32-unknown-unknown
2523
cargo b --release --example circle --target wasm32-unknown-unknown
2624
cargo b --release --example billboard --target wasm32-unknown-unknown
2725
cargo b --release --example worms --target wasm32-unknown-unknown
2826
cargo b --release --example instancing --target wasm32-unknown-unknown
2927
cargo b --release --example puffs --target wasm32-unknown-unknown
30-
# 2D
28+
cargo b --release --example lut --target wasm32-unknown-unknown
3129
cargo b --release --example 2d --target wasm32-unknown-unknown
3230

3331
echo Bindgen all examples...
@@ -52,6 +50,7 @@ wasm-bindgen --out-name wasm_billboard --out-dir examples/wasm/target --target w
5250
wasm-bindgen --out-name wasm_worms --out-dir examples/wasm/target --target web target/wasm32-unknown-unknown/release/examples/worms.wasm
5351
wasm-bindgen --out-name wasm_instancing --out-dir examples/wasm/target --target web target/wasm32-unknown-unknown/release/examples/instancing.wasm
5452
wasm-bindgen --out-name wasm_puffs --out-dir examples/wasm/target --target web target/wasm32-unknown-unknown/release/examples/puffs.wasm
53+
wasm-bindgen --out-name wasm_lut --out-dir examples/wasm/target --target web target/wasm32-unknown-unknown/release/examples/lut.wasm
5554
wasm-bindgen --out-name wasm_2d --out-dir examples/wasm/target --target web target/wasm32-unknown-unknown/release/examples/2d.wasm
5655

5756
echo Done. See docs/wasm.md for help on running the examples locally.

examples/billboard.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,8 @@ fn setup(
113113
// per-particle rotation)
114114
let rotation_attr = writer.attr(Attribute::F32_0).expr();
115115

116-
let texture_slot = writer.lit(0u32).expr();
117-
118116
let mut module = writer.finish();
119-
module.add_texture_slot("color");
117+
module.add_texture_slot("color", SlotDimension::D2);
120118

121119
let effect = effects.add(
122120
EffectAsset::new(32768, SpawnerSettings::rate(64.0.into()), module)
@@ -129,7 +127,7 @@ fn setup(
129127
.init(init_rotation)
130128
.init(init_color)
131129
.render(ParticleTextureModifier {
132-
texture_slot,
130+
texture_slot: 0,
133131
sample_mapping: ImageSampleMapping::ModulateOpacityFromR,
134132
})
135133
.render(OrientModifier {

examples/circle.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,9 @@ fn setup(
112112
.expr();
113113
let update_sprite_index = SetAttributeModifier::new(Attribute::SPRITE_INDEX, sprite_index);
114114

115-
let texture_slot = writer.lit(0u32).expr();
116-
let texture_slot2 = writer.lit(1u32).expr();
117-
118115
let mut module = writer.finish();
119-
module.add_texture_slot("color");
120-
module.add_texture_slot("shape");
116+
module.add_texture_slot("color", SlotDimension::D2);
117+
module.add_texture_slot("shape", SlotDimension::D2);
121118

122119
let effect = effects.add(
123120
EffectAsset::new(
@@ -132,11 +129,11 @@ fn setup(
132129
.init(init_lifetime)
133130
.update(update_sprite_index)
134131
.render(ParticleTextureModifier {
135-
texture_slot,
132+
texture_slot: 0,
136133
sample_mapping: ImageSampleMapping::ModulateOpacityFromR,
137134
})
138135
.render(ParticleTextureModifier {
139-
texture_slot: texture_slot2,
136+
texture_slot: 1,
140137
sample_mapping: ImageSampleMapping::ModulateRGB,
141138
})
142139
.render(FlipbookModifier { sprite_grid_size })

examples/gradient.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,9 @@ fn setup(
6868
speed: writer.lit(2.).expr(),
6969
};
7070

71-
// Use texture slot #0 in ParticleTextureModifier
72-
let texture_slot = writer.lit(0u32).expr();
73-
7471
// Define that texture slot (giving it a name for convenience)
7572
let mut module = writer.finish();
76-
module.add_texture_slot("color");
73+
module.add_texture_slot("color", SlotDimension::D2);
7774

7875
let effect = effects.add(
7976
EffectAsset::new(32768, SpawnerSettings::rate(1000.0.into()), module)
@@ -83,7 +80,7 @@ fn setup(
8380
.init(init_age)
8481
.init(init_lifetime)
8582
.render(ParticleTextureModifier {
86-
texture_slot,
83+
texture_slot: 0,
8784
sample_mapping: ImageSampleMapping::ModulateOpacityFromR,
8885
})
8986
.render(ColorOverLifetimeModifier::new(gradient)),

examples/instancing.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -281,14 +281,12 @@ fn setup(
281281
let radial_accel =
282282
RadialAccelModifier::new(writer.lit(Vec3::ZERO).expr(), writer.lit(-3).expr());
283283

284-
let texture_slot = writer.lit(0u32).expr();
285-
286284
let prop_color = writer.add_property("prop_color", 0xFFFFFFFFu32.into());
287285
let prop_color = writer.prop(prop_color);
288286
let update_col = SetAttributeModifier::new(Attribute::COLOR, prop_color.expr());
289287

290288
let mut module = writer.finish();
291-
module.add_texture_slot("color");
289+
module.add_texture_slot("color", SlotDimension::D2);
292290

293291
let alt_effect = effects.add(
294292
EffectAsset::new(512, SpawnerSettings::rate(102.0.into()), module)
@@ -300,7 +298,7 @@ fn setup(
300298
.update(radial_accel)
301299
.update(update_col)
302300
.render(ParticleTextureModifier {
303-
texture_slot,
301+
texture_slot: 0,
304302
sample_mapping: ImageSampleMapping::Modulate,
305303
}),
306304
);

0 commit comments

Comments
 (0)