diff --git a/packages/website/src/components/Armor/components/PrimaryArmorSceneComponent/index.tsx b/packages/website/src/components/Armor/components/PrimaryArmorSceneComponent/index.tsx index 656d77858..fe4f57145 100644 --- a/packages/website/src/components/Armor/components/PrimaryArmorSceneComponent/index.tsx +++ b/packages/website/src/components/Armor/components/PrimaryArmorSceneComponent/index.tsx @@ -5,7 +5,7 @@ import { } from "@blitzkit/core"; import { invalidate, useFrame } from "@react-three/fiber"; import type { QuicklimeEvent } from "quicklime"; -import { useEffect, useState } from "react"; +import { useEffect, useRef } from "react"; import { MeshBasicMaterial, NormalBlending, @@ -43,44 +43,43 @@ export function PrimaryArmorSceneComponent({ node, thickness, }: PrimaryArmorSceneComponentProps) { - const [material] = useState( - () => - new ShaderMaterial({ - fragmentShader, - vertexShader, + const material = useRef( + new ShaderMaterial({ + fragmentShader, + vertexShader, - fog: true, - transparent: true, + fog: true, + transparent: true, - blending: isHalloween ? SubtractiveBlending : NormalBlending, + blending: isHalloween ? SubtractiveBlending : NormalBlending, - uniforms: UniformsUtils.merge([ - UniformsLib.common, - UniformsLib.fog, + uniforms: UniformsUtils.merge([ + UniformsLib.common, + UniformsLib.fog, - { - thickness: { value: null }, - penetration: { value: null }, - caliber: { value: null }, - ricochet: { value: null }, - normalization: { value: null }, - isExplosive: { value: null }, - canSplash: { value: null }, - damage: { value: null }, - explosionRadius: { value: null }, - greenPenetration: { value: null }, - advancedHighlighting: { value: null }, - opaque: { value: null }, + { + thickness: { value: null }, + penetration: { value: null }, + caliber: { value: null }, + ricochet: { value: null }, + normalization: { value: null }, + isExplosive: { value: null }, + canSplash: { value: null }, + damage: { value: null }, + explosionRadius: { value: null }, + greenPenetration: { value: null }, + advancedHighlighting: { value: null }, + opaque: { value: null }, - inverseProjectionMatrix: { value: null }, - resolution: { value: new Vector2() }, - spacedArmorBuffer: { value: null }, - spacedArmorDepth: { value: null }, + inverseProjectionMatrix: { value: null }, + resolution: { value: new Vector2() }, + spacedArmorBuffer: { value: null }, + spacedArmorDepth: { value: null }, - opacity: { value: 0 }, - }, - ]), - }) + opacity: { value: 0 }, + }, + ]), + }), ); useEffect(() => { @@ -89,17 +88,17 @@ export function PrimaryArmorSceneComponent({ const shell = tankopediaEphemeral.customShell ?? Duel.state.antagonist.shell; - material.uniforms.caliber.value = shell.caliber; - material.uniforms.ricochet.value = degToRad( - isExplosive(shell.type) ? 90 : shell.ricochet! + material.current.uniforms.caliber.value = shell.caliber; + material.current.uniforms.ricochet.value = degToRad( + isExplosive(shell.type) ? 90 : shell.ricochet!, ); - material.uniforms.normalization.value = degToRad( - shell.normalization ?? 0 + material.current.uniforms.normalization.value = degToRad( + shell.normalization ?? 0, ); - material.uniforms.isExplosive.value = isExplosive(shell.type); - material.uniforms.canSplash.value = canSplash(shell.type); - material.uniforms.damage.value = shell.armor_damage; - material.uniforms.explosionRadius.value = shell.explosion_radius; + material.current.uniforms.isExplosive.value = isExplosive(shell.type); + material.current.uniforms.canSplash.value = canSplash(shell.type); + material.current.uniforms.damage.value = shell.armor_damage; + material.current.uniforms.explosionRadius.value = shell.explosion_radius; handleProtagonistEquipmentChange(true); handleAntagonistEquipmentChange(true); @@ -107,31 +106,32 @@ export function PrimaryArmorSceneComponent({ invalidate(); } function handleGreenPenetrationChange(greenPenetration: boolean) { - material.uniforms.greenPenetration.value = greenPenetration; + material.current.uniforms.greenPenetration.value = greenPenetration; } function handleAdvancedHighlightingChange(advancedHighlighting: boolean) { - material.uniforms.advancedHighlighting.value = advancedHighlighting; + material.current.uniforms.advancedHighlighting.value = + advancedHighlighting; invalidate(); } function handleOpaqueChange(opaque: boolean) { - material.uniforms.opaque.value = opaque; + material.current.uniforms.opaque.value = opaque; } function handleWireframeChange(wireframe: boolean) { - material.wireframe = wireframe; + material.current.wireframe = wireframe; } function handleProtagonistEquipmentChange(noInvalidate = false) { const equipment = Duel.state.protagonist.equipmentMatrix; const hasEnhancedArmor = hasEquipment( 110, Duel.state.protagonist.tank.equipment_preset, - equipment + equipment, ); const equalizer = (Duel.state.equalize ? Duel.state.protagonist.tank.equalizer?.armor : undefined) ?? 1; - material.uniforms.thickness.value = + material.current.uniforms.thickness.value = thickness * (hasEnhancedArmor ? 1.04 : 1) * equalizer; if (!noInvalidate) invalidate(); @@ -145,29 +145,29 @@ export function PrimaryArmorSceneComponent({ const hasCalibratedShells = hasEquipment( 103, Duel.state.antagonist.tank.equipment_preset, - equipment + equipment, ); - material.uniforms.penetration.value = + material.current.uniforms.penetration.value = penetration * resolvePenetrationCoefficient( hasCalibratedShells, Duel.state.equalize, shell.type, - Duel.state.antagonist.tank.equalizer + Duel.state.antagonist.tank.equalizer, ); if (!noInvalidate) invalidate(); } function handleTransitionEvent(event: QuicklimeEvent) { - material.uniforms.opacity.value = event.data; + material.current.uniforms.opacity.value = event.data; } handleShellChange(); handleGreenPenetrationChange(TankopediaPersistent.state.greenPenetration); handleAdvancedHighlightingChange( - TankopediaPersistent.state.advancedHighlighting + TankopediaPersistent.state.advancedHighlighting, ); handleOpaqueChange(TankopediaPersistent.state.opaque); handleWireframeChange(TankopediaPersistent.state.wireframe); @@ -181,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), ]; @@ -212,13 +212,14 @@ export function PrimaryArmorSceneComponent({ }, []); useFrame(({ gl, camera }) => { - gl.getSize(material.uniforms.resolution.value).multiplyScalar( - gl.getPixelRatio() + gl.getSize(material.current.uniforms.resolution.value).multiplyScalar( + gl.getPixelRatio(), ); - material.uniforms.spacedArmorBuffer.value = spacedArmorRenderTarget.texture; - material.uniforms.spacedArmorDepth.value = + material.current.uniforms.spacedArmorBuffer.value = + spacedArmorRenderTarget.texture; + material.current.uniforms.spacedArmorDepth.value = spacedArmorRenderTarget.depthTexture; - material.uniforms.inverseProjectionMatrix.value = + material.current.uniforms.inverseProjectionMatrix.value = camera.projectionMatrixInverse; }); @@ -243,7 +244,7 @@ export function PrimaryArmorSceneComponent({ {...props} key={`${key}-include`} renderOrder={1} - material={material} + material={material.current} /> ); },