Add second ant texture with MRT for extended ant state

This commit is contained in:
Jared Miller 2026-03-09 10:45:26 -04:00
parent 221606b527
commit cff99b7f08
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C
6 changed files with 59 additions and 41 deletions

View file

@ -7,8 +7,8 @@ interface Resources {
worldRenderTarget: THREE.WebGLRenderTarget; worldRenderTarget: THREE.WebGLRenderTarget;
worldRenderTargetCopy: THREE.WebGLRenderTarget; worldRenderTargetCopy: THREE.WebGLRenderTarget;
worldBlurredRenderTarget: THREE.WebGLRenderTarget; worldBlurredRenderTarget: THREE.WebGLRenderTarget;
antsDataRenderTarget0: THREE.WebGLRenderTarget; antsComputeTarget0: THREE.WebGLRenderTarget;
antsDataRenderTarget1: THREE.WebGLRenderTarget; antsComputeTarget1: THREE.WebGLRenderTarget;
antsDiscreteRenderTarget: THREE.WebGLRenderTarget; antsDiscreteRenderTarget: THREE.WebGLRenderTarget;
} }
@ -59,28 +59,8 @@ export default class Renderer {
minFilter: THREE.NearestFilter, minFilter: THREE.NearestFilter,
}, },
), ),
antsDataRenderTarget0: new THREE.WebGLRenderTarget( antsComputeTarget0: Renderer.makeAntsMRT(antTextureSize),
antTextureSize, antsComputeTarget1: Renderer.makeAntsMRT(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,
},
),
antsDiscreteRenderTarget: new THREE.WebGLRenderTarget( antsDiscreteRenderTarget: new THREE.WebGLRenderTarget(
Config.worldSize, Config.worldSize,
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) { public renderSimulation(scenes: SceneCollection) {
const [antsComputeSource, antsComputeTarget] = const [antsComputeSource, antsComputeTarget] =
scenes.ants.getRenderTargets(); scenes.ants.getRenderTargets();
@ -108,7 +105,9 @@ export default class Renderer {
this.setViewportFromRT(antsComputeTarget); this.setViewportFromRT(antsComputeTarget);
this.renderer.setRenderTarget(antsComputeTarget); this.renderer.setRenderTarget(antsComputeTarget);
scenes.ants.material.uniforms.tLastState.value = 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 = scenes.ants.material.uniforms.tWorld.value =
this.resources.worldBlurredRenderTarget.texture; this.resources.worldBlurredRenderTarget.texture;
this.renderer.render(scenes.ants, scenes.ants.camera); this.renderer.render(scenes.ants, scenes.ants.camera);
@ -116,9 +115,11 @@ export default class Renderer {
this.setViewportFromRT(this.resources.antsDiscreteRenderTarget); this.setViewportFromRT(this.resources.antsDiscreteRenderTarget);
this.renderer.setRenderTarget(this.resources.antsDiscreteRenderTarget); this.renderer.setRenderTarget(this.resources.antsDiscreteRenderTarget);
scenes.discretize.material.uniforms.tDataCurrent.value = scenes.discretize.material.uniforms.tDataCurrent.value =
antsComputeTarget.texture; antsComputeTarget.textures[0];
scenes.discretize.material.uniforms.tDataLast.value = 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.renderer.render(scenes.discretize, scenes.discretize.camera);
this.setViewportFromRT(this.resources.worldRenderTarget); this.setViewportFromRT(this.resources.worldRenderTarget);
@ -129,7 +130,8 @@ export default class Renderer {
this.resources.antsDiscreteRenderTarget.texture; this.resources.antsDiscreteRenderTarget.texture;
this.renderer.render(scenes.world, scenes.world.camera); 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 = scenes.screen.groundMaterial.uniforms.map.value =
this.resources.worldRenderTargetCopy.texture; this.resources.worldRenderTargetCopy.texture;
} }
@ -220,18 +222,18 @@ export default class Renderer {
this.renderer.setRenderTarget(this.resources.worldBlurredRenderTarget); this.renderer.setRenderTarget(this.resources.worldBlurredRenderTarget);
this.renderer.clear(); this.renderer.clear();
this.resources.antsDataRenderTarget0.setSize( this.resources.antsComputeTarget0.setSize(
antTextureSize, antTextureSize,
antTextureSize, antTextureSize,
); );
this.renderer.setRenderTarget(this.resources.antsDataRenderTarget0); this.renderer.setRenderTarget(this.resources.antsComputeTarget0);
this.renderer.clear(); this.renderer.clear();
this.resources.antsDataRenderTarget1.setSize( this.resources.antsComputeTarget1.setSize(
antTextureSize, antTextureSize,
antTextureSize, antTextureSize,
); );
this.renderer.setRenderTarget(this.resources.antsDataRenderTarget1); this.renderer.setRenderTarget(this.resources.antsComputeTarget1);
this.renderer.clear(); this.renderer.clear();
this.resources.antsDiscreteRenderTarget.setSize( this.resources.antsDiscreteRenderTarget.setSize(

View file

@ -19,6 +19,7 @@ export default class AntsComputeScene extends AbstractScene {
uniforms: { uniforms: {
uTime: { value: 0 }, uTime: { value: 0 },
tLastState: { value: null }, tLastState: { value: null },
tLastExtState: { value: null },
tWorld: { value: null }, tWorld: { value: null },
}, },
vertexShader, vertexShader,
@ -32,8 +33,8 @@ export default class AntsComputeScene extends AbstractScene {
this.material = material; this.material = material;
this.renderTargets = [ this.renderTargets = [
this.renderer.resources.antsDataRenderTarget0, this.renderer.resources.antsComputeTarget0,
this.renderer.resources.antsDataRenderTarget1, this.renderer.resources.antsComputeTarget1,
]; ];
} }

View file

@ -17,6 +17,7 @@ export default class AntsDiscretizeScene extends AbstractScene {
uniforms: { uniforms: {
tDataCurrent: { value: null }, tDataCurrent: { value: null },
tDataLast: { value: null }, tDataLast: { value: null },
tDataExtCurrent: { value: null },
}, },
vertexShader, vertexShader,
fragmentShader, fragmentShader,
@ -36,8 +37,8 @@ export default class AntsDiscretizeScene extends AbstractScene {
this.mesh = new THREE.InstancedMesh( this.mesh = new THREE.InstancedMesh(
new THREE.BoxGeometry(1, 1, 1), new THREE.BoxGeometry(1, 1, 1),
this.material, this.material,
this.renderer.resources.antsDataRenderTarget0.width * this.renderer.resources.antsComputeTarget0.width *
this.renderer.resources.antsDataRenderTarget0.height, this.renderer.resources.antsComputeTarget0.height,
); );
this.add(this.mesh); this.add(this.mesh);
} }

View file

@ -60,8 +60,8 @@ export default class ScreenScene extends AbstractScene {
this.material = new THREE.ShaderMaterial({ this.material = new THREE.ShaderMaterial({
uniforms: { uniforms: {
tData: { tData: {
value: this.renderer.resources.antsDataRenderTarget0 value: this.renderer.resources.antsComputeTarget0
.texture, .textures[0],
}, },
tAnt: { value: antTexture }, tAnt: { value: antTexture },
tFood: { value: foodTexture }, tFood: { value: foodTexture },
@ -182,8 +182,8 @@ export default class ScreenScene extends AbstractScene {
const ants = new THREE.InstancedMesh( const ants = new THREE.InstancedMesh(
new THREE.PlaneGeometry(scale, scale), new THREE.PlaneGeometry(scale, scale),
this.material, this.material,
this.renderer.resources.antsDataRenderTarget0.width * this.renderer.resources.antsComputeTarget0.width *
this.renderer.resources.antsDataRenderTarget0.height, this.renderer.resources.antsComputeTarget0.height,
); );
ants.position.x = ants.position.y = -0.5; ants.position.x = ants.position.y = -0.5;

View file

@ -5,10 +5,12 @@ precision highp int;
in vec2 vUv; in vec2 vUv;
out vec4 FragColor; layout(location = 0) out vec4 FragColor;
layout(location = 1) out vec4 FragColorExt;
uniform float uTime; uniform float uTime;
uniform sampler2D tLastState; uniform sampler2D tLastState;
uniform sampler2D tLastExtState;
uniform sampler2D tWorld; uniform sampler2D tWorld;
const float sampleDistance = 20.; const float sampleDistance = 20.;
@ -73,6 +75,7 @@ float getMaxScentStorage(vec2 antDataUv) {
void main() { void main() {
vec4 lastState = texture(tLastState, vUv); vec4 lastState = texture(tLastState, vUv);
vec4 lastExtState = texture(tLastExtState, vUv);
float noise = rand(vUv * 1000. + fract(uTime / 1000.)); float noise = rand(vUv * 1000. + fract(uTime / 1000.));
@ -82,6 +85,11 @@ void main() {
float storage = float(int(lastState.w) >> 1); float storage = float(int(lastState.w) >> 1);
bool wasObstacle = isObstacle(pos); bool wasObstacle = isObstacle(pos);
float personality = lastExtState.r;
float cargoQuality = lastExtState.g;
float pathIntDx = lastExtState.b;
float pathIntDy = lastExtState.a;
bool movementProcessed = false; bool movementProcessed = false;
if (pos == vec2(0)) { // init new ant if (pos == vec2(0)) { // init new ant
@ -89,6 +97,10 @@ void main() {
angle = rand(vUv * 10000.) * 2. * PI; angle = rand(vUv * 10000.) * 2. * PI;
isCarrying = 0.; isCarrying = 0.;
storage = 0.; storage = 0.;
personality = rand(vUv * 42069.); // 0.0 = pure follower, 1.0 = pure explorer
cargoQuality = 0.;
pathIntDx = 0.;
pathIntDy = 0.;
} }
if (isCarrying == 0.) { if (isCarrying == 0.) {
@ -201,4 +213,5 @@ void main() {
angle, angle,
float((uint(max(storage - SCENT_PER_MARKER, 0.)) << 1) + uint(isCarrying)) float((uint(max(storage - SCENT_PER_MARKER, 0.)) << 1) + uint(isCarrying))
); );
FragColorExt = vec4(personality, cargoQuality, pathIntDx, pathIntDy);
} }

View file

@ -11,6 +11,7 @@ out float vIsCellCleared;
uniform sampler2D tDataCurrent; uniform sampler2D tDataCurrent;
uniform sampler2D tDataLast; uniform sampler2D tDataLast;
uniform sampler2D tDataExtCurrent;
const float cellSize = 1. / WORLD_SIZE; const float cellSize = 1. / WORLD_SIZE;