Update GUI

This commit is contained in:
vHawk 2022-07-11 03:05:09 +03:00
parent a3c03cafef
commit c84a3b46b7
15 changed files with 60 additions and 52 deletions

View file

@ -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

View file

@ -21,10 +21,9 @@ export default new class App {
private renderer: Renderer = new Renderer(<HTMLCanvasElement>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;
}
}

View file

@ -1,6 +1,6 @@
export default {
worldSize: 1024,
antsCount: 64 ** 2,
antsCount: 12,
simulationStepsPerSecond: 60,
scentThreshold: 0.01,
scentFadeOutFactor: 0.998,

View file

@ -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();

View file

@ -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);

View file

@ -25,7 +25,7 @@
</style>
</head>
<body>
<div id="info">Controls:<br/>Q - draw home cells<br/>W - draw food cells<br/>E - draw obstacle<br/>Drag and scroll to move the camera</div>
<div id="info">Controls:<br/>Q - draw home cells<br/>W - draw food cells<br/>E - draw obstacle<br/>R - erase<br/>Drag and scroll to move the camera</div>
<canvas id="canvas"></canvas>
</body>
</html>

View file

@ -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;
}

View file

@ -52,7 +52,7 @@ export default class AntsComputeScene extends AbstractScene {
}
public update(deltaTime: number) {
public update() {
this.material.uniforms.uTime.value = performance.now();
}
}

View file

@ -50,7 +50,7 @@ export default class AntsDiscretizeScene extends AbstractScene {
}
public update(deltaTime: number) {
public update() {
}
}

View file

@ -40,7 +40,7 @@ export default class DrawScene extends AbstractScene {
}
public update(deltaTime: number) {
public update() {
}
}

View file

@ -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() {
}
}

View file

@ -37,7 +37,7 @@ export default class WorldBlurScene extends AbstractScene {
}
public update(deltaTime: number) {
public update() {
}
}

View file

@ -38,7 +38,7 @@ export default class WorldComputeScene extends AbstractScene {
}
public update(deltaTime: number) {
public update() {
}
}

View file

@ -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);

View file

@ -25,6 +25,10 @@ void main() {
isHome = 1;
} else if (drawMode == 3.) {
isObstacle = 1;
} else if (drawMode == 4.) {
isFood = 0;
isHome = 0;
isObstacle = 0;
}
}