precision highp float; precision highp int; in vec2 vUv; out vec4 FragColor; uniform sampler2D tWorld; uniform sampler2D uMaterialProps; const float offset = 1. / WORLD_SIZE * SCENT_BLUR_RADIUS; const float repellentOffset = 1. / WORLD_SIZE * REPELLENT_BLUR_RADIUS; // returns 1.0 if materialId has GAS behavior (pheromone can diffuse through it) float isAir(float materialId) { vec4 props = texelFetch(uMaterialProps, ivec2(int(materialId), 0), 0); return props.r == BEHAVIOR_GAS ? 1.0 : 0.0; } void main() { vec4 s0 = texture(tWorld, vUv); float centerAir = isAir(s0.x); vec4 s1 = texture(tWorld, vUv + vec2(1, 1) * offset); vec4 s2 = texture(tWorld, vUv + vec2(-1, -1) * offset); vec4 s3 = texture(tWorld, vUv + vec2(-1, 1) * offset); vec4 s4 = texture(tWorld, vUv + vec2(1, -1) * offset); float a1 = isAir(s1.x); float a2 = isAir(s2.x); float a3 = isAir(s3.x); float a4 = isAir(s4.x); float scentCount = 1.0 + a1 + a2 + a3 + a4; float scentToHome = (s0.y + s1.y * a1 + s2.y * a2 + s3.y * a3 + s4.y * a4) / scentCount * (1. - SCENT_FADE_OUT_FACTOR) * centerAir; float scentToFood = (s0.z + s1.z * a1 + s2.z * a2 + s3.z * a3 + s4.z * a4) / scentCount * (1. - SCENT_FADE_OUT_FACTOR) * centerAir; // repellent channel uses its own diffusion radius and decay rate vec4 rr0 = texture(tWorld, vUv); vec4 rr1 = texture(tWorld, vUv + vec2(1, 1) * repellentOffset); vec4 rr2 = texture(tWorld, vUv + vec2(-1, -1) * repellentOffset); vec4 rr3 = texture(tWorld, vUv + vec2(-1, 1) * repellentOffset); vec4 rr4 = texture(tWorld, vUv + vec2(1, -1) * repellentOffset); float b1 = isAir(rr1.x); float b2 = isAir(rr2.x); float b3 = isAir(rr3.x); float b4 = isAir(rr4.x); float repellentCount = 1.0 + b1 + b2 + b3 + b4; float repellent = (rr0.w + rr1.w * b1 + rr2.w * b2 + rr3.w * b3 + rr4.w * b4) / repellentCount * (1. - REPELLENT_FADE_OUT_FACTOR) * centerAir; FragColor = vec4( s0.x, scentToHome < SCENT_THRESHOLD ? 0. : scentToHome, scentToFood < SCENT_THRESHOLD ? 0. : scentToFood, repellent < REPELLENT_THRESHOLD ? 0. : repellent ); }