Resize FBs and recompile materials after config change
This commit is contained in:
parent
a2b5d45a52
commit
9e80ac2c96
13 changed files with 120 additions and 72 deletions
|
|
@ -53,7 +53,7 @@ export default new class App {
|
|||
}
|
||||
|
||||
private resetRenderer() {
|
||||
this.renderer.reset();
|
||||
this.renderer.reset(this.scenes);
|
||||
}
|
||||
|
||||
private updateSimulationInterval() {
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ export default {
|
|||
antsCount: 64 ** 2,
|
||||
simulationStepsPerSecond: 60,
|
||||
scentThreshold: 0.01,
|
||||
scentFadeOutFactor: 0.999,
|
||||
scentFadeOutFactor: 0.998,
|
||||
scentBlurRadius: 0.1,
|
||||
scentMaxStorage: 1e6,
|
||||
scentPerMarker: 1000,
|
||||
scentPerMarker: 300,
|
||||
antSpeed: 1,
|
||||
antRotationAngle: Math.PI / 50,
|
||||
brushRadius: 20,
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@ export default class GUI extends EventEmitter {
|
|||
|
||||
const simFolder = this.gui.addFolder('Simulation');
|
||||
|
||||
simFolder.add(Config, 'worldSize', 256, 8096).onChange(() => {
|
||||
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, 300).onChange(() => {
|
||||
simFolder.add(Config, 'simulationStepsPerSecond', 1, 500).onChange(() => {
|
||||
this.emit('simulationStepsPerSecond');
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import * as THREE from 'three';
|
||||
import {SceneCollection} from "./App";
|
||||
import Config from "./Config";
|
||||
import {WebGLRenderTarget} from "three";
|
||||
|
||||
interface Resources {
|
||||
worldRenderTarget: THREE.WebGLRenderTarget;
|
||||
|
|
@ -73,28 +74,24 @@ export default class Renderer {
|
|||
public renderSimulation(scenes: SceneCollection) {
|
||||
const [antsComputeSource, antsComputeTarget] = scenes.ants.getRenderTargets();
|
||||
|
||||
this.renderer.setViewport(0, 0, scenes.worldBlur.renderWidth, scenes.worldBlur.renderHeight);
|
||||
|
||||
this.setViewportFromRT(this.resources.worldBlurredRenderTarget);
|
||||
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.setViewportFromRT(antsComputeTarget);
|
||||
this.renderer.setRenderTarget(antsComputeTarget);
|
||||
scenes.ants.material.uniforms.tLastState.value = antsComputeSource.texture;
|
||||
scenes.ants.material.uniforms.tWorld.value = this.resources.worldBlurredRenderTarget.texture;
|
||||
this.renderer.render(scenes.ants, scenes.ants.camera);
|
||||
|
||||
this.renderer.setViewport(0, 0, scenes.discretize.renderWidth, scenes.discretize.renderHeight);
|
||||
|
||||
this.setViewportFromRT(this.resources.antsDiscreteRenderTarget);
|
||||
this.renderer.setRenderTarget(this.resources.antsDiscreteRenderTarget);
|
||||
scenes.discretize.material.uniforms.tDataCurrent.value = antsComputeTarget.texture;
|
||||
scenes.discretize.material.uniforms.tDataLast.value = antsComputeSource.texture;
|
||||
this.renderer.render(scenes.discretize, scenes.discretize.camera);
|
||||
|
||||
this.renderer.setViewport(0, 0, scenes.world.renderWidth, scenes.world.renderHeight);
|
||||
|
||||
this.setViewportFromRT(this.resources.worldRenderTarget);
|
||||
this.renderer.setRenderTarget(this.resources.worldRenderTarget);
|
||||
scenes.world.material.uniforms.tLastState.value = this.resources.worldBlurredRenderTarget.texture;
|
||||
scenes.world.material.uniforms.tDiscreteAnts.value = this.resources.antsDiscreteRenderTarget.texture;
|
||||
|
|
@ -104,8 +101,12 @@ export default class Renderer {
|
|||
scenes.screen.groundMaterial.uniforms.map.value = this.resources.worldRenderTargetCopy.texture;
|
||||
}
|
||||
|
||||
private setViewportFromRT(rt: WebGLRenderTarget) {
|
||||
this.renderer.setViewport(0, 0, rt.width, rt.height);
|
||||
}
|
||||
|
||||
public renderToScreen(scenes: SceneCollection) {
|
||||
this.renderer.setViewport(0, 0, scenes.draw.renderWidth, scenes.draw.renderHeight);
|
||||
this.setViewportFromRT(this.resources.worldRenderTargetCopy);
|
||||
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;
|
||||
|
|
@ -137,8 +138,36 @@ export default class Renderer {
|
|||
};
|
||||
}
|
||||
|
||||
public reset() {
|
||||
public reset(scenes: SceneCollection) {
|
||||
const antTextureSize = Math.ceil(Math.sqrt(Config.antsCount));
|
||||
|
||||
this.resources.worldRenderTarget.setSize(Config.worldSize, Config.worldSize)
|
||||
this.renderer.setRenderTarget(this.resources.worldRenderTarget);
|
||||
this.renderer.clear();
|
||||
|
||||
this.resources.worldRenderTargetCopy.setSize(Config.worldSize, Config.worldSize)
|
||||
this.renderer.setRenderTarget(this.resources.worldRenderTargetCopy);
|
||||
this.renderer.clear();
|
||||
|
||||
this.resources.worldBlurredRenderTarget.setSize(Config.worldSize, Config.worldSize)
|
||||
this.renderer.setRenderTarget(this.resources.worldBlurredRenderTarget);
|
||||
this.renderer.clear();
|
||||
|
||||
this.resources.antsDataRenderTarget0.setSize(antTextureSize, antTextureSize)
|
||||
this.renderer.setRenderTarget(this.resources.antsDataRenderTarget0);
|
||||
this.renderer.clear();
|
||||
|
||||
this.resources.antsDataRenderTarget1.setSize(antTextureSize, antTextureSize)
|
||||
this.renderer.setRenderTarget(this.resources.antsDataRenderTarget1);
|
||||
this.renderer.clear();
|
||||
|
||||
this.resources.antsDiscreteRenderTarget.setSize(Config.worldSize, Config.worldSize)
|
||||
this.renderer.setRenderTarget(this.resources.antsDiscreteRenderTarget);
|
||||
this.renderer.clear();
|
||||
|
||||
for (const scene of Object.values(scenes)) {
|
||||
scene.recompileMaterials();
|
||||
}
|
||||
}
|
||||
|
||||
static convertNumberToFloatString(n: number): string {
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ import Renderer from "../Renderer";
|
|||
export default abstract class AbstractScene extends THREE.Scene {
|
||||
protected readonly renderer: Renderer;
|
||||
public readonly camera: THREE.Camera;
|
||||
public renderWidth: number = 1;
|
||||
public renderHeight: number = 1;
|
||||
|
||||
protected constructor(renderer: Renderer) {
|
||||
super();
|
||||
|
|
@ -13,6 +11,8 @@ export default abstract class AbstractScene extends THREE.Scene {
|
|||
this.renderer = renderer;
|
||||
}
|
||||
|
||||
public abstract recompileMaterials(): void;
|
||||
|
||||
public abstract resize(width: number, height: number): void;
|
||||
|
||||
public abstract update(deltaTime: number): void;
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ export default class AntsComputeScene extends AbstractScene {
|
|||
const material = new THREE.RawShaderMaterial({
|
||||
uniforms: {
|
||||
uTime: {value: 0},
|
||||
tLastState: {value: this.renderer.resources.antsDataRenderTarget0.texture},
|
||||
tWorld: {value: this.renderer.resources.worldRenderTarget.texture},
|
||||
tLastState: {value: null},
|
||||
tWorld: {value: null},
|
||||
},
|
||||
vertexShader,
|
||||
fragmentShader,
|
||||
|
|
@ -35,9 +35,6 @@ export default class AntsComputeScene extends AbstractScene {
|
|||
this.renderer.resources.antsDataRenderTarget0,
|
||||
this.renderer.resources.antsDataRenderTarget1
|
||||
];
|
||||
|
||||
this.renderWidth = this.renderer.resources.antsDataRenderTarget0.width;
|
||||
this.renderHeight = this.renderer.resources.antsDataRenderTarget0.height;
|
||||
}
|
||||
|
||||
public getRenderTargets(): [WebGLRenderTarget, WebGLRenderTarget] {
|
||||
|
|
@ -46,6 +43,11 @@ export default class AntsComputeScene extends AbstractScene {
|
|||
return this.renderTargets;
|
||||
}
|
||||
|
||||
public recompileMaterials() {
|
||||
this.material.defines = this.renderer.getCommonMaterialDefines();
|
||||
this.material.needsUpdate = true;
|
||||
}
|
||||
|
||||
public resize(width: number, height: number) {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import * as THREE from 'three';
|
||||
import {WebGLRenderTarget} from 'three';
|
||||
import Renderer from "../Renderer";
|
||||
import AbstractScene from "./AbstractScene";
|
||||
import fragmentShader from '../shaders/antsDiscretize.frag';
|
||||
|
|
@ -8,12 +7,12 @@ import vertexShader from '../shaders/antsDiscretize.vert';
|
|||
export default class AntsDiscretizeScene extends AbstractScene {
|
||||
public readonly camera: THREE.OrthographicCamera = new THREE.OrthographicCamera();
|
||||
public readonly material: THREE.RawShaderMaterial;
|
||||
public mesh: THREE.InstancedMesh;
|
||||
|
||||
constructor(renderer: Renderer) {
|
||||
super(renderer);
|
||||
|
||||
const geometry = new THREE.BoxBufferGeometry(1, 1, 1);
|
||||
const material = new THREE.RawShaderMaterial({
|
||||
this.material = new THREE.RawShaderMaterial({
|
||||
uniforms: {
|
||||
tDataCurrent: {value: null},
|
||||
tDataLast: {value: null},
|
||||
|
|
@ -23,21 +22,28 @@ export default class AntsDiscretizeScene extends AbstractScene {
|
|||
defines: this.renderer.getCommonMaterialDefines(),
|
||||
glslVersion: THREE.GLSL3
|
||||
});
|
||||
const mesh = new THREE.InstancedMesh(
|
||||
geometry,
|
||||
material,
|
||||
this.renderer.resources.antsDataRenderTarget0.width * this.renderer.resources.antsDataRenderTarget0.height
|
||||
);
|
||||
this.add(mesh);
|
||||
|
||||
this.material = material;
|
||||
|
||||
this.renderWidth = this.renderer.resources.worldRenderTarget.width;
|
||||
this.renderHeight = this.renderer.resources.worldRenderTarget.height;
|
||||
this.createMesh();
|
||||
}
|
||||
|
||||
public getRenderTarget(): WebGLRenderTarget {
|
||||
return this.renderer.resources.antsDiscreteRenderTarget;
|
||||
private createMesh() {
|
||||
if (this.mesh) {
|
||||
this.remove(this.mesh);
|
||||
this.mesh.dispose();
|
||||
}
|
||||
|
||||
this.mesh = new THREE.InstancedMesh(
|
||||
new THREE.BoxBufferGeometry(1, 1, 1),
|
||||
this.material,
|
||||
this.renderer.resources.antsDataRenderTarget0.width * this.renderer.resources.antsDataRenderTarget0.height
|
||||
);
|
||||
this.add(this.mesh);
|
||||
}
|
||||
|
||||
public recompileMaterials() {
|
||||
this.material.defines = this.renderer.getCommonMaterialDefines();
|
||||
this.material.needsUpdate = true;
|
||||
this.createMesh();
|
||||
}
|
||||
|
||||
public resize(width: number, height: number) {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ 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();
|
||||
|
|
@ -30,13 +29,11 @@ export default class DrawScene extends AbstractScene {
|
|||
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 recompileMaterials() {
|
||||
this.material.defines = this.renderer.getCommonMaterialDefines();
|
||||
this.material.needsUpdate = true;
|
||||
}
|
||||
|
||||
public resize(width: number, height: number) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import vertexShaderAnts from "../shaders/ants.vert";
|
|||
import fragmentShaderAnts from "../shaders/ants.frag";
|
||||
import vertexShaderGround from "../shaders/screenWorld.vert";
|
||||
import fragmentShaderGround from "../shaders/screenWorld.frag";
|
||||
import Config from "../Config";
|
||||
|
||||
enum PointerState {
|
||||
None,
|
||||
|
|
@ -16,11 +17,14 @@ enum PointerState {
|
|||
export default class ScreenScene extends AbstractScene {
|
||||
public readonly camera: THREE.OrthographicCamera;
|
||||
public readonly material: THREE.ShaderMaterial;
|
||||
public ants: THREE.InstancedMesh;
|
||||
public readonly groundMaterial: THREE.ShaderMaterial;
|
||||
public readonly pointerPosition: THREE.Vector2 = new THREE.Vector2();
|
||||
public drawMode: PointerState = PointerState.None;
|
||||
private cameraZoomLinear: number = 0;
|
||||
private isPointerDown: boolean = false;
|
||||
public renderWidth: number = 1;
|
||||
public renderHeight: number = 1;
|
||||
|
||||
constructor(renderer: Renderer) {
|
||||
super(renderer);
|
||||
|
|
@ -40,9 +44,6 @@ export default class ScreenScene extends AbstractScene {
|
|||
|
||||
this.groundMaterial = ground.material;
|
||||
|
||||
//ground.position.x = 0.5;
|
||||
//ground.position.y = 0.5;
|
||||
|
||||
this.add(ground);
|
||||
|
||||
const antTexture = new THREE.TextureLoader().load('textures/ant.png');
|
||||
|
|
@ -62,15 +63,7 @@ export default class ScreenScene extends AbstractScene {
|
|||
transparent: true
|
||||
});
|
||||
|
||||
const ants = new THREE.InstancedMesh(
|
||||
new THREE.PlaneBufferGeometry(0.015, 0.015),
|
||||
this.material,
|
||||
this.renderer.resources.antsDataRenderTarget0.width * this.renderer.resources.antsDataRenderTarget0.height
|
||||
)
|
||||
|
||||
ants.position.x = ants.position.y = -0.5;
|
||||
|
||||
this.add(ants);
|
||||
this.createInstancedAntsMesh();
|
||||
|
||||
this.camera = new THREE.OrthographicCamera(-0.5, 0.5, 0.5, -0.5);
|
||||
|
||||
|
|
@ -164,6 +157,33 @@ export default class ScreenScene extends AbstractScene {
|
|||
this.camera.updateProjectionMatrix();
|
||||
}
|
||||
|
||||
private createInstancedAntsMesh() {
|
||||
if (this.ants) {
|
||||
this.remove(this.ants);
|
||||
this.ants.dispose();
|
||||
}
|
||||
|
||||
const scale = 8 / Config.worldSize;
|
||||
|
||||
const ants = new THREE.InstancedMesh(
|
||||
new THREE.PlaneBufferGeometry(scale, scale),
|
||||
this.material,
|
||||
this.renderer.resources.antsDataRenderTarget0.width * this.renderer.resources.antsDataRenderTarget0.height
|
||||
)
|
||||
|
||||
ants.position.x = ants.position.y = -0.5;
|
||||
|
||||
this.add(ants);
|
||||
|
||||
this.ants = ants;
|
||||
}
|
||||
|
||||
public recompileMaterials() {
|
||||
this.groundMaterial.defines = this.renderer.getCommonMaterialDefines();
|
||||
this.groundMaterial.needsUpdate = true;
|
||||
this.createInstancedAntsMesh();
|
||||
}
|
||||
|
||||
public resize(width: number, height: number) {
|
||||
const aspect = width / height;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import AbstractScene from "./AbstractScene";
|
|||
import FullScreenTriangleGeometry from "../utils/FullScreenTriangleGeometry";
|
||||
import fragmentShader from '../shaders/worldBlur.frag';
|
||||
import vertexShader from '../shaders/worldBlur.vert';
|
||||
import {WebGLRenderTarget} from "three";
|
||||
|
||||
export default class WorldBlurScene extends AbstractScene {
|
||||
public readonly camera: THREE.OrthographicCamera = new THREE.OrthographicCamera();
|
||||
|
|
@ -16,7 +15,7 @@ export default class WorldBlurScene extends AbstractScene {
|
|||
const geometry = new FullScreenTriangleGeometry();
|
||||
const material = new THREE.RawShaderMaterial({
|
||||
uniforms: {
|
||||
tWorld: {value: this.renderer.resources.worldRenderTarget.texture},
|
||||
tWorld: {value: null},
|
||||
},
|
||||
vertexShader,
|
||||
fragmentShader,
|
||||
|
|
@ -27,13 +26,11 @@ export default class WorldBlurScene extends AbstractScene {
|
|||
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.worldBlurredRenderTarget;
|
||||
public recompileMaterials() {
|
||||
this.material.defines = this.renderer.getCommonMaterialDefines();
|
||||
this.material.needsUpdate = true;
|
||||
}
|
||||
|
||||
public resize(width: number, height: number) {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import AbstractScene from "./AbstractScene";
|
|||
import FullScreenTriangleGeometry from "../utils/FullScreenTriangleGeometry";
|
||||
import fragmentShader from '../shaders/world.frag';
|
||||
import vertexShader from '../shaders/world.vert';
|
||||
import {WebGLRenderTarget} from "three";
|
||||
|
||||
export default class WorldComputeScene extends AbstractScene {
|
||||
public readonly camera: THREE.OrthographicCamera = new THREE.OrthographicCamera();
|
||||
|
|
@ -28,13 +27,11 @@ export default class WorldComputeScene extends AbstractScene {
|
|||
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 recompileMaterials() {
|
||||
this.material.defines = this.renderer.getCommonMaterialDefines();
|
||||
this.material.needsUpdate = true;
|
||||
}
|
||||
|
||||
public resize(width: number, height: number) {
|
||||
|
|
|
|||
|
|
@ -34,11 +34,11 @@ void main() {
|
|||
float storage = float(int(dataSampleCurrent.w) >> 1);
|
||||
|
||||
vIsCarryingFood = isCarrying;
|
||||
vScentFactor = storage / 1000000.;
|
||||
vScentFactor = storage / SCENT_MAX_STORAGE;
|
||||
vIsCellCleared = isCellCleared;
|
||||
|
||||
gl_Position = vec4(
|
||||
(position.xy * cellSize * 0.01 + floor(offset * WORLD_SIZE) / WORLD_SIZE + cellSize * 0.5) * 2. - 1.,
|
||||
(position.xy * cellSize + floor(offset * WORLD_SIZE) / WORLD_SIZE + cellSize * 0.5) * 2. - 1.,
|
||||
0,
|
||||
1
|
||||
);
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ void main() {
|
|||
int isFood = cellData & 1;
|
||||
int isHome = (cellData & 2) >> 1;
|
||||
int isObstacle = (cellData & 4) >> 2;
|
||||
float scentToHome = lastState.y + discreteAnts.x * 10.;
|
||||
float scentToFood = lastState.z + discreteAnts.y * 10.;
|
||||
float scentToHome = min(10., lastState.y + discreteAnts.x);
|
||||
float scentToFood = min(10., lastState.z + discreteAnts.y);
|
||||
|
||||
if (discreteAnts.z == 1.) {
|
||||
isFood = 0;
|
||||
|
|
|
|||
Loading…
Reference in a new issue