Interaction improvements and minor fixes

This commit is contained in:
vHawk 2022-06-29 00:35:45 +03:00
parent fb772db717
commit 27c835b8e5
16 changed files with 262 additions and 95 deletions

View file

@ -25,7 +25,7 @@
"scripts": { "scripts": {
"build": "webpack --config ./webpack.config.js --mode=production", "build": "webpack --config ./webpack.config.js --mode=production",
"dev": "webpack serve --config ./webpack.config.js --mode=development", "dev": "webpack serve --config ./webpack.config.js --mode=development",
"gh-pages": "push-dir --dir=build --branch=gh-pages" "gh-pages": "npm run build && push-dir --dir=build --branch=gh-pages"
}, },
"author": "", "author": "",
"license": "MIT" "license": "MIT"

View file

@ -6,6 +6,7 @@ import AntsDiscretizeScene from "./scenes/AntsDiscretizeScene";
import WorldBlurScene from "./scenes/WorldBlurScene"; import WorldBlurScene from "./scenes/WorldBlurScene";
import Config from "./Config"; import Config from "./Config";
import GUI from "./GUI"; import GUI from "./GUI";
import DrawScene from "./scenes/DrawScene";
export interface SceneCollection { export interface SceneCollection {
ants: AntsComputeScene; ants: AntsComputeScene;
@ -13,6 +14,7 @@ export interface SceneCollection {
worldBlur: WorldBlurScene; worldBlur: WorldBlurScene;
discretize: AntsDiscretizeScene; discretize: AntsDiscretizeScene;
screen: ScreenScene; screen: ScreenScene;
draw: DrawScene;
} }
export default new class App { export default new class App {
@ -22,6 +24,7 @@ export default new class App {
private renderLoop = (deltaTime: number): void => this.render(deltaTime); private renderLoop = (deltaTime: number): void => this.render(deltaTime);
private simInterval: NodeJS.Timer; private simInterval: NodeJS.Timer;
private simulationStepsPerSecond: number = 0; private simulationStepsPerSecond: number = 0;
private simStarted: boolean = false;
constructor() { constructor() {
this.initScenes(); this.initScenes();
@ -47,6 +50,8 @@ export default new class App {
} }
this.simulationStep(); this.simulationStep();
this.simStarted = true;
}, 1000 / this.simulationStepsPerSecond); }, 1000 / this.simulationStepsPerSecond);
} }
@ -57,12 +62,13 @@ export default new class App {
worldBlur: new WorldBlurScene(this.renderer), worldBlur: new WorldBlurScene(this.renderer),
discretize: new AntsDiscretizeScene(this.renderer), discretize: new AntsDiscretizeScene(this.renderer),
screen: new ScreenScene(this.renderer), screen: new ScreenScene(this.renderer),
draw: new DrawScene(this.renderer)
}; };
} }
private resize() { private resize() {
const width = window.innerWidth; const width = window.innerWidth * window.devicePixelRatio;
const height = window.innerHeight; const height = window.innerHeight * window.devicePixelRatio;
this.renderer.resizeCanvas(width, height); this.renderer.resizeCanvas(width, height);
@ -82,6 +88,10 @@ export default new class App {
private render(deltaTime: number) { private render(deltaTime: number) {
requestAnimationFrame(this.renderLoop); requestAnimationFrame(this.renderLoop);
if (!this.simStarted) {
return;
}
this.renderer.renderToScreen(this.scenes); this.renderer.renderToScreen(this.scenes);
} }
} }

View file

@ -8,5 +8,6 @@ export default {
scentMaxStorage: 1e6, scentMaxStorage: 1e6,
scentPerMarker: 1000, scentPerMarker: 1000,
antSpeed: 1, antSpeed: 1,
antRotationAngle: Math.PI / 50 antRotationAngle: Math.PI / 50,
brushRadius: 20,
}; };

View file

@ -15,6 +15,8 @@ export default class GUI {
const controlsFolder = this.gui.addFolder('Controls'); const controlsFolder = this.gui.addFolder('Controls');
controlsFolder.add(Config, 'brushRadius', 1, 100);
simFolder.open(); simFolder.open();
controlsFolder.open(); controlsFolder.open();
} }

View file

