Constant DEFORM_WGSL
Source pub const DEFORM_WGSL: &str = r#"
struct DeformerData {
kind: vec4u,
current_a: vec4f,
current_b: vec4f,
previous_a: vec4f,
previous_b: vec4f,
}
struct DeformedVertex {
position: vec3f,
normal: vec3f,
tangent: vec4f,
previous_position: vec3f,
}
@group(2) @binding(0) var<storage, read> deformers: array<DeformerData>;
@group(2) @binding(1) var<storage, read> roller_plan: array<vec4f>;
fn plan_sample(s: f32, offset: u32, count: u32) -> vec4f {
var low = 0u;
var high = count - 1u;
let clamped = clamp(s, roller_plan[offset].x, roller_plan[offset + high].x);
while (high - low > 1u) {
let middle = (low + high) / 2u;
if (roller_plan[offset + middle].x < clamped) {
low = middle;
} else {
high = middle;
}
}
let a = roller_plan[offset + low];
let b = roller_plan[offset + high];
let before = roller_plan[offset + max(low, 1u) - 1u];
let after = roller_plan[offset + min(high + 1u, count - 1u)];
let span = b.x - a.x;
let u = (clamped - a.x) / span;
let u2 = u * u;
let u3 = u2 * u;
let ta = normalize(vec2f(b.y - before.y, b.z - before.z));
let tb = normalize(vec2f(after.y - a.y, after.z - a.z));
let p = (2.0 * u3 - 3.0 * u2 + 1.0) * a.yz
+ (u3 - 2.0 * u2 + u) * span * ta
+ (-2.0 * u3 + 3.0 * u2) * b.yz
+ (u3 - u2) * span * tb;
let derivative = (6.0 * u2 - 6.0 * u) * a.yz / span
+ (3.0 * u2 - 4.0 * u + 1.0) * ta
+ (-6.0 * u2 + 6.0 * u) * b.yz / span
+ (3.0 * u2 - 2.0 * u) * tb;
return vec4f(p, normalize(derivative));
}
fn curved_keep(rest: vec3f, data: DeformerData, previous: bool) -> f32 {
let state = select(data.current_a, data.previous_a, previous);
return 1.0 - smoothstep(0.0, 3.14159265 * state.y, rest.x - state.x);
}
fn flattened(rest: vec3f, data: DeformerData, normal: vec3f, tangent: vec3f) -> array<vec3f, 2> {
let keep = curved_keep(rest, data, false);
if (keep >= 1.0) {
return array<vec3f, 2>(normal, tangent);
}
let side = select(1.0, -1.0, normal.y < 0.0);
let n = normalize(mix(vec3f(0.0, side, 0.0), normal, keep));
let along = tangent - n * dot(tangent, n);
let t = select(normalize(along), vec3f(1.0, 0.0, 0.0), dot(along, along) < 1e-12);
return array<vec3f, 2>(n, t);
}
fn curved_roll(rest: vec3f, data: DeformerData, previous: bool) -> Rolled {
let state = select(data.current_a, data.previous_a, previous);
if (data.kind.w == 1u) {
return roll_place(rest, state.x, state.y, state.z);
}
let sample = plan_sample(min(rest.x, state.x), data.kind.y, data.kind.z);
let direction = sample.zw;
let normal = vec2f(-direction.y, direction.x);
let rolled = roll_place(rest, state.x, state.y, state.z);
var out: Rolled;
if (rest.x <= state.x) {
out.position = vec3f(sample.xy + normal * rest.y, rest.z);
out.tangent = vec3f(direction, 0.0);
out.normal = vec3f(normal, 0.0);
} else {
let travel = rest.x - state.x;
let shrink = state.z / 6.28318531;
let fade = exp(-travel / state.y);
let planar = rolled.position.xy - vec2f(state.x, shrink * (1.0 - fade));
let tangent = normalize(rolled.tangent.xy - vec2f(0.0, shrink / state.y * fade));
out.position = vec3f(sample.xy + direction * planar.x + normal * planar.y, rest.z);
out.tangent = vec3f(direction * tangent.x + normal * tangent.y, 0.0);
out.normal = vec3f(direction * -tangent.y + normal * tangent.x, 0.0);
out.position += out.normal * rest.y * curved_keep(rest, data, previous);
}
return out;
}
fn deform_wind_position(rest: vec3f, data: DeformerData, previous: bool) -> vec3f {
let a = select(data.current_a, data.previous_a, previous);
let b = select(data.current_b, data.previous_b, previous);
return rest + bend(rest, data.kind.y, a.x, a.y, b.xyz, f32(data.kind.z));
}
fn deform_position(rest: vec3f, deformer_id: u32, previous: bool) -> vec3f {
if (deformer_id == 0xffffffffu) {
return rest;
}
let data = deformers[deformer_id];
if (data.kind.x == 1u) {
let a = select(data.current_a, data.previous_a, previous);
return roll_place(rest, a.x, a.y, a.z).position;
}
if (data.kind.x == 3u) {
return curved_roll(rest, data, previous).position;
}
if (data.kind.x == 2u) {
return deform_wind_position(rest, data, previous);
}
return rest;
}
fn deform_vertex(rest: vec3f, normal: vec3f, tangent: vec4f, deformer_id: u32) -> DeformedVertex {
var out: DeformedVertex;
out.position = rest;
out.normal = normal;
out.tangent = tangent;
out.previous_position = rest;
if (deformer_id == 0xffffffffu) {
return out;
}
let data = deformers[deformer_id];
if (data.kind.x == 1u || data.kind.x == 3u) {
var current: Rolled;
var n = normal;
var t = tangent.xyz;
if (data.kind.x == 3u) {
current = curved_roll(rest, data, false);
if (data.kind.w == 0u) {
let flat = flattened(rest, data, normal, tangent.xyz);
n = flat[0];
t = flat[1];
}
} else {
current = roll_place(rest, data.current_a.x, data.current_a.y, data.current_a.z);
}
let axis = vec3f(0.0, 0.0, 1.0);
out.position = current.position;
out.previous_position = deform_position(rest, deformer_id, true);
out.normal = normalize(current.tangent * n.x + current.normal * n.y + axis * n.z);
out.tangent = vec4f(normalize(current.tangent * t.x + current.normal * t.y + axis * t.z), tangent.w);
} else if (data.kind.x == 2u) {
out.position = deform_wind_position(rest, data, false);
out.previous_position = deform_position(rest, deformer_id, true);
let step = 0.001;
let dx = (deform_wind_position(rest + vec3f(step, 0.0, 0.0), data, false) - out.position) / step;
let dy = (deform_wind_position(rest + vec3f(0.0, step, 0.0), data, false) - out.position) / step;
let dz = (deform_wind_position(rest + vec3f(0.0, 0.0, step), data, false) - out.position) / step;
let cofactor = mat3x3f(cross(dy, dz), cross(dz, dx), cross(dx, dy));
let jacobian = mat3x3f(dx, dy, dz);
out.normal = normalize(cofactor * normal);
out.tangent = vec4f(normalize(jacobian * tangent.xyz), tangent.w);
}
return out;
}
"#;