Skip to content

Commit c131b5d

Browse files
mvaligurskyMartin Valigursky
andauthored
WGSL shader variant for Integer Textures example (#8226)
Co-authored-by: Martin Valigursky <[email protected]>
1 parent 7280517 commit c131b5d

File tree

3 files changed

+114
-1
lines changed

3 files changed

+114
-1
lines changed

examples/src/examples/shaders/integer-textures.example.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ const outputShader = pc.ShaderUtils.createShader(device, {
144144
uniqueName: 'RenderOutputShader',
145145
attributes: { aPosition: pc.SEMANTIC_POSITION },
146146
vertexChunk: 'quadVS',
147-
fragmentGLSL: files['renderOutput.frag']
147+
fragmentGLSL: files['renderOutput.glsl.frag'],
148+
fragmentWGSL: files['renderOutput.wgsl.frag']
148149
// For the output shader, we don't need to specify the output type,
149150
// as we are returning a vec4 by default.
150151
});
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Texture (unsigned-integer, fetch-only)
2+
var sourceTexture: texture_2d<u32>;
3+
4+
// Uniforms (auto-buffered, accessed as uniform.<name>)
5+
uniform mousePosition: vec2f;
6+
uniform brushRadius: f32;
7+
8+
// Interpolated varying (from vertex shader)
9+
varying uv0: vec2f;
10+
11+
// Color constants
12+
const whiteColor: vec3f = vec3f(1.0);
13+
const skyBlueColor: vec3f = vec3f(0.2, 0.2, 0.2);
14+
const yellowSandColor: vec3f = vec3f(0.73, 0.58, 0.26);
15+
const orangeSandColor: vec3f = vec3f(0.87, 0.43, 0.22);
16+
const graySandColor: vec3f = vec3f(0.13, 0.16, 0.17);
17+
const grayWallColor: vec3f = vec3f(0.5, 0.5, 0.5);
18+
const waterBlueColor: vec3f = vec3f(0.2, 0.3, 0.8);
19+
20+
// Particle element constants
21+
const AIR: u32 = 0u;
22+
const SAND: u32 = 1u;
23+
const ORANGESAND: u32 = 2u;
24+
const GRAYSAND: u32 = 3u;
25+
const WALL: u32 = 4u;
26+
27+
// Circle distance function
28+
fn circle(p: vec2f, r: f32) -> f32 {
29+
return length(p) - r;
30+
}
31+
32+
const circleOutline: f32 = 0.0025;
33+
34+
// Helper: check bounds in integer texel space
35+
fn isInBounds(c: vec2i, size: vec2i) -> bool {
36+
return (c.x > 0 && c.x < size.x - 1) &&
37+
(c.y > 0 && c.y < size.y - 1);
38+
}
39+
40+
// Particle representation
41+
struct Particle {
42+
element: u32,
43+
movedThisFrame: bool,
44+
shade: u32,
45+
waterMass: u32 // unused here
46+
};
47+
48+
// Pseudo-random generator
49+
fn rand(pos: vec2f, val: f32) -> f32 {
50+
return fract(pos.x * pos.y * val * 1000.0);
51+
}
52+
53+
// Pack a Particle into a single u32
54+
fn pack(p: Particle) -> u32 {
55+
var packed: u32 = 0u;
56+
packed |= (p.element & 0x7u);
57+
packed |= u32(p.movedThisFrame) << 3;
58+
packed |= ((p.shade & 0xFu) << 4);
59+
return packed;
60+
}
61+
62+
// Unpack a u32 into a Particle
63+
fn unpack(packed: u32) -> Particle {
64+
var pt: Particle;
65+
pt.element = packed & 0x7u;
66+
pt.movedThisFrame = ((packed >> 3) & 0x1u) != 0u;
67+
pt.shade = (packed >> 4) & 0xFu;
68+
pt.waterMass = 0u;
69+
return pt;
70+
}
71+
72+
// Fetch and decode a particle from the texture
73+
fn getParticle(coord: vec2i) -> Particle {
74+
let texel: vec4<u32> = textureLoad(sourceTexture, coord, 0);
75+
return unpack(texel.x);
76+
}
77+
78+
@fragment
79+
fn fragmentMain(input: FragmentInput) -> FragmentOutput {
80+
var output: FragmentOutput;
81+
82+
// Determine integer texture size & sample coordinate
83+
let dims: vec2u = textureDimensions(sourceTexture);
84+
let size: vec2i = vec2i(dims);
85+
let coord: vec2i = vec2i(input.uv0 * vec2f(size));
86+
87+
let particle = getParticle(coord);
88+
89+
var gameColor: vec3f = skyBlueColor;
90+
if (particle.element == SAND) {
91+
gameColor = mix(yellowSandColor, whiteColor, (f32(particle.shade) / 15.0) * 0.5);
92+
} else if (particle.element == WALL) {
93+
gameColor = grayWallColor;
94+
} else if (particle.element == ORANGESAND) {
95+
gameColor = mix(orangeSandColor, whiteColor, (f32(particle.shade) / 15.0) * 0.5);
96+
} else if (particle.element == GRAYSAND) {
97+
gameColor = mix(graySandColor, whiteColor, (f32(particle.shade) / 15.0) * 0.5);
98+
}
99+
100+
// Render a brush circle
101+
let d: f32 = length(input.uv0 - uniform.mousePosition);
102+
let wd: f32 = fwidth(d);
103+
let circleVal: f32 = smoothstep(uniform.brushRadius + wd, uniform.brushRadius, d);
104+
let circleInner: f32 = smoothstep(uniform.brushRadius - circleOutline + wd, uniform.brushRadius - circleOutline, d);
105+
let brush: f32 = max(circleVal - circleInner, 0.0) * 0.5;
106+
107+
let outColor: vec3f = mix(gameColor, vec3f(1.0), brush);
108+
109+
output.color = vec4f(outColor, 1.0);
110+
return output;
111+
}
112+

0 commit comments

Comments
 (0)