diff --git a/src/shaders/antsCompute.frag b/src/shaders/antsCompute.frag index cdf8b60..aa234b1 100644 --- a/src/shaders/antsCompute.frag +++ b/src/shaders/antsCompute.frag @@ -15,6 +15,7 @@ uniform sampler2D tWorld; uniform sampler2D tPresence; uniform float uForagerRatio; uniform sampler2D uMaterialProps; +uniform vec4 uAntSpawn; const float ANT_CARRY_STRENGTH = 1.0; const float sampleDistance = 20.; @@ -94,38 +95,68 @@ void main() { int antIndex = int(vUv.y * float(texSize.y)) * texSize.x + int(vUv.x * float(texSize.x)); if (pos == vec2(0)) { // init new ant - // only activate ants within the start count - if (antIndex >= ANTS_START_COUNT) { - // dormant ant — output zeros and skip everything + bool spawnRequested = (uAntSpawn.w > 0.5); + + if (antIndex >= ANTS_START_COUNT && !spawnRequested) { + // dormant ant, no spawn request — skip FragColor = vec4(0); FragColorExt = vec4(0); return; } - #if VIEW_MODE_SIDE - // spawn on sand surface: random X, scan down from top to find first non-air cell - float spawnX = rand(vUv * 10000.); - float pixelSize = 1.0 / float(textureSize(tWorld, 0).x); - float surfaceY = 0.6; // fallback if scan finds nothing - for (float scanY = 1.0; scanY > 0.0; scanY -= pixelSize) { - float matId = texture(tWorld, vec2(spawnX, scanY)).x; - if (matId > 0.5) { // non-air cell found - surfaceY = scanY + pixelSize; // one cell above the surface - break; + if (antIndex >= ANTS_START_COUNT && spawnRequested) { + // probabilistic activation: ~brushRadius ants per frame + float activationChance = uAntSpawn.z / float(ANT_BUDGET); + float roll = rand(vUv * 50000. + fract(uTime / 1000.)); + if (roll > activationChance) { + // not selected this frame — stay dormant + FragColor = vec4(0); + FragColorExt = vec4(0); + return; } + // activate at spawn position with scatter + float scatter = uAntSpawn.z / WORLD_SIZE; + float rngX = rand(vUv * 10000. + fract(uTime / 1000.)); + float rngY = rand(vUv * 20000. + fract(uTime / 1000.) + 0.5); + pos = vec2( + uAntSpawn.x + (rngX - 0.5) * scatter, + uAntSpawn.y + (rngY - 0.5) * scatter + ); + pos = clamp(pos, 0., 1.); + angle = rand(vUv * 42069.) * 2.0 * PI; + isCarrying = 0.; + storage = 0.; + personality = rand(vUv * 42069.); + cargoMaterialId = 0.; + pathIntDx = 0.; + pathIntDy = 0.; + } else { + // normal init for starting ants + #if VIEW_MODE_SIDE + // spawn on sand surface: random X, scan down from top to find first non-air cell + float spawnX = rand(vUv * 10000.); + float pixelSize = 1.0 / float(textureSize(tWorld, 0).x); + float surfaceY = 0.6; // fallback if scan finds nothing + for (float scanY = 1.0; scanY > 0.0; scanY -= pixelSize) { + float matId = texture(tWorld, vec2(spawnX, scanY)).x; + if (matId > 0.5) { // non-air cell found + surfaceY = scanY + pixelSize; // one cell above the surface + break; + } + } + pos = vec2(spawnX, surfaceY); + angle = -PI * 0.5; // face downward initially + #else + pos = vec2(0.5); + angle = rand(vUv * 10000.) * 2. * PI; + #endif + isCarrying = 0.; + storage = 0.; + personality = rand(vUv * 42069.); // 0.0 = pure follower, 1.0 = pure explorer + cargoMaterialId = 0.; + pathIntDx = 0.; + pathIntDy = 0.; } - pos = vec2(spawnX, surfaceY); - angle = -PI * 0.5; // face downward initially - #else - pos = vec2(0.5); - angle = rand(vUv * 10000.) * 2. * PI; - #endif - isCarrying = 0.; - storage = 0.; - personality = rand(vUv * 42069.); // 0.0 = pure follower, 1.0 = pure explorer - cargoMaterialId = 0.; - pathIntDx = 0.; - pathIntDy = 0.; } // --- GRAVITY AND SURFACE CHECK ---