Fix dynamic armor overlay vanishing on re-render

PrimaryArmorSceneComponent rebuilt its ShaderMaterial every render with null uniforms that were only set once on mount. Create it once with useState instead.
This commit is contained in:
Mark Greene committed 2026-10-02 19:24:43 +13:00
1 parent 763ecf22b0
commit 0941c23a3c
1 file changed
+18 -15
@@ -5,7 +5,7 @@ import {
} from "@blitzkit/core";
import { invalidate, useFrame } from "@react-three/fiber";
import type { QuicklimeEvent } from "quicklime";
import { useEffect } from "react";
import { useEffect, useState } from "react";
import {
MeshBasicMaterial,
NormalBlending,
@@ -43,7 +43,9 @@ export function PrimaryArmorSceneComponent({
node,
thickness,
}: PrimaryArmorSceneComponentProps) {
const material = new ShaderMaterial({
const [material] = useState(
() =>
new ShaderMaterial({
fragmentShader,
vertexShader,
@@ -78,7 +80,8 @@ export function PrimaryArmorSceneComponent({
opacity: { value: 0 },
},
]),
});
})
);
useEffect(() => {
function handleShellChange() {
@@ -88,10 +91,10 @@ export function PrimaryArmorSceneComponent({
material.uniforms.caliber.value = shell.caliber;
material.uniforms.ricochet.value = degToRad(
isExplosive(shell.type) ? 90 : shell.ricochet!,
isExplosive(shell.type) ? 90 : shell.ricochet!
);
material.uniforms.normalization.value = degToRad(
shell.normalization ?? 0,
shell.normalization ?? 0
);
material.uniforms.isExplosive.value = isExplosive(shell.type);
material.uniforms.canSplash.value = canSplash(shell.type);
@@ -121,7 +124,7 @@ export function PrimaryArmorSceneComponent({
const hasEnhancedArmor = hasEquipment(
110,
Duel.state.protagonist.tank.equipment_preset,
equipment,
equipment
);
const equalizer =
(Duel.state.equalize
@@ -142,7 +145,7 @@ export function PrimaryArmorSceneComponent({
const hasCalibratedShells = hasEquipment(
103,
Duel.state.antagonist.tank.equipment_preset,
equipment,
equipment
);
material.uniforms.penetration.value =
@@ -151,7 +154,7 @@ export function PrimaryArmorSceneComponent({
hasCalibratedShells,
Duel.state.equalize,
shell.type,
Duel.state.antagonist.tank.equalizer,
Duel.state.antagonist.tank.equalizer
);
if (!noInvalidate) invalidate();
@@ -164,7 +167,7 @@ export function PrimaryArmorSceneComponent({
handleShellChange();
handleGreenPenetrationChange(TankopediaPersistent.state.greenPenetration);
handleAdvancedHighlightingChange(
TankopediaPersistent.state.advancedHighlighting,
TankopediaPersistent.state.advancedHighlighting
);
handleOpaqueChange(TankopediaPersistent.state.opaque);
handleWireframeChange(TankopediaPersistent.state.wireframe);
@@ -178,27 +181,27 @@ export function PrimaryArmorSceneComponent({
Tankopedia.on((state) => state.customShell, handleShellChange),
TankopediaPersistent.on(
(state) => state.greenPenetration,
handleGreenPenetrationChange,
handleGreenPenetrationChange
),
TankopediaPersistent.on(
(state) => state.advancedHighlighting,
handleAdvancedHighlightingChange,
handleAdvancedHighlightingChange
),
TankopediaPersistent.on((state) => state.opaque, handleOpaqueChange),
Duel.on(
(state) => state.protagonist.equipmentMatrix,
() => handleProtagonistEquipmentChange(),
() => handleProtagonistEquipmentChange()
),
Duel.on(
(state) => state.antagonist.equipmentMatrix,
() => handleAntagonistEquipmentChange(),
() => handleAntagonistEquipmentChange()
),
Duel.on(
(state) => state.equalize,
() => {
handleProtagonistEquipmentChange();
handleAntagonistEquipmentChange();
},
}
),
() => transitionEvent.off(handleTransitionEvent),
];
@@ -210,7 +213,7 @@ export function PrimaryArmorSceneComponent({
useFrame(({ gl, camera }) => {
gl.getSize(material.uniforms.resolution.value).multiplyScalar(
gl.getPixelRatio(),
gl.getPixelRatio()
);
material.uniforms.spacedArmorBuffer.value = spacedArmorRenderTarget.texture;
material.uniforms.spacedArmorDepth.value =