Files
MapLibreParticleLab/shaders/particle_gpu_validation.fragment.glsl
OpenAI Codex 0b076c6d52
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
feat: establish android particle field rendering loop
2026-08-31 10:41:12 +08:00

60 lines
3.0 KiB
GLSL

layout (std140) uniform ParticleGpuValidationUBO {
highp vec4 u_pass;
highp vec4 u_marker;
highp vec4 u_mask;
highp mat4 u_matrix;
};
uniform sampler2D u_previous;
uniform sampler2D u_mask_texture;
uniform sampler2D u_field_texture;
uniform sampler2D u_state_texture;
in vec2 v_uv;
in vec2 v_world;
void main() {
vec4 previous = texture(u_previous, v_uv);
float mode = u_pass.x;
if (mode < 0.5) {
// 40-01: State A/B samples the uploaded OfflineFixture Particle Field.
// RG stores field-normalized position, B stores age, and the Field
// texture encodes canonical U-east/V-north at that geographic sample.
vec2 position = previous.rg;
if (previous.a < 0.5) position = v_uv;
vec2 velocity = texture(u_field_texture, position).rg * 2.0 - 1.0;
position = fract(position + velocity * u_pass.y * 0.004);
if (any(isnan(velocity))) position = v_uv;
fragColor = vec4(position, fract(previous.b + 0.03125 * u_pass.y), 1.0);
} else if (mode < 1.5) {
// The trail consumes State B/A written by the real field-sampling pass.
// Four deterministic texels are enough for the Stage A visual proof.
float marker = 0.0;
marker = max(marker, 1.0 - smoothstep(0.0, u_marker.z, distance(v_uv, texture(u_state_texture, vec2(0.125, 0.125)).rg)));
marker = max(marker, 1.0 - smoothstep(0.0, u_marker.z, distance(v_uv, texture(u_state_texture, vec2(0.375, 0.375)).rg)));
marker = max(marker, 1.0 - smoothstep(0.0, u_marker.z, distance(v_uv, texture(u_state_texture, vec2(0.625, 0.625)).rg)));
marker = max(marker, 1.0 - smoothstep(0.0, u_marker.z, distance(v_uv, texture(u_state_texture, vec2(0.875, 0.875)).rg)));
vec3 color = previous.rgb * u_marker.w + marker * vec3(0.08, 0.55, 1.0);
fragColor = vec4(min(color, vec3(1.0)), 1.0);
} else {
// Current-frame canonical world composite and shared Mask.
float intensity = max(previous.r, max(previous.g, previous.b));
float ocean = texture(u_mask_texture, v_world).a;
if (u_pass.z > 0.5 && ocean < 0.5) discard;
float stripe = 0.55 + 0.45 * sin((v_world.x + v_world.y) * 100.0 + u_pass.y * 0.07);
// A=(0°,0°), B=(-90°,approximately 0°), C/D straddle ±180°.
float anchors = 0.0;
anchors = max(anchors, 1.0 - smoothstep(0.0, 0.008, distance(v_world, vec2(0.50, 0.50))));
anchors = max(anchors, 1.0 - smoothstep(0.0, 0.008, distance(v_world, vec2(0.25, 0.50))));
anchors = max(anchors, 1.0 - smoothstep(0.0, 0.008, distance(v_world, vec2(0.02, 0.50))));
anchors = max(anchors, 1.0 - smoothstep(0.0, 0.008, distance(v_world, vec2(0.98, 0.50))));
vec3 color = u_pass.w < 1.5 ? vec3(0.10, 0.70, 1.00) : vec3(0.35, 1.00, 0.45);
fragColor = vec4(mix(color * stripe, vec3(1.00, 0.82, 0.15), anchors),
0.28 + min(intensity, 0.35) * 0.35 + anchors * 0.35);
}
#ifdef OVERDRAW_INSPECTOR
fragColor = vec4(1.0);
#endif
}