Resize FBs and recompile materials after config change

This commit is contained in:
vHawk 2022-06-30 00:35:59 +03:00
parent a2b5d45a52
commit 9e80ac2c96
13 changed files with 120 additions and 72 deletions

View file

@ -53,7 +53,7 @@ export default new class App {
}
private resetRenderer() {
this.renderer.reset();
this.renderer.reset(this.scenes);
}
private updateSimulationInterval() {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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