Files
MapLibreParticleLab/shaders/particle_gpu_validation.vertex.glsl
OpenAI Codex e48fa087e0
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
feat: add particle visual runtime controls
2026-09-03 19:47:47 +08:00

59 lines
2.3 KiB
GLSL

layout (location = 0) in vec2 a_pos;
out vec2 v_uv;
out vec2 v_world;
out vec2 v_particle_velocity;
out float v_particle_valid;
layout (std140) uniform ParticleGpuValidationUBO {
highp vec4 u_pass;
highp vec4 u_marker;
highp vec4 u_mask;
highp vec4 u_visual;
highp mat4 u_matrix;
};
uniform sampler2D u_state_texture;
uniform sampler2D u_field_texture;
uniform sampler2D u_next_field_texture;
void main() {
v_uv = a_pos;
v_world = a_pos;
v_particle_velocity = vec2(0.0);
v_particle_valid = 1.0;
if (u_pass.x < 1.5) {
gl_Position = vec4(a_pos * 2.0 - 1.0, 0.0, 1.0);
} else if (u_pass.x > 3.5) {
// 40-05: a_pos.x packs State texel X plus a static line endpoint.
// State position, interpolated Field velocity, speed color and streak
// orientation are all evaluated on GPU; the CPU never supplies live
// particle position, direction, or color data.
float endpoint = mod(a_pos.x, 2.0) * 2.0 - 1.0;
vec2 stateIndex = vec2(floor(a_pos.x * 0.5), a_pos.y);
vec2 stateUV = (stateIndex + vec2(0.5)) / u_mask.xy;
vec2 position = texture(u_state_texture, stateUV).rg;
vec4 field0 = texture(u_field_texture, position);
vec4 field1 = texture(u_next_field_texture, position);
vec2 velocity = mix(field0.rg * 2.0 - 1.0, field1.rg * 2.0 - 1.0, u_marker.x);
bool valid = field0.a >= 0.5 && field1.a >= 0.5 && !any(isnan(velocity));
vec2 mercatorVelocity = vec2(velocity.x, -velocity.y);
float speed = length(mercatorVelocity);
v_uv = position;
v_world = position;
v_particle_velocity = mercatorVelocity;
v_particle_valid = valid && speed > 0.00001 ? 1.0 : 0.0;
if (v_particle_valid < 0.5) {
gl_Position = vec4(-2.0, -2.0, 0.0, 1.0);
} else {
vec2 direction = mercatorVelocity / speed;
vec2 streakPosition = position + direction * endpoint * u_visual.y * 0.5;
gl_Position = vec4(streakPosition * 2.0 - 1.0, 0.0, 1.0);
}
} else {
// VALIDATION ONLY: a_pos is canonical z0 world geometry; u_matrix is
// PaintParameters::matrixForTile() for the selected MapLibre world copy.
gl_Position = u_matrix * vec4(a_pos * 8192.0, 0.0, 1.0);
}
}