@ -4,6 +4,7 @@ import Config from "./Config";
interface Resources { interface Resources {
worldRenderTarget: THREE.WebGLRenderTarget; worldRenderTarget: THREE.WebGLRenderTarget;
worldRenderTargetCopy: THREE.WebGLRenderTarget;
worldBlurredRenderTarget: THREE.WebGLRenderTarget; worldBlurredRenderTarget: THREE.WebGLRenderTarget;
antsDataRenderTarget0: THREE.WebGLRenderTarget; antsDataRenderTarget0: THREE.WebGLRenderTarget;
antsDataRenderTarget1: THREE.WebGLRenderTarget; antsDataRenderTarget1: THREE.WebGLRenderTarget;
@ -31,12 +32,19 @@ export default class Renderer {
magFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter,
minFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter,
}), }),
worldRenderTargetCopy: new THREE.WebGLRenderTarget(Config.worldSize, Config.worldSize, {
format: THREE.RGBAFormat,
type: THREE.FloatType,
depthBuffer: false,
magFilter: THREE.NearestFilter,
minFilter: THREE.LinearFilter,
}),
worldBlurredRenderTarget: new THREE.WebGLRenderTarget(Config.worldSize, Config.worldSize, { worldBlurredRenderTarget: new THREE.WebGLRenderTarget(Config.worldSize, Config.worldSize, {
format: THREE.RGBAFormat, format: THREE.RGBAFormat,
type: THREE.FloatType, type: THREE.FloatType,
depthBuffer: false, depthBuffer: false,
magFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter,
minFilter: THREE.LinearFilter, minFilter: THREE.NearestFilter,
}), }),
antsDataRenderTarget0: new THREE.WebGLRenderTarget(antTextureSize, antTextureSize, { antsDataRenderTarget0: new THREE.WebGLRenderTarget(antTextureSize, antTextureSize, {
format: THREE.RGBAFormat, format: THREE.RGBAFormat,
@ -65,39 +73,47 @@ export default class Renderer {
public renderSimulation(scenes: SceneCollection) { public renderSimulation(scenes: SceneCollection) {
const [antsComputeSource, antsComputeTarget] = scenes.ants.getRenderTargets(); const [antsComputeSource, antsComputeTarget] = scenes.ants.getRenderTargets();
this.renderer.setViewport(0, 0, scenes.worldBlur.renderWidth, scenes.worldBlur.renderHeight);
this.renderer.setRenderTarget(this.resources.worldBlurredRenderTarget);
scenes.worldBlur.material.uniforms.tWorld.value = this.resources.worldRenderTarget.texture;
this.renderer.render(scenes.worldBlur, scenes.worldBlur.camera);
this.renderer.setViewport(0, 0, scenes.ants.renderWidth, scenes.ants.renderHeight); this.renderer.setViewport(0, 0, scenes.ants.renderWidth, scenes.ants.renderHeight);
this.renderer.setRenderTarget(antsComputeTarget); this.renderer.setRenderTarget(antsComputeTarget);
scenes.ants.material.uniforms.tLastState.value = antsComputeSource.texture; scenes.ants.material.uniforms.tLastState.value = antsComputeSource.texture;
scenes.ants.material.uniforms.tWorld.value = scenes.worldBlur.getRenderTarget().texture; scenes.ants.material.uniforms.tWorld.value = this.resources.worldBlurredRenderTarget.texture;
this.renderer.render(scenes.ants, scenes.ants.camera); this.renderer.render(scenes.ants, scenes.ants.camera);
this.renderer.setViewport(0, 0, scenes.discretize.renderWidth, scenes.discretize.renderHeight); this.renderer.setViewport(0, 0, scenes.discretize.renderWidth, scenes.discretize.renderHeight);
this.renderer.setRenderTarget(scenes.discretize.getRenderTarget()); this.renderer.setRenderTarget(this.resources.antsDiscreteRenderTarget);
scenes.discretize.material.uniforms.tDataCurrent.value = antsComputeTarget.texture; scenes.discretize.material.uniforms.tDataCurrent.value = antsComputeTarget.texture;
scenes.discretize.material.uniforms.tDataLast.value = antsComputeSource.texture; scenes.discretize.material.uniforms.tDataLast.value = antsComputeSource.texture;
this.renderer.render(scenes.discretize, scenes.discretize.camera); this.renderer.render(scenes.discretize, scenes.discretize.camera);
this.renderer.setViewport(0, 0, scenes.world.renderWidth, scenes.world.renderHeight); this.renderer.setViewport(0, 0, scenes.world.renderWidth, scenes.world.renderHeight);
this.renderer.setRenderTarget(scenes.world.getRenderTarget()); this.renderer.setRenderTarget(this.resources.worldRenderTarget);
scenes.world.material.uniforms.tLastState.value = scenes.worldBlur.getRenderTarget().texture; scenes.world.material.uniforms.tLastState.value = this.resources.worldBlurredRenderTarget.texture;
scenes.world.material.uniforms.tDiscreteAnts.value = scenes.discretize.getRenderTarget().texture; scenes.world.material.uniforms.tDiscreteAnts.value = this.resources.antsDiscreteRenderTarget.texture;
scenes.world.material.uniforms.pointerData.value = scenes.screen.getPointerData();
this.renderer.render(scenes.world, scenes.world.camera); this.renderer.render(scenes.world, scenes.world.camera);
this.renderer.setViewport(0, 0, scenes.worldBlur.renderWidth, scenes.worldBlur.renderHeight);
this.renderer.setRenderTarget(scenes.worldBlur.getRenderTarget());
scenes.worldBlur.material.uniforms.tWorld.value = scenes.world.getRenderTarget().texture;
this.renderer.render(scenes.worldBlur, scenes.worldBlur.camera);
scenes.screen.material.uniforms.tData.value = antsComputeTarget.texture; scenes.screen.material.uniforms.tData.value = antsComputeTarget.texture;
scenes.screen.groundMaterial.uniforms.map.value = scenes.worldBlur.getRenderTarget().texture; scenes.screen.groundMaterial.uniforms.map.value = this.resources.worldRenderTargetCopy.texture;
} }
public renderToScreen(scenes: SceneCollection) { public renderToScreen(scenes: SceneCollection) {
this.renderer.setViewport(0, 0, scenes.draw.renderWidth, scenes.draw.renderHeight);
this.renderer.setRenderTarget(this.resources.worldRenderTargetCopy);
scenes.draw.material.uniforms.tWorld.value = this.resources.worldRenderTarget.texture;
scenes.draw.material.uniforms.pointerPosition.value = scenes.screen.pointerPosition;
scenes.draw.material.uniforms.drawMode.value = scenes.screen.drawMode;
scenes.draw.material.uniforms.brushRadius.value = Config.brushRadius;
this.renderer.render(scenes.draw, scenes.draw.camera);
this.renderer.copyFramebufferToTexture(new THREE.Vector2(), this.resources.worldRenderTarget.texture);
this.renderer.setViewport(0, 0, scenes.screen.renderWidth, scenes.screen.renderHeight); this.renderer.setViewport(0, 0, scenes.screen.renderWidth, scenes.screen.renderHeight);
this.renderer.setRenderTarget(null); this.renderer.setRenderTarget(null);
this.renderer.render(scenes.screen, scenes.screen.camera); this.renderer.render(scenes.screen, scenes.screen.camera);

49
src/scenes/DrawScene.ts Normal file
View file

@ -0,0 +1,49 @@
import * as THREE from 'three';
import Renderer from "../Renderer";
import AbstractScene from "./AbstractScene";
import FullScreenTriangleGeometry from "../utils/FullScreenTriangleGeometry";
import fragmentShader from '../shaders/draw.frag';
import vertexShader from '../shaders/draw.vert';
import {WebGLRenderTarget} from "three";
export default class DrawScene extends AbstractScene {
public readonly camera: THREE.OrthographicCamera = new THREE.OrthographicCamera();
public readonly material: THREE.RawShaderMaterial;
constructor(renderer: Renderer) {
super(renderer);
const geometry = new FullScreenTriangleGeometry();
const material = new THREE.RawShaderMaterial({
uniforms: {
tWorld: {value: null},
pointerPosition: {value: new THREE.Vector2()},
drawMode: {value: 0},
brushRadius: {value: 0},
},
vertexShader,
fragmentShader,
defines: this.renderer.getCommonMaterialDefines(),
glslVersion: THREE.GLSL3
});
const mesh = new THREE.Mesh(geometry, material);
this.add(mesh);
this.material = material;
this.renderWidth = this.renderer.resources.worldRenderTarget.width;
this.renderHeight = this.renderer.resources.worldRenderTarget.height;
}
public getRenderTarget(): WebGLRenderTarget {
return this.renderer.resources.worldRenderTarget;
}
public resize(width: number, height: number) {
}
public update(deltaTime: number) {
}
}

View file

@ -8,25 +8,29 @@ import fragmentShaderGround from "../shaders/screenWorld.frag";
enum PointerState { enum PointerState {
None, None,
LMB, Food,
RMB Home,
Obstacle
} }
export default class ScreenScene extends AbstractScene { export default class ScreenScene extends AbstractScene {
public readonly camera: THREE.PerspectiveCamera; public readonly camera: THREE.OrthographicCamera;
public readonly material: THREE.ShaderMaterial; public readonly material: THREE.ShaderMaterial;
public readonly groundMaterial: THREE.ShaderMaterial; public readonly groundMaterial: THREE.ShaderMaterial;
public readonly pointerPosition: THREE.Vector2 = new THREE.Vector2(); public readonly pointerPosition: THREE.Vector2 = new THREE.Vector2();
public pointerState: PointerState = PointerState.None; public drawMode: PointerState = PointerState.None;
private cameraZoomLinear: number = 0;
private isPointerDown: boolean = false;
constructor(renderer: Renderer) { constructor(renderer: Renderer) {
super(renderer); super(renderer);
const ground = new THREE.Mesh( const ground = new THREE.Mesh(
new THREE.PlaneBufferGeometry(10, 10), new THREE.PlaneBufferGeometry(1, 1),
new THREE.ShaderMaterial({ new THREE.ShaderMaterial({
uniforms: { uniforms: {
map: {value: this.renderer.resources.worldRenderTarget.texture}, map: {value: this.renderer.resources.worldRenderTarget.texture},
tDiscreteAnts: {value: this.renderer.resources.antsDiscreteRenderTarget.texture},
}, },
vertexShader: vertexShaderGround, vertexShader: vertexShaderGround,
fragmentShader: fragmentShaderGround, fragmentShader: fragmentShaderGround,
@ -37,8 +41,8 @@ export default class ScreenScene extends AbstractScene {
this.groundMaterial = ground.material; this.groundMaterial = ground.material;
ground.position.x += 5; //ground.position.x = 0.5;
ground.position.y += 5; //ground.position.y = 0.5;
this.add(ground); this.add(ground);
@ -60,48 +64,31 @@ export default class ScreenScene extends AbstractScene {
}); });
const ants = new THREE.InstancedMesh( const ants = new THREE.InstancedMesh(
new THREE.PlaneBufferGeometry(0.15, 0.15), new THREE.PlaneBufferGeometry(0.015, 0.015),
this.material, this.material,
this.renderer.resources.antsDataRenderTarget0.width * this.renderer.resources.antsDataRenderTarget0.height this.renderer.resources.antsDataRenderTarget0.width * this.renderer.resources.antsDataRenderTarget0.height
) )
ants.position.x = ants.position.y = -0.5;
this.add(ants); this.add(ants);
this.camera = new THREE.PerspectiveCamera(50, 1, 0.1, 10000); this.camera = new THREE.OrthographicCamera(-0.5, 0.5, 0.5, -0.5);
this.add(this.camera); this.add(this.camera);
this.camera.position.z = 12; this.camera.position.z = 12;
this.camera.position.x = this.camera.position.y = 5;
const raycastVector = new THREE.Vector2(0, 0); const raycastVector = new THREE.Vector2(0, 0);
const raycaster = new THREE.Raycaster(); const raycaster = new THREE.Raycaster();
this.renderer.canvas.addEventListener('contextmenu', (e) => { this.renderer.canvas.addEventListener('contextmenu', e => {
e.preventDefault(); e.preventDefault();
}); });
this.renderer.canvas.addEventListener('pointerdown', (e) => { this.renderer.canvas.addEventListener('pointerdown', e => {
raycastVector.x = (e.clientX / window.innerWidth) * 2 - 1; this.isPointerDown = true;
raycastVector.y = -(e.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(raycastVector, this.camera);
const intersects = raycaster.intersectObjects([ground]);
if (intersects.length > 0) {
const uv = intersects[0].uv;
this.pointerPosition.copy(uv);
if (e.button === 0) {
this.pointerState = PointerState.LMB;
} else if (e.button === 2) {
this.pointerState = PointerState.RMB;
}
}
});
this.renderer.canvas.addEventListener('pointermove', (e) => {
raycastVector.x = (e.clientX / window.innerWidth) * 2 - 1; raycastVector.x = (e.clientX / window.innerWidth) * 2 - 1;
raycastVector.y = -(e.clientY / window.innerHeight) * 2 + 1; raycastVector.y = -(e.clientY / window.innerHeight) * 2 + 1;
@ -115,22 +102,77 @@ export default class ScreenScene extends AbstractScene {
} }
}); });
this.renderer.canvas.addEventListener('pointerup', (e) => { this.renderer.canvas.addEventListener('pointermove', e => {
this.pointerState = PointerState.None; if (this.isPointerDown) {
const dx = e.movementX;
const dy = e.movementY;
this.camera.position.x -= dx / window.innerHeight / this.camera.zoom;
this.camera.position.y += dy / window.innerHeight / this.camera.zoom;
}
raycastVector.x = (e.clientX / window.innerWidth) * 2 - 1;
raycastVector.y = -(e.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(raycastVector, this.camera);
const intersects = raycaster.intersectObjects([ground]);
if (intersects.length > 0) {
const uv = intersects[0].uv;
this.pointerPosition.copy(uv);
}
});
this.renderer.canvas.addEventListener('pointerup', e => {
this.isPointerDown = false;
});
this.renderer.canvas.addEventListener('pointerleave', e => {
this.isPointerDown = false;
});
this.renderer.canvas.addEventListener('wheel', e => {
this.cameraZoomLinear -= e.deltaY * 0.001;
this.updateCameraZoom();
});
window.addEventListener('keydown', e => {
switch (e.code) {
case 'KeyQ': {
this.drawMode = PointerState.Home;
break;
}
case 'KeyW': {
this.drawMode = PointerState.Food;
break;
}
case 'KeyE': {
this.drawMode = PointerState.Obstacle;
break;
}
}
});
window.addEventListener('keyup', e => {
this.drawMode = PointerState.None;
}); });
} }
public getPointerData(): THREE.Vector4 { private updateCameraZoom() {
return new THREE.Vector4( this.camera.zoom = 2 ** this.cameraZoomLinear;
+(this.pointerState === PointerState.LMB), this.camera.updateProjectionMatrix();
+(this.pointerState === PointerState.RMB),
this.pointerPosition.x,
this.pointerPosition.y
);
} }
public resize(width: number, height: number) { public resize(width: number, height: number) {
this.camera.aspect = width / height; const aspect = width / height;
this.camera.left = -0.5 * aspect;
this.camera.right = 0.5 * aspect;
this.camera.top = 0.5;
this.camera.bottom = -0.5;
this.camera.updateProjectionMatrix(); this.camera.updateProjectionMatrix();
this.renderWidth = width; this.renderWidth = width;

View file

@ -16,9 +16,8 @@ export default class WorldComputeScene extends AbstractScene {
const geometry = new FullScreenTriangleGeometry(); const geometry = new FullScreenTriangleGeometry();
const material = new THREE.RawShaderMaterial({ const material = new THREE.RawShaderMaterial({
uniforms: { uniforms: {
tLastState: {value: this.renderer.resources.worldRenderTarget.texture}, tLastState: {value: null},
tDiscreteAnts: {value: this.renderer.resources.antsDiscreteRenderTarget.texture}, tDiscreteAnts: {value: null}
pointerData: {value: new THREE.Vector4()},
}, },
vertexShader, vertexShader,
fragmentShader, fragmentShader,

View file

@ -26,7 +26,7 @@ void main() {
vec4 dataSample = texture(tData, vec2(sampleX, sampleY) / dataTextureSize); vec4 dataSample = texture(tData, vec2(sampleX, sampleY) / dataTextureSize);
vec2 offset = dataSample.xy * 10.; vec2 offset = dataSample.xy;
vec2 rotatedPosition = rotate(position.xy, -dataSample.z + PI * 0.5); vec2 rotatedPosition = rotate(position.xy, -dataSample.z + PI * 0.5);
vIsCarryingFood = float(int(dataSample.w) & 1); vIsCarryingFood = float(int(dataSample.w) & 1);

View file

@ -77,21 +77,6 @@ void main() {
storage = 0.; storage = 0.;
} }
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;
}
}
if (isCarrying == 0.) { if (isCarrying == 0.) {
if (noise < 0.33) { if (noise < 0.33) {
vec2 offset = vec2(cos(angle), sin(angle)) * sampleDistance; vec2 offset = vec2(cos(angle), sin(angle)) * sampleDistance;
@ -181,6 +166,21 @@ void main() {
angle += PI * (noise - 0.5); 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( FragColor = vec4(
pos.x, pos.x,
pos.y, pos.y,

View file

@ -38,7 +38,7 @@ void main() {
vIsCellCleared = isCellCleared; vIsCellCleared = isCellCleared;
gl_Position = vec4( gl_Position = vec4(
(position.xy * cellSize * 0.1 + floor(offset * WORLD_SIZE) / WORLD_SIZE + cellSize * 0.5) * 2. - 1., (position.xy * cellSize * 0.01 + floor(offset * WORLD_SIZE) / WORLD_SIZE + cellSize * 0.5) * 2. - 1.,
0, 0,
1 1
); );

28
src/shaders/draw.frag Normal file
View file

@ -0,0 +1,28 @@
precision highp float;
precision highp int;
in vec2 vUv;
out vec4 FragColor;
uniform sampler2D tWorld;
uniform vec2 pointerPosition;
uniform float drawMode;
uniform float brushRadius;
void main() {
vec4 lastState = texture(tWorld, vUv);
float isFood = lastState.x;
float isHome = lastState.y;
if (distance(pointerPosition, vUv) < brushRadius / WORLD_SIZE) {
if (drawMode == 1.) {
isFood = 1.;
} else if (drawMode == 2.) {
isHome = 1.;
}
}
FragColor = vec4(isFood, isHome, lastState.zw);
}

12
src/shaders/draw.vert Normal file
View file

@ -0,0 +1,12 @@
precision highp float;
precision highp int;
in vec3 position;
in vec2 uv;
out vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4(position, 1.0);
}

View file

@ -6,21 +6,35 @@ in vec2 vUv;
out vec4 FragColor; out vec4 FragColor;
uniform sampler2D map; uniform sampler2D map;
uniform sampler2D tDiscreteAnts;
void main() { void main() {
vec4 value = clamp(texture(map, vUv), 0., 1.); vec4 value = clamp(texture(map, vUv), 0., 1.);
vec3 bg = vec3(0.9);
bg = mix(bg, vec3(0.2, 0.2, 0.8), clamp(value.a, 0., 1.)); float isFood = value.r;
bg = mix(bg, vec3(0.8, 0.2, 0.2), clamp(value.b, 0., 1.)); float isHome = value.g;
float toFood = value.b;
float toHome = value.a;
if (value.r == 1.) { // The part below doen't seem right.
bg = vec3(1, 0.2, 0.2); // I could figure out a better way to make pheromone colors blend properly on white background :(
vec3 t = vec3(0.95, 0.2, 0.2) * toFood + vec3(0.2, 0.2, 0.95) * toHome;
float a = clamp(toHome + toFood, 0., 1.);
t /= a;
if (a == 0.) t = vec3(0);
vec3 color = mix(vec3(1, 1, 1), t, a * 0.7);
if (isFood == 1.) {
color = vec3(1, 0.1, 0.1);
} }
if (value.g == 1.) { if (isHome == 1.) {
bg = vec3(0.2, 0.2, 1); color = vec3(0.1, 0.1, 1);
} }
FragColor = vec4(bg, 1); FragColor = vec4(color, 1);
} }

View file

@ -7,7 +7,6 @@ out vec4 FragColor;
uniform sampler2D tLastState; uniform sampler2D tLastState;
uniform sampler2D tDiscreteAnts; uniform sampler2D tDiscreteAnts;
uniform vec4 pointerData;
void main() { void main() {
vec4 lastState = texture(tLastState, vUv); vec4 lastState = texture(tLastState, vUv);
@ -15,17 +14,12 @@ void main() {
float isFood = lastState.x; float isFood = lastState.x;
float isHome = lastState.y; float isHome = lastState.y;
float scentToHome = lastState.z + discreteAnts.x * 2.; float scentToHome = min(10., lastState.z + discreteAnts.x * 2.);
float scentToFood = lastState.w + discreteAnts.y * 2.; float scentToFood = min(10., lastState.w + discreteAnts.y * 2.);
if (discreteAnts.z == 1.) { if (discreteAnts.z == 1.) {
isFood = 0.; isFood = 0.;
} }
if (distance(pointerData.zw, vUv) < 0.02) {
isFood = max(isFood, pointerData.x);
isHome = max(isHome, pointerData.y);
}
FragColor = vec4(isFood, isHome, scentToHome, scentToFood); FragColor = vec4(isFood, isHome, scentToHome, scentToFood);
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 229 B

After

Width:  |  Height:  |  Size: 229 B