Constant CANOPY_COOKIE_WGSL
Source pub const CANOPY_COOKIE_WGSL: &str = r#"
struct CanopyParams {
center_extent: vec4f,
sun_receiver: vec4f,
wind: vec4f,
direction: vec4f,
projected_extent: vec4f,
mode_sharpness: vec4f,
}
struct Card {
position_size: vec4f,
right_size: vec4f,
up: vec4f,
pivot_level: vec4f,
motion_color: vec4f,
atlas: vec4f,
lod: vec4f,
}
@group(0) @binding(0) var<uniform> params: CanopyParams;
@group(0) @binding(1) var<storage, read> cards: array<Card>;
@group(0) @binding(2) var alpha_atlas: texture_2d<f32>;
@group(0) @binding(3) var alpha_sampler: sampler;
fn tree_sway(rest: vec3f, pivot: vec3f, level: f32, stiffness: f32, wind_time: f32, strength: f32, direction: vec3f) -> vec3f {
let d = normalize(direction.xz + vec2f(0.00001, 0.0));
let arm = length(rest - pivot);
let phase = wind_time * (0.7 + level * 0.41) + pivot.x * 0.83 + pivot.z * 0.67;
let bend = sin(phase) * strength * (1.0 - stiffness) * arm * (0.012 + 0.009 * level);
return rest + vec3f(d.x * bend, -abs(bend) * 0.12, d.y * bend);
}
struct Varying { @builtin(position) clip: vec4f, @location(0) uv: vec2f, @location(1) @interpolate(flat) atlas: vec4f, @location(2) @interpolate(flat) lod: vec4f, }
@vertex fn vertex(@builtin(vertex_index) vertex: u32, @builtin(instance_index) instance: u32) -> Varying {
let card = cards[instance];
let corners = array<vec2f, 6>(vec2f(-1.0,-1.0), vec2f(1.0,-1.0), vec2f(-1.0,1.0), vec2f(-1.0,1.0), vec2f(1.0,-1.0), vec2f(1.0,1.0));
let corner = corners[vertex];
let rest = card.position_size.xyz + card.right_size.xyz * card.position_size.w * corner.x + card.up.xyz * card.right_size.w * corner.y;
let moved = tree_sway(rest, card.pivot_level.xyz, card.pivot_level.w, card.motion_color.x, params.wind.x, params.wind.y, params.direction.xyz) + vec3f(params.center_extent.x, params.wind.z, params.center_extent.y);
let sun_input = params.sun_receiver.xyz;
let sun = select(vec3f(0.0, 1.0, 0.0), sun_input / max(length(sun_input), 1e-6), length(sun_input) > 1e-6);
let reference = select(vec3f(0.0, 1.0, 0.0), vec3f(0.0, 0.0, 1.0), abs(sun.y) > 0.99);
let axis_u = normalize(cross(sun, reference));
let axis_v = cross(axis_u, sun);
let projected = vec2f(dot(moved, axis_u), dot(moved, axis_v));
let uv = (projected - params.projected_extent.xy) / params.projected_extent.zw + vec2f(0.5);
var out: Varying;
out.clip = vec4f(uv.x * 2.0 - 1.0, 1.0 - uv.y * 2.0, 0.0, 1.0);
out.uv = (corner + vec2f(1.0)) * 0.5;
out.atlas = card.atlas;
out.lod = card.lod;
return out;
}
@fragment fn fragment(input: Varying) -> @location(0) f32 {
let uv = input.atlas.xy + input.uv * input.atlas.zw;
let weight = select(1.0 - input.lod.x, input.lod.x, input.lod.z > 0.5);
return textureSample(alpha_atlas, alpha_sampler, uv).r * weight;
}
"#;