Add pheromone settings to GUI

This commit is contained in:
vHawk 2022-07-11 05:43:33 +03:00
parent c84a3b46b7
commit 9ecb9f55aa
7 changed files with 24 additions and 22 deletions

View file

@ -4,6 +4,8 @@ A simple ant colony GPU-accelerated simulation made with Three.js.
**[Live demo](https://vhawk.github.io/ants-simulation/)** **[Live demo](https://vhawk.github.io/ants-simulation/)**
![ants collecting food](https://i.imgur.com/FeU3UvR.png)
## Rules ## Rules
Ants can emit two types of pheromones: to-home pheromone and to-food pheromone. To-home pheromones are emitted by those ants searching for food and to-food pheromones are emitted by those carrying food. Ants searching for food are attracted to to-food pheromones, while ants searching for home are attracted to to-home pheromones. Ants can emit two types of pheromones: to-home pheromone and to-food pheromone. To-home pheromones are emitted by those ants searching for food and to-food pheromones are emitted by those carrying food. Ants searching for food are attracted to to-food pheromones, while ants searching for home are attracted to to-home pheromones.

View file

@ -34,11 +34,7 @@ export default new class App {
this.renderLoop(0); this.renderLoop(0);
this.gui.on('antsCount', () => { this.gui.on('reset', () => {
this.resetRenderer();
});
this.gui.on('worldSize', () => {
this.resetRenderer(); this.resetRenderer();
}); });
} }
@ -84,6 +80,7 @@ export default new class App {
const simStepsToDo = deltaTime / 1000 * Config.simulationStepsPerSecond; const simStepsToDo = deltaTime / 1000 * Config.simulationStepsPerSecond;
this.queuedSimSteps += simStepsToDo; this.queuedSimSteps += simStepsToDo;
this.queuedSimSteps = Math.min(this.queuedSimSteps, 10);
while (this.queuedSimSteps >= 1) { while (this.queuedSimSteps >= 1) {
this.simulationStep(); this.simulationStep();

View file

@ -3,11 +3,12 @@ export default {
antsCount: 12, antsCount: 12,
simulationStepsPerSecond: 60, simulationStepsPerSecond: 60,
scentThreshold: 0.01, scentThreshold: 0.01,
scentFadeOutFactor: 0.998, scentFadeOutFactor: 0.001,
scentBlurRadius: 0.1, scentBlurRadius: 0.1,
scentMaxStorage: 1e6, scentMaxStorage: 1e6,
scentPerMarker: 300, scentPerMarker: 200,
scentMaxPerCell: 10,
antSpeed: 1, antSpeed: 1,
antRotationAngle: Math.PI / 50, antRotationAngle: Math.PI / 30,
brushRadius: 20, brushRadius: 20,
}; };

View file

@ -15,21 +15,22 @@ export default class GUI extends EventEmitter {
simFolder.add(Config, 'worldSize', 256, 4096) simFolder.add(Config, 'worldSize', 256, 4096)
.name('World size') .name('World size')
.step(1) .step(1)
.onChange(() => { .onChange(() => this.emit('reset'));
this.emit('worldSize');
});
simFolder.add(Config, 'antsCount', 0, 22) simFolder.add(Config, 'antsCount', 0, 22)
.name('Ants count 2^') .name('Ants count 2^')
.step(1) .step(1)
.onChange(() => { .onChange(() => this.emit('reset'));
this.emit('antsCount'); simFolder.add(Config, 'scentFadeOutFactor', 0, 0.01)
}); .name('Pheromone evaporation factor')
.step(0.0001)
.onChange(() => this.emit('reset'));
simFolder.add(Config, 'scentBlurRadius', 0, 0.5)
.name('Pheromone diffusion factor')
.step(0.01)
.onChange(() => this.emit('reset'));
simFolder.add(Config, 'simulationStepsPerSecond', 1, 500) simFolder.add(Config, 'simulationStepsPerSecond', 1, 500)
.name('Simulation steps per second') .name('Simulation steps per second')
.step(1) .step(1);
.onChange(() => {
this.emit('simulationStepsPerSecond');
});
const controlsFolder = this.gui.addFolder('Controls'); const controlsFolder = this.gui.addFolder('Controls');

View file

@ -133,6 +133,7 @@ export default class Renderer {
SCENT_BLUR_RADIUS: Renderer.convertNumberToFloatString(Config.scentBlurRadius), SCENT_BLUR_RADIUS: Renderer.convertNumberToFloatString(Config.scentBlurRadius),
SCENT_MAX_STORAGE: Renderer.convertNumberToFloatString(Config.scentMaxStorage), SCENT_MAX_STORAGE: Renderer.convertNumberToFloatString(Config.scentMaxStorage),
SCENT_PER_MARKER: Renderer.convertNumberToFloatString(Config.scentPerMarker), SCENT_PER_MARKER: Renderer.convertNumberToFloatString(Config.scentPerMarker),
SCENT_MAX_PER_CELL: Renderer.convertNumberToFloatString(Config.scentMaxPerCell),
ANT_SPEED: Renderer.convertNumberToFloatString(Config.antSpeed), ANT_SPEED: Renderer.convertNumberToFloatString(Config.antSpeed),
ANT_ROTATION_ANGLE: Renderer.convertNumberToFloatString(Config.antRotationAngle) ANT_ROTATION_ANGLE: Renderer.convertNumberToFloatString(Config.antRotationAngle)
}; };

View file

@ -16,8 +16,8 @@ void main() {
int isFood = cellData & 1; int isFood = cellData & 1;
int isHome = (cellData & 2) >> 1; int isHome = (cellData & 2) >> 1;
int isObstacle = (cellData & 4) >> 2; int isObstacle = (cellData & 4) >> 2;
float scentToHome = min(10., lastState.y + discreteAnts.x); float scentToHome = min(SCENT_MAX_PER_CELL, lastState.y + discreteAnts.x);
float scentToFood = min(10., lastState.z + discreteAnts.y); float scentToFood = min(SCENT_MAX_PER_CELL, lastState.z + discreteAnts.y);
if (discreteAnts.z == 1.) { if (discreteAnts.z == 1.) {
isFood = 0; isFood = 0;

View file

@ -16,8 +16,8 @@ void main() {
vec4 s3 = 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); vec4 s4 = texture(tWorld, vUv + vec2(1, -1) * offset);
float scentToHome = (s0.y + s1.y + s2.y + s3.y + s4.y) / 5. * SCENT_FADE_OUT_FACTOR; float scentToHome = (s0.y + s1.y + s2.y + s3.y + s4.y) / 5. * (1. - SCENT_FADE_OUT_FACTOR);
float scentToFood = (s0.z + s1.z + s2.z + s3.z + s4.z) / 5. * SCENT_FADE_OUT_FACTOR; float scentToFood = (s0.z + s1.z + s2.z + s3.z + s4.z) / 5. * (1. - SCENT_FADE_OUT_FACTOR);
FragColor = vec4( FragColor = vec4(
s0.x, s0.x,