diff --git a/src/Renderer.ts b/src/Renderer.ts index a91fc6a..7a3979a 100644 --- a/src/Renderer.ts +++ b/src/Renderer.ts @@ -7,8 +7,8 @@ interface Resources { worldRenderTarget: THREE.WebGLRenderTarget; worldRenderTargetCopy: THREE.WebGLRenderTarget; worldBlurredRenderTarget: THREE.WebGLRenderTarget; - antsDataRenderTarget0: THREE.WebGLRenderTarget; - antsDataRenderTarget1: THREE.WebGLRenderTarget; + antsComputeTarget0: THREE.WebGLRenderTarget; + antsComputeTarget1: THREE.WebGLRenderTarget; antsDiscreteRenderTarget: THREE.WebGLRenderTarget; } @@ -59,28 +59,8 @@ export default class Renderer { minFilter: THREE.NearestFilter, }, ), - antsDataRenderTarget0: new THREE.WebGLRenderTarget( - antTextureSize, - antTextureSize, - { - format: THREE.RGBAFormat, - type: THREE.FloatType, - depthBuffer: false, - magFilter: THREE.NearestFilter, - minFilter: THREE.NearestFilter, - }, - ), - antsDataRenderTarget1: new THREE.WebGLRenderTarget( - antTextureSize, - antTextureSize, - { - format: THREE.RGBAFormat, - type: THREE.FloatType, - depthBuffer: false, - magFilter: THREE.NearestFilter, - minFilter: THREE.NearestFilter, - }, - ), + antsComputeTarget0: Renderer.makeAntsMRT(antTextureSize), + antsComputeTarget1: Renderer.makeAntsMRT(antTextureSize), antsDiscreteRenderTarget: new THREE.WebGLRenderTarget( Config.worldSize, Config.worldSize, @@ -95,6 +75,23 @@ export default class Renderer { }; } + private static makeAntsMRT(size: number): THREE.WebGLRenderTarget { + const mrt = new THREE.WebGLRenderTarget(size, size, { + count: 2, + type: THREE.FloatType, + magFilter: THREE.NearestFilter, + minFilter: THREE.NearestFilter, + depthBuffer: false, + }); + // both attachments get the same texture params + for (const texture of mrt.textures) { + texture.type = THREE.FloatType; + texture.magFilter = THREE.NearestFilter; + texture.minFilter = THREE.NearestFilter; + } + return mrt; + } + public renderSimulation(scenes: SceneCollection) { const [antsComputeSource, antsComputeTarget] = scenes.ants.getRenderTargets(); @@ -108,7 +105,9 @@ export default class Renderer { this.setViewportFromRT(antsComputeTarget); this.renderer.setRenderTarget(antsComputeTarget); scenes.ants.material.uniforms.tLastState.value = - antsComputeSource.texture; + antsComputeSource.textures[0]; + scenes.ants.material.uniforms.tLastExtState.value = + antsComputeSource.textures[1]; scenes.ants.material.uniforms.tWorld.value = this.resources.worldBlurredRenderTarget.texture; this.renderer.render(scenes.ants, scenes.ants.camera); @@ -116,9 +115,11 @@ export default class Renderer { this.setViewportFromRT(this.resources.antsDiscreteRenderTarget); this.renderer.setRenderTarget(this.resources.antsDiscreteRenderTarget); scenes.discretize.material.uniforms.tDataCurrent.value = - antsComputeTarget.texture; + antsComputeTarget.textures[0]; scenes.discretize.material.uniforms.tDataLast.value = - antsComputeSource.texture; + antsComputeSource.textures[0]; + scenes.discretize.material.uniforms.tDataExtCurrent.value = + antsComputeTarget.textures[1]; this.renderer.render(scenes.discretize, scenes.discretize.camera); this.setViewportFromRT(this.resources.worldRenderTarget); @@ -129,7 +130,8 @@ export default class Renderer { this.resources.antsDiscreteRenderTarget.texture; this.renderer.render(scenes.world, scenes.world.camera); - scenes.screen.material.uniforms.tData.value = antsComputeTarget.texture; + scenes.screen.material.uniforms.tData.value = + antsComputeTarget.textures[0]; scenes.screen.groundMaterial.uniforms.map.value = this.resources.worldRenderTargetCopy.texture; } @@ -220,18 +222,18 @@ export default class Renderer { this.renderer.setRenderTarget(this.resources.worldBlurredRenderTarget); this.renderer.clear(); - this.resources.antsDataRenderTarget0.setSize( + this.resources.antsComputeTarget0.setSize( antTextureSize, antTextureSize, ); - this.renderer.setRenderTarget(this.resources.antsDataRenderTarget0); + this.renderer.setRenderTarget(this.resources.antsComputeTarget0); this.renderer.clear(); - this.resources.antsDataRenderTarget1.setSize( + this.resources.antsComputeTarget1.setSize( antTextureSize, antTextureSize, ); - this.renderer.setRenderTarget(this.resources.antsDataRenderTarget1); + this.renderer.setRenderTarget(this.resources.antsComputeTarget1); this.renderer.clear(); this.resources.antsDiscreteRenderTarget.setSize( diff --git a/src/scenes/AntsComputeScene.ts b/src/scenes/AntsComputeScene.ts index d6d82b0..82b85e9 100644 --- a/src/scenes/AntsComputeScene.ts +++ b/src/scenes/AntsComputeScene.ts @@ -19,6 +19,7 @@ export default class AntsComputeScene extends AbstractScene { uniforms: { uTime: { value: 0 }, tLastState: { value: null }, + tLastExtState: { value: null }, tWorld: { value: null }, }, vertexShader, @@ -32,8 +33,8 @@ export default class AntsComputeScene extends AbstractScene { this.material = material; this.renderTargets = [ - this.renderer.resources.antsDataRenderTarget0, - this.renderer.resources.antsDataRenderTarget1, + this.renderer.resources.antsComputeTarget0, + this.renderer.resources.antsComputeTarget1, ]; } diff --git a/src/scenes/AntsDiscretizeScene.ts b/src/scenes/AntsDiscretizeScene.ts index f0ac7db..db4fcd0 100644 --- a/src/scenes/AntsDiscretizeScene.ts +++ b/src/scenes/AntsDiscretizeScene.ts @@ -17,6 +17,7 @@ export default class AntsDiscretizeScene extends AbstractScene { uniforms: { tDataCurrent: { value: null }, tDataLast: { value: null }, + tDataExtCurrent: { value: null }, }, vertexShader, fragmentShader, @@ -36,8 +37,8 @@ export default class AntsDiscretizeScene extends AbstractScene { this.mesh = new THREE.InstancedMesh( new THREE.BoxGeometry(1, 1, 1), this.material, - this.renderer.resources.antsDataRenderTarget0.width * - this.renderer.resources.antsDataRenderTarget0.height, + this.renderer.resources.antsComputeTarget0.width * + this.renderer.resources.antsComputeTarget0.height, ); this.add(this.mesh); } diff --git a/src/scenes/ScreenScene.ts b/src/scenes/ScreenScene.ts index daff0c2..6964814 100644 --- a/src/scenes/ScreenScene.ts +++ b/src/scenes/ScreenScene.ts @@ -60,8 +60,8 @@ export default class ScreenScene extends AbstractScene { this.material = new THREE.ShaderMaterial({ uniforms: { tData: { - value: this.renderer.resources.antsDataRenderTarget0 - .texture, + value: this.renderer.resources.antsComputeTarget0 + .textures[0], }, tAnt: { value: antTexture }, tFood: { value: foodTexture }, @@ -182,8 +182,8 @@ export default class ScreenScene extends AbstractScene { const ants = new THREE.InstancedMesh( new THREE.PlaneGeometry(scale, scale), this.material, - this.renderer.resources.antsDataRenderTarget0.width * - this.renderer.resources.antsDataRenderTarget0.height, + this.renderer.resources.antsComputeTarget0.width * + this.renderer.resources.antsComputeTarget0.height, ); ants.position.x = ants.position.y = -0.5; diff --git a/src/shaders/antsCompute.frag b/src/shaders/antsCompute.frag index 2e22071..8635892 100644 --- a/src/shaders/antsCompute.frag +++ b/src/shaders/antsCompute.frag @@ -5,10 +5,12 @@ precision highp int; in vec2 vUv; -out vec4 FragColor; +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.; @@ -73,6 +75,7 @@ float getMaxScentStorage(vec2 antDataUv) { void main() { vec4 lastState = texture(tLastState, vUv); + vec4 lastExtState = texture(tLastExtState, vUv); float noise = rand(vUv * 1000. + fract(uTime / 1000.)); @@ -82,6 +85,11 @@ void main() { 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 @@ -89,6 +97,10 @@ void main() { 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.) { @@ -201,4 +213,5 @@ void main() { angle, float((uint(max(storage - SCENT_PER_MARKER, 0.)) << 1) + uint(isCarrying)) ); + FragColorExt = vec4(personality, cargoQuality, pathIntDx, pathIntDy); } \ No newline at end of file diff --git a/src/shaders/antsDiscretize.vert b/src/shaders/antsDiscretize.vert index 90747a9..1d2c14e 100644 --- a/src/shaders/antsDiscretize.vert +++ b/src/shaders/antsDiscretize.vert @@ -11,6 +11,7 @@ out float vIsCellCleared; uniform sampler2D tDataCurrent; uniform sampler2D tDataLast; +uniform sampler2D tDataExtCurrent; const float cellSize = 1. / WORLD_SIZE;