217 lines
No EOL
6.4 KiB
GLSL
217 lines
No EOL
6.4 KiB
GLSL
precision highp float;
|
|
precision highp int;
|
|
|
|
#define PI 3.1415926535897932384626433832795
|
|
|
|
in vec2 vUv;
|
|
|
|
layout(location = 0) out vec4 FragColor;
|
|
layout(location = 1) out vec4 FragColorExt;
|
|
|
|
uniform float uTime;
|
|
uniform sampler2D tLastState;
|
|
uniform sampler2D tLastExtState;
|
|
uniform sampler2D tWorld;
|
|
|
|
const float sampleDistance = 20.;
|
|
const float cellSize = 1. / WORLD_SIZE;
|
|
|
|
float rand(vec2 co) {
|
|
float a = 12.9898;
|
|
float b = 78.233;
|
|
float c = 43758.5453;
|
|
float dt = dot(co.xy ,vec2(a,b));
|
|
float sn = mod(dt, 3.14);
|
|
return fract(sin(sn) * c);
|
|
}
|
|
|
|
vec2 roundUvToCellCenter(vec2 uv) {
|
|
return floor(uv * WORLD_SIZE) / WORLD_SIZE + cellSize * 0.5;
|
|
}
|
|
|
|
bool tryGetFood(vec2 pos) {
|
|
float value = texture(tWorld, roundUvToCellCenter(pos)).x;
|
|
|
|
return (int(value) & 1) == 1;
|
|
}
|
|
|
|
bool tryDropFood(vec2 pos) {
|
|
float value = texture(tWorld, roundUvToCellCenter(pos)).x;
|
|
|
|
return ((int(value) & 2) >> 1) == 1;
|
|
}
|
|
|
|
bool isObstacle(vec2 pos) {
|
|
float value = texture(tWorld, roundUvToCellCenter(pos)).x;
|
|
|
|
return ((int(value) & 4) >> 2) == 1;
|
|
}
|
|
|
|
float smell(vec2 pos, float isCarrying) {
|
|
vec2 value = texture(tWorld, pos).yz;
|
|
|
|
if (isCarrying > 0.5) {
|
|
return value.y;
|
|
}
|
|
|
|
return value.x;
|
|
}
|
|
|
|
vec2 applyOffsetToPos(vec2 pos, vec2 offsetDirectaion) {
|
|
vec2 newPos = clamp(pos + offsetDirectaion * cellSize, 0., 1.);
|
|
|
|
if (!isObstacle(pos) && isObstacle(newPos)) {
|
|
return pos;
|
|
}
|
|
|
|
return newPos;
|
|
}
|
|
|
|
float getMaxScentStorage(vec2 antDataUv) {
|
|
float factor = 0.8 + rand(antDataUv * 100.) * 0.2;
|
|
|
|
return SCENT_MAX_STORAGE * factor;
|
|
}
|
|
|
|
void main() {
|
|
vec4 lastState = texture(tLastState, vUv);
|
|
vec4 lastExtState = texture(tLastExtState, vUv);
|
|
|
|
float noise = rand(vUv * 1000. + fract(uTime / 1000.));
|
|
|
|
vec2 pos = lastState.xy;
|
|
float angle = lastState.z;
|
|
float isCarrying = float(int(lastState.w) & 1);
|
|
float storage = float(int(lastState.w) >> 1);
|
|
bool wasObstacle = isObstacle(pos);
|
|
|
|
float personality = lastExtState.r;
|
|
float cargoQuality = lastExtState.g;
|
|
float pathIntDx = lastExtState.b;
|
|
float pathIntDy = lastExtState.a;
|
|
|
|
bool movementProcessed = false;
|
|
|
|
if (pos == vec2(0)) { // init new ant
|
|
pos = vec2(0.5);
|
|
angle = rand(vUv * 10000.) * 2. * PI;
|
|
isCarrying = 0.;
|
|
storage = 0.;
|
|
personality = rand(vUv * 42069.); // 0.0 = pure follower, 1.0 = pure explorer
|
|
cargoQuality = 0.;
|
|
pathIntDx = 0.;
|
|
pathIntDy = 0.;
|
|
}
|
|
|
|
if (isCarrying == 0.) {
|
|
if (noise < 0.33) {
|
|
vec2 offset = vec2(cos(angle), sin(angle)) * sampleDistance;
|
|
vec2 point = applyOffsetToPos(pos, offset);
|
|
|
|
if (tryGetFood(point)) {
|
|
movementProcessed = true;
|
|
}
|
|
} else if (noise < 0.66) {
|
|
float newAngle = angle - ANT_ROTATION_ANGLE;
|
|
vec2 offset = vec2(cos(newAngle), sin(newAngle)) * sampleDistance;
|
|
vec2 point = applyOffsetToPos(pos, offset);
|
|
|
|
if (tryGetFood(point)) {
|
|
movementProcessed = true;
|
|
angle = newAngle;
|
|
}
|
|
} else {
|
|
float newAngle = angle + ANT_ROTATION_ANGLE;
|
|
vec2 offset = vec2(cos(newAngle), sin(newAngle)) * sampleDistance;
|
|
vec2 point = applyOffsetToPos(pos, offset);
|
|
|
|
if (tryGetFood(point)) {
|
|
movementProcessed = true;
|
|
angle = newAngle;
|
|
}
|
|
}
|
|
} else if (isCarrying == 1.) {
|
|
if (noise < 0.33) {
|
|
vec2 offset = vec2(cos(angle), sin(angle)) * sampleDistance;
|
|
vec2 point = applyOffsetToPos(pos, offset);
|
|
|
|
if (tryDropFood(point)) {
|
|
movementProcessed = true;
|
|
}
|
|
} else if (noise < 0.66) {
|
|
float newAngle = angle - ANT_ROTATION_ANGLE;
|
|
vec2 offset = vec2(cos(newAngle), sin(newAngle)) * sampleDistance;
|
|
vec2 point = applyOffsetToPos(pos, offset);
|
|
|
|
if (tryDropFood(point)) {
|
|
movementProcessed = true;
|
|
angle = newAngle;
|
|
}
|
|
} else {
|
|
float newAngle = angle + ANT_ROTATION_ANGLE;
|
|
vec2 offset = vec2(cos(newAngle), sin(newAngle)) * sampleDistance;
|
|
vec2 point = applyOffsetToPos(pos, offset);
|
|
|
|
if (tryDropFood(point)) {
|
|
movementProcessed = true;
|
|
angle = newAngle;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!movementProcessed) {
|
|
float noise2 = rand(vUv * 1000. + fract(uTime / 1000.) + 0.2);
|
|
|
|
float sampleAhead = smell(applyOffsetToPos(pos, vec2(cos(angle), sin(angle)) * sampleDistance), isCarrying);
|
|
float sampleLeft = smell(applyOffsetToPos(pos, vec2(cos(angle - ANT_ROTATION_ANGLE), sin(angle - ANT_ROTATION_ANGLE)) * sampleDistance), isCarrying);
|
|
float sampleRight = smell(applyOffsetToPos(pos, vec2(cos(angle + ANT_ROTATION_ANGLE), sin(angle + ANT_ROTATION_ANGLE)) * sampleDistance), isCarrying);
|
|
|
|
if (sampleAhead > sampleLeft && sampleAhead > sampleRight) {
|
|
// don't change direction
|
|
} else if (sampleLeft > sampleAhead && sampleLeft > sampleRight) {
|
|
angle -= ANT_ROTATION_ANGLE; // steer left
|
|
} else if (sampleRight > sampleAhead && sampleRight > sampleLeft) {
|
|
angle += ANT_ROTATION_ANGLE; // steer right
|
|
} else if (noise < 0.33) {
|
|
angle += ANT_ROTATION_ANGLE; // no smell detected, do random movement
|
|
} else if (noise < 0.66) {
|
|
angle -= ANT_ROTATION_ANGLE;
|
|
}
|
|
|
|
if (noise2 > 0.5) {
|
|
angle += ANT_ROTATION_ANGLE * 2.;
|
|
} else {
|
|
angle -= ANT_ROTATION_ANGLE * 2.;
|
|
}
|
|
}
|
|
|
|
vec2 offset = vec2(cos(angle), sin(angle));
|
|
pos = applyOffsetToPos(pos, offset);
|
|
|
|
if (fract(pos.x) == 0. || fract(pos.y) == 0. || (!wasObstacle && isObstacle(pos + offset * cellSize))) {
|
|
angle += PI * (noise - 0.5);
|
|
}
|
|
|
|
if (tryGetFood(pos) && isCarrying == 0.) {
|
|
isCarrying = 1.;
|
|
angle += PI;
|
|
storage = getMaxScentStorage(vUv);
|
|
}
|
|
|
|
if (tryDropFood(pos)) {
|
|
storage = getMaxScentStorage(vUv);
|
|
|
|
if (isCarrying == 1.) {
|
|
isCarrying = 0.;
|
|
angle += PI;
|
|
}
|
|
}
|
|
|
|
FragColor = vec4(
|
|
pos.x,
|
|
pos.y,
|
|
angle,
|
|
float((uint(max(storage - SCENT_PER_MARKER, 0.)) << 1) + uint(isCarrying))
|
|
);
|
|
FragColorExt = vec4(personality, cargoQuality, pathIntDx, pathIntDy);
|
|
} |