From c84a3b46b76c89c70b018fb350fca12a0873d766 Mon Sep 17 00:00:00 2001 From: vHawk <48140945+vHawk@users.noreply.github.com> Date: Mon, 11 Jul 2022 03:05:09 +0300 Subject: [PATCH] Update GUI --- README.md | 4 --- src/App.ts | 43 +++++++++++++------------------ src/Config.ts | 2 +- src/GUI.ts | 29 ++++++++++++++------- src/Renderer.ts | 4 +-- src/index.html | 2 +- src/scenes/AbstractScene.ts | 2 +- src/scenes/AntsComputeScene.ts | 2 +- src/scenes/AntsDiscretizeScene.ts | 2 +- src/scenes/DrawScene.ts | 2 +- src/scenes/ScreenScene.ts | 9 +++++-- src/scenes/WorldBlurScene.ts | 2 +- src/scenes/WorldComputeScene.ts | 2 +- src/shaders/ants.vert | 3 ++- src/shaders/draw.frag | 4 +++ 15 files changed, 60 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index 30cf4c9..70efa16 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,6 @@ If an ant senses the desirable pheromones nearby, then it turns to the direction It is important to prevent ants from following pheromone trails left by those ants who wandered too far from home or a food source. Each individual ant has an inventory for storing pheromones. Each time an ant leaves a pheromone marker anywhere on the map a small portion of the stored pheromones is used. And each time it picks up food or reaches home its inventory gets fully refilled. Pheromone trails left by ants evaporate and diffuse over time. - -## Compute pipeline overview - -TODO ## References diff --git a/src/App.ts b/src/App.ts index 18d9ddd..176d0d5 100644 --- a/src/App.ts +++ b/src/App.ts @@ -21,10 +21,9 @@ export default new class App { private renderer: Renderer = new Renderer(document.getElementById('canvas')); private scenes: SceneCollection; private gui: GUI = new GUI(); - private renderLoop = (deltaTime: number): void => this.render(deltaTime); - private simInterval: NodeJS.Timer; - private simulationStepsPerSecond: number = 0; - private simStarted: boolean = false; + private renderLoop = (time: number): void => this.render(time); + private lastTime: number = 0; + private queuedSimSteps: number = 0; constructor() { this.initScenes(); @@ -35,9 +34,6 @@ export default new class App { this.renderLoop(0); - this.simulationStepsPerSecond = Config.simulationStepsPerSecond; - this.updateSimulationInterval(); - this.gui.on('antsCount', () => { this.resetRenderer(); }); @@ -45,27 +41,12 @@ export default new class App { this.gui.on('worldSize', () => { this.resetRenderer(); }); - - this.gui.on('simulationStepsPerSecond', () => { - this.simulationStepsPerSecond = Config.simulationStepsPerSecond; - this.updateSimulationInterval(); - }); } private resetRenderer() { this.renderer.reset(this.scenes); } - private updateSimulationInterval() { - clearInterval(this.simInterval); - - this.simInterval = setInterval(() => { - this.simulationStep(); - - this.simStarted = true; - }, 1000 / this.simulationStepsPerSecond); - } - private initScenes() { this.scenes = { ants: new AntsComputeScene(this.renderer), @@ -90,19 +71,31 @@ export default new class App { private simulationStep() { for (const scene of Object.values(this.scenes)) { - scene.update(0); + scene.update(); } this.renderer.renderSimulation(this.scenes); } - private render(deltaTime: number) { + private render(time: number) { requestAnimationFrame(this.renderLoop); - if (!this.simStarted) { + const deltaTime = time - this.lastTime; + const simStepsToDo = deltaTime / 1000 * Config.simulationStepsPerSecond; + + this.queuedSimSteps += simStepsToDo; + + while (this.queuedSimSteps >= 1) { + this.simulationStep(); + --this.queuedSimSteps; + } + + if (time === 0) { return; } this.renderer.renderToScreen(this.scenes); + + this.lastTime = time; } } \ No newline at end of file diff --git a/src/Config.ts b/src/Config.ts index cdd9b01..63342e0 100644 --- a/src/Config.ts +++ b/src/Config.ts @@ -1,6 +1,6 @@ export default { worldSize: 1024, - antsCount: 64 ** 2, + antsCount: 12, simulationStepsPerSecond: 60, scentThreshold: 0.01, scentFadeOutFactor: 0.998, diff --git a/src/GUI.ts b/src/GUI.ts index e657a7c..4b79c5a 100644 --- a/src/GUI.ts +++ b/src/GUI.ts @@ -12,19 +12,28 @@ export default class GUI extends EventEmitter { const simFolder = this.gui.addFolder('Simulation'); - simFolder.add(Config, 'worldSize', 256, 4096).onChange(() => { - this.emit('worldSize'); - }); - simFolder.add(Config, 'antsCount', 1, 1e6).onChange(() => { - this.emit('antsCount'); - }); - simFolder.add(Config, 'simulationStepsPerSecond', 1, 500).onChange(() => { - this.emit('simulationStepsPerSecond'); - }); + simFolder.add(Config, 'worldSize', 256, 4096) + .name('World size') + .step(1) + .onChange(() => { + this.emit('worldSize'); + }); + simFolder.add(Config, 'antsCount', 0, 22) + .name('Ants count 2^') + .step(1) + .onChange(() => { + this.emit('antsCount'); + }); + simFolder.add(Config, 'simulationStepsPerSecond', 1, 500) + .name('Simulation steps per second') + .step(1) + .onChange(() => { + this.emit('simulationStepsPerSecond'); + }); const controlsFolder = this.gui.addFolder('Controls'); - controlsFolder.add(Config, 'brushRadius', 1, 100); + controlsFolder.add(Config, 'brushRadius', 1, 100).name('Brush radius'); simFolder.open(); controlsFolder.open(); diff --git a/src/Renderer.ts b/src/Renderer.ts index 2393408..e83941a 100644 --- a/src/Renderer.ts +++ b/src/Renderer.ts @@ -23,7 +23,7 @@ export default class Renderer { } private initResources() { - const antTextureSize = Math.round(Math.sqrt(Config.antsCount)); + const antTextureSize = Math.round(Math.sqrt(2 ** Config.antsCount)); this.resources = { worldRenderTarget: new THREE.WebGLRenderTarget(Config.worldSize, Config.worldSize, { @@ -139,7 +139,7 @@ export default class Renderer { } public reset(scenes: SceneCollection) { - const antTextureSize = Math.ceil(Math.sqrt(Config.antsCount)); + const antTextureSize = Math.round(Math.sqrt(2 ** Config.antsCount)); this.resources.worldRenderTarget.setSize(Config.worldSize, Config.worldSize) this.renderer.setRenderTarget(this.resources.worldRenderTarget); diff --git a/src/index.html b/src/index.html index 89288ee..0fd00f8 100644 --- a/src/index.html +++ b/src/index.html @@ -25,7 +25,7 @@ -
Controls:
Q - draw home cells
W - draw food cells
E - draw obstacle
Drag and scroll to move the camera
+
Controls:
Q - draw home cells
W - draw food cells
E - draw obstacle
R - erase
Drag and scroll to move the camera
diff --git a/src/scenes/AbstractScene.ts b/src/scenes/AbstractScene.ts index 01eae6c..9f67445 100644 --- a/src/scenes/AbstractScene.ts +++ b/src/scenes/AbstractScene.ts @@ -15,5 +15,5 @@ export default abstract class AbstractScene extends THREE.Scene { public abstract resize(width: number, height: number): void; - public abstract update(deltaTime: number): void; + public abstract update(): void; } \ No newline at end of file diff --git a/src/scenes/AntsComputeScene.ts b/src/scenes/AntsComputeScene.ts index f658224..bd4b1e9 100644 --- a/src/scenes/AntsComputeScene.ts +++ b/src/scenes/AntsComputeScene.ts @@ -52,7 +52,7 @@ export default class AntsComputeScene extends AbstractScene { } - public update(deltaTime: number) { + public update() { this.material.uniforms.uTime.value = performance.now(); } } \ No newline at end of file diff --git a/src/scenes/AntsDiscretizeScene.ts b/src/scenes/AntsDiscretizeScene.ts index 3e95bce..27aafd5 100644 --- a/src/scenes/AntsDiscretizeScene.ts +++ b/src/scenes/AntsDiscretizeScene.ts @@ -50,7 +50,7 @@ export default class AntsDiscretizeScene extends AbstractScene { } - public update(deltaTime: number) { + public update() { } } \ No newline at end of file diff --git a/src/scenes/DrawScene.ts b/src/scenes/DrawScene.ts index d0d9f9e..12c3268 100644 --- a/src/scenes/DrawScene.ts +++ b/src/scenes/DrawScene.ts @@ -40,7 +40,7 @@ export default class DrawScene extends AbstractScene { } - public update(deltaTime: number) { + public update() { } } \ No newline at end of file diff --git a/src/scenes/ScreenScene.ts b/src/scenes/ScreenScene.ts index f376fbd..2000bd7 100644 --- a/src/scenes/ScreenScene.ts +++ b/src/scenes/ScreenScene.ts @@ -11,7 +11,8 @@ enum PointerState { None, Food, Home, - Obstacle + Obstacle, + Erase } export default class ScreenScene extends AbstractScene { @@ -144,6 +145,10 @@ export default class ScreenScene extends AbstractScene { this.drawMode = PointerState.Obstacle; break; } + case 'KeyR': { + this.drawMode = PointerState.Erase; + break; + } } }); @@ -198,7 +203,7 @@ export default class ScreenScene extends AbstractScene { this.renderHeight = height; } - public update(deltaTime: number) { + public update() { } } \ No newline at end of file diff --git a/src/scenes/WorldBlurScene.ts b/src/scenes/WorldBlurScene.ts index 71136ac..9f8a298 100644 --- a/src/scenes/WorldBlurScene.ts +++ b/src/scenes/WorldBlurScene.ts @@ -37,7 +37,7 @@ export default class WorldBlurScene extends AbstractScene { } - public update(deltaTime: number) { + public update() { } } \ No newline at end of file diff --git a/src/scenes/WorldComputeScene.ts b/src/scenes/WorldComputeScene.ts index a463d62..0d47c71 100644 --- a/src/scenes/WorldComputeScene.ts +++ b/src/scenes/WorldComputeScene.ts @@ -38,7 +38,7 @@ export default class WorldComputeScene extends AbstractScene { } - public update(deltaTime: number) { + public update() { } } \ No newline at end of file diff --git a/src/shaders/ants.vert b/src/shaders/ants.vert index 57fc9f2..12221a8 100644 --- a/src/shaders/ants.vert +++ b/src/shaders/ants.vert @@ -23,8 +23,9 @@ void main() { float id = float(gl_InstanceID); float sampleY = floor(id / dataTextureSize); float sampleX = id - sampleY * dataTextureSize; + vec2 antDataUV = (vec2(sampleX, sampleY) + 0.5) / dataTextureSize; - vec4 dataSample = texture(tData, vec2(sampleX, sampleY) / dataTextureSize); + vec4 dataSample = texture(tData, antDataUV); vec2 offset = dataSample.xy; vec2 rotatedPosition = rotate(position.xy, -dataSample.z + PI * 0.5); diff --git a/src/shaders/draw.frag b/src/shaders/draw.frag index 294ecd7..483942e 100644 --- a/src/shaders/draw.frag +++ b/src/shaders/draw.frag @@ -25,6 +25,10 @@ void main() { isHome = 1; } else if (drawMode == 3.) { isObstacle = 1; + } else if (drawMode == 4.) { + isFood = 0; + isHome = 0; + isObstacle = 0; } }