diff --git a/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx b/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx
index 60ce34687..17bbdfae3 100644
--- a/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx
+++ b/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx
@@ -21,6 +21,8 @@ import { SceneProps } from '../SceneProps';
import { ModelLoader } from './components/ModelLoader';
import { Options } from './components/Options';
import { TankArmor } from './components/TankArmor';
+import { ExternalModuleMask } from './components/TankArmor/components/ExternalModuleMask';
+import { SpacedArmorDepth } from './components/TankArmor/components/SpacedArmorDepth';
import { TankModel } from './components/TankModel';
export function TankSandbox() {
@@ -173,6 +175,8 @@ export function TankSandbox() {
+
+
) : (
diff --git a/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor/components/ExternalModuleMask.tsx b/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor/components/ExternalModuleMask.tsx
index a490f7890..fe109f16d 100644
--- a/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor/components/ExternalModuleMask.tsx
+++ b/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor/components/ExternalModuleMask.tsx
@@ -15,6 +15,10 @@ import { useModelDefinitions } from '../../../../../../../../../hooks/useModelDe
import { useDuel } from '../../../../../../../../../stores/duel';
import { useTankopediaTemporary } from '../../../../../../../../../stores/tankopedia';
+interface ExternalModuleMaskProps {
+ ornamental?: boolean;
+}
+
/**
* When rendered, generates a mask and thickness buffer for external modules.
* - R: 1 means external module
@@ -22,15 +26,120 @@ import { useTankopediaTemporary } from '../../../../../../../../../stores/tankop
* - B: no data
* - A: 1 means is armor; 0 is background
*/
-export const ExternalModuleMask = memo(() => {
- const protagonist = useDuel((state) => state.protagonist!);
- const wrapper = useRef(null);
- const modelDefinitions = useModelDefinitions();
- const turretContainer = useRef(null);
- const gunContainer = useRef(null);
- const initialTankopediaState = useTankopediaTemporary.getState();
+export const ExternalModuleMask = memo(
+ ({ ornamental = false }) => {
+ const protagonist = useDuel((state) => state.protagonist!);
+ const wrapper = useRef(null);
+ const modelDefinitions = useModelDefinitions();
+ const turretContainer = useRef(null);
+ const gunContainer = useRef(null);
+ const initialTankopediaState = useTankopediaTemporary.getState();
- useEffect(() => {
+ useEffect(() => {
+ const hullOrigin = new Vector3(
+ tankModelDefinition.hullOrigin[0],
+ tankModelDefinition.hullOrigin[1],
+ -tankModelDefinition.hullOrigin[2],
+ ).applyAxisAngle(I_HAT, Math.PI / 2);
+ const turretOrigin = new Vector3(
+ tankModelDefinition.turretOrigin[0],
+ tankModelDefinition.turretOrigin[1],
+ -tankModelDefinition.turretOrigin[2],
+ ).applyAxisAngle(I_HAT, Math.PI / 2);
+ const gunOrigin = new Vector3(
+ turretModelDefinition.gunOrigin[0],
+ turretModelDefinition.gunOrigin[1],
+ -turretModelDefinition.gunOrigin[2],
+ ).applyAxisAngle(I_HAT, Math.PI / 2);
+ const turretPosition = new Vector3();
+ const turretRotation = new Euler();
+ const gunPosition = new Vector3();
+ const gunRotation = new Euler();
+
+ function handleModelTransform({ yaw, pitch }: ModelTransformEventData) {
+ gunPosition
+ .set(0, 0, 0)
+ .sub(hullOrigin)
+ .sub(turretOrigin)
+ .sub(gunOrigin)
+ .applyAxisAngle(I_HAT, pitch)
+ .add(gunOrigin)
+ .add(turretOrigin)
+ .add(hullOrigin);
+ gunRotation.set(pitch, 0, 0);
+ gunContainer.current?.position.copy(gunPosition);
+ gunContainer.current?.rotation.copy(gunRotation);
+
+ if (yaw === undefined) return;
+
+ turretPosition
+ .set(0, 0, 0)
+ .sub(turretOrigin)
+ .sub(hullOrigin)
+ .applyAxisAngle(new Vector3(0, 0, 1), yaw);
+ turretRotation.set(0, 0, yaw);
+
+ if (tankModelDefinition.turretRotation) {
+ const initialPitch = -degToRad(
+ tankModelDefinition.turretRotation.pitch,
+ );
+ const initialYaw = -degToRad(tankModelDefinition.turretRotation.yaw);
+ const initialRoll = -degToRad(
+ tankModelDefinition.turretRotation.roll,
+ );
+
+ turretPosition
+ .applyAxisAngle(I_HAT, initialPitch)
+ .applyAxisAngle(J_HAT, initialRoll)
+ .applyAxisAngle(K_HAT, initialYaw);
+ turretRotation.x += initialPitch;
+ turretRotation.y += initialRoll;
+ turretRotation.z += initialYaw;
+ }
+
+ turretPosition.add(turretOrigin).add(hullOrigin);
+ turretContainer.current?.position.copy(turretPosition);
+ turretContainer.current?.rotation.copy(turretRotation);
+ }
+
+ handleModelTransform(useTankopediaTemporary.getState().model.pose);
+ modelTransformEvent.on(handleModelTransform);
+
+ return () => {
+ modelTransformEvent.off(handleModelTransform);
+ };
+ });
+
+ useEffect(() => {
+ const unsubscribe = useTankopediaTemporary.subscribe(
+ (state) => state.mode,
+ (mode) => {
+ if (wrapper.current) wrapper.current.visible = mode === 'armor';
+ },
+ );
+
+ return unsubscribe;
+ });
+
+ const armorGltf = useArmor(protagonist.tank.id);
+ const { gltf: modelGltf } = useModel(protagonist.tank.id);
+
+ const armorNodes = Object.values(armorGltf.nodes);
+ const modelNodes = Object.values(modelGltf.nodes);
+ const tankModelDefinition = modelDefinitions[protagonist.tank.id];
+ const turretModelDefinition =
+ tankModelDefinition.turrets[protagonist.turret.id];
+ const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id];
+ const maxThickness = Math.max(
+ tankModelDefinition.trackThickness,
+ gunModelDefinition.barrelThickness,
+ ...armorNodes
+ .map((node) => {
+ const armorId = nameToArmorId(node.name);
+ return resolveArmor(tankModelDefinition.armor, armorId).thickness;
+ })
+ .filter(Boolean),
+ );
const hullOrigin = new Vector3(
tankModelDefinition.hullOrigin[0],
tankModelDefinition.hullOrigin[1],
@@ -46,223 +155,127 @@ export const ExternalModuleMask = memo(() => {
turretModelDefinition.gunOrigin[1],
-turretModelDefinition.gunOrigin[2],
).applyAxisAngle(I_HAT, Math.PI / 2);
- const turretPosition = new Vector3();
- const turretRotation = new Euler();
- const gunPosition = new Vector3();
- const gunRotation = new Euler();
- function handleModelTransform({ yaw, pitch }: ModelTransformEventData) {
- gunPosition
- .set(0, 0, 0)
- .sub(hullOrigin)
- .sub(turretOrigin)
- .sub(gunOrigin)
- .applyAxisAngle(I_HAT, pitch)
- .add(gunOrigin)
- .add(turretOrigin)
- .add(hullOrigin);
- gunRotation.set(pitch, 0, 0);
- gunContainer.current?.position.copy(gunPosition);
- gunContainer.current?.rotation.copy(gunRotation);
+ return (
+
+
+ {armorNodes.map((node) => {
+ const isHull = node.name.startsWith('hull_');
+ const isVisible = isHull;
+ const armorId = nameToArmorId(node.name);
+ const { thickness, spaced } = resolveArmor(
+ tankModelDefinition.armor,
+ armorId,
+ );
- if (yaw === undefined) return;
+ if (!isVisible || thickness === undefined || spaced) return null;
- turretPosition
- .set(0, 0, 0)
- .sub(turretOrigin)
- .sub(hullOrigin)
- .applyAxisAngle(new Vector3(0, 0, 1), yaw);
- turretRotation.set(0, 0, yaw);
+ return (
+
+ );
+ })}
+
- if (tankModelDefinition.turretRotation) {
- const initialPitch = -degToRad(
- tankModelDefinition.turretRotation.pitch,
- );
- const initialYaw = -degToRad(tankModelDefinition.turretRotation.yaw);
- const initialRoll = -degToRad(tankModelDefinition.turretRotation.roll);
+ {modelNodes.map((node) => {
+ const isWheel = node.name.startsWith('chassis_wheel_');
+ const isTrack = node.name.startsWith('chassis_track_');
+ const isVisible = isWheel || isTrack;
- turretPosition
- .applyAxisAngle(I_HAT, initialPitch)
- .applyAxisAngle(J_HAT, initialRoll)
- .applyAxisAngle(K_HAT, initialYaw);
- turretRotation.x += initialPitch;
- turretRotation.y += initialRoll;
- turretRotation.z += initialYaw;
- }
-
- turretPosition.add(turretOrigin).add(hullOrigin);
- turretContainer.current?.position.copy(turretPosition);
- turretContainer.current?.rotation.copy(turretRotation);
- }
-
- handleModelTransform(useTankopediaTemporary.getState().model.pose);
- modelTransformEvent.on(handleModelTransform);
-
- return () => {
- modelTransformEvent.off(handleModelTransform);
- };
- });
-
- useEffect(() => {
- const unsubscribe = useTankopediaTemporary.subscribe(
- (state) => state.mode,
- (mode) => {
- if (wrapper.current) wrapper.current.visible = mode === 'armor';
- },
- );
-
- return unsubscribe;
- });
-
- const armorGltf = useArmor(protagonist.tank.id);
- const { gltf: modelGltf } = useModel(protagonist.tank.id);
-
- const armorNodes = Object.values(armorGltf.nodes);
- const modelNodes = Object.values(modelGltf.nodes);
- const tankModelDefinition = modelDefinitions[protagonist.tank.id];
- const turretModelDefinition =
- tankModelDefinition.turrets[protagonist.turret.id];
- const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id];
- const maxThickness = Math.max(
- tankModelDefinition.trackThickness,
- gunModelDefinition.barrelThickness,
- ...armorNodes
- .map((node) => {
- const armorId = nameToArmorId(node.name);
- return resolveArmor(tankModelDefinition.armor, armorId).thickness;
- })
- .filter(Boolean),
- );
- const hullOrigin = new Vector3(
- tankModelDefinition.hullOrigin[0],
- tankModelDefinition.hullOrigin[1],
- -tankModelDefinition.hullOrigin[2],
- ).applyAxisAngle(I_HAT, Math.PI / 2);
- const turretOrigin = new Vector3(
- tankModelDefinition.turretOrigin[0],
- tankModelDefinition.turretOrigin[1],
- -tankModelDefinition.turretOrigin[2],
- ).applyAxisAngle(I_HAT, Math.PI / 2);
- const gunOrigin = new Vector3(
- turretModelDefinition.gunOrigin[0],
- turretModelDefinition.gunOrigin[1],
- -turretModelDefinition.gunOrigin[2],
- ).applyAxisAngle(I_HAT, Math.PI / 2);
-
- return (
-
-
- {armorNodes.map((node) => {
- const isHull = node.name.startsWith('hull_');
- const isVisible = isHull;
- const armorId = nameToArmorId(node.name);
- const { thickness, spaced } = resolveArmor(
- tankModelDefinition.armor,
- armorId,
- );
-
- if (!isVisible || thickness === undefined || spaced) return null;
+ if (!isVisible) return null;
return (
);
})}
-
- {modelNodes.map((node) => {
- const isWheel = node.name.startsWith('chassis_wheel_');
- const isTrack = node.name.startsWith('chassis_track_');
- const isVisible = isWheel || isTrack;
+
+
+ {armorNodes.map((node) => {
+ const isCurrentTurret = node.name.startsWith(
+ `turret_${turretModelDefinition.model.toString().padStart(2, '0')}`,
+ );
+ const isVisible = isCurrentTurret;
+ const armorId = nameToArmorId(node.name);
+ const { thickness, spaced } = resolveArmor(
+ turretModelDefinition.armor,
+ armorId,
+ );
- if (!isVisible) return null;
+ if (!isVisible || thickness === undefined || spaced) return null;
- return (
-
- );
- })}
+ return (
+
+ );
+ })}
+
-
-
- {armorNodes.map((node) => {
- const isCurrentTurret = node.name.startsWith(
- `turret_${turretModelDefinition.model.toString().padStart(2, '0')}`,
- );
- const isVisible = isCurrentTurret;
- const armorId = nameToArmorId(node.name);
- const { thickness, spaced } = resolveArmor(
- turretModelDefinition.armor,
- armorId,
- );
+
+ {armorNodes.map((node) => {
+ const isCurrentGun = node.name.startsWith(
+ `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`,
+ );
+ const isVisible = isCurrentGun;
+ const armorId = nameToArmorId(node.name);
+ const { thickness, spaced } = resolveArmor(
+ gunModelDefinition.armor,
+ armorId,
+ );
- if (!isVisible || thickness === undefined || spaced) return null;
+ if (!isVisible || thickness === undefined || spaced) return null;
- return (
-
- );
- })}
-
+ return (
+
+ );
+ })}
-
- {armorNodes.map((node) => {
- const isCurrentGun = node.name.startsWith(
- `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`,
- );
- const isVisible = isCurrentGun;
- const armorId = nameToArmorId(node.name);
- const { thickness, spaced } = resolveArmor(
- gunModelDefinition.armor,
- armorId,
- );
+ {modelNodes.map((node) => {
+ const isCurrentGun =
+ node.name ===
+ `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`;
+ const isVisible = isCurrentGun;
- if (!isVisible || thickness === undefined || spaced) return null;
+ if (!isVisible) return null;
- return (
-
- );
- })}
-
- {modelNodes.map((node) => {
- const isCurrentGun =
- node.name ===
- `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`;
- const isVisible = isCurrentGun;
-
- if (!isVisible) return null;
-
- return (
-
- );
- })}
+ return (
+
+ );
+ })}
+
-
- );
-});
+ );
+ },
+);
diff --git a/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor/components/SpacedArmorDepth.tsx b/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor/components/SpacedArmorDepth.tsx
index d074452a0..12a06171b 100644
--- a/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor/components/SpacedArmorDepth.tsx
+++ b/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor/components/SpacedArmorDepth.tsx
@@ -15,6 +15,10 @@ import { useModelDefinitions } from '../../../../../../../../../hooks/useModelDe
import { useDuel } from '../../../../../../../../../stores/duel';
import { useTankopediaTemporary } from '../../../../../../../../../stores/tankopedia';
+interface SpacedArmorDepthProps {
+ ornamental?: boolean;
+}
+
/**
* When rendered, this component provides the depth buffer for the armor which
* when compared to the depth of the core armor will give you the distance
@@ -26,17 +30,122 @@ import { useTankopediaTemporary } from '../../../../../../../../../stores/tankop
* - B: no data
* - A: 1 means is armor; 0 is background
*/
-export const SpacedArmorDepth = memo(() => {
- const protagonist = useDuel((state) => state.protagonist!);
- const wrapper = useRef(null);
- const modelDefinitions = useModelDefinitions();
- const turretContainer = useRef(null);
- const gunContainer = useRef(null);
- const initialTankopediaState = useTankopediaTemporary.getState();
+export const SpacedArmorDepth = memo(
+ ({ ornamental = false }) => {
+ const protagonist = useDuel((state) => state.protagonist!);
+ const wrapper = useRef(null);
+ const modelDefinitions = useModelDefinitions();
+ const turretContainer = useRef(null);
+ const gunContainer = useRef(null);
+ const initialTankopediaState = useTankopediaTemporary.getState();
- useEffect(() => {
- if (!modelDefinitions) return;
+ useEffect(() => {
+ if (!modelDefinitions) return;
+ const hullOrigin = new Vector3(
+ tankModelDefinition.hullOrigin[0],
+ tankModelDefinition.hullOrigin[1],
+ -tankModelDefinition.hullOrigin[2],
+ ).applyAxisAngle(I_HAT, Math.PI / 2);
+ const turretOrigin = new Vector3(
+ tankModelDefinition.turretOrigin[0],
+ tankModelDefinition.turretOrigin[1],
+ -tankModelDefinition.turretOrigin[2],
+ ).applyAxisAngle(I_HAT, Math.PI / 2);
+ const gunOrigin = new Vector3(
+ turretModelDefinition.gunOrigin[0],
+ turretModelDefinition.gunOrigin[1],
+ -turretModelDefinition.gunOrigin[2],
+ ).applyAxisAngle(I_HAT, Math.PI / 2);
+ const turretPosition = new Vector3();
+ const turretRotation = new Euler();
+ const gunPosition = new Vector3();
+ const gunRotation = new Euler();
+
+ function handleModelTransform({ yaw, pitch }: ModelTransformEventData) {
+ gunPosition
+ .set(0, 0, 0)
+ .sub(hullOrigin)
+ .sub(turretOrigin)
+ .sub(gunOrigin)
+ .applyAxisAngle(I_HAT, pitch)
+ .add(gunOrigin)
+ .add(turretOrigin)
+ .add(hullOrigin);
+ gunRotation.set(pitch, 0, 0);
+ gunContainer.current?.position.copy(gunPosition);
+ gunContainer.current?.rotation.copy(gunRotation);
+
+ if (yaw === undefined) return;
+
+ turretPosition
+ .set(0, 0, 0)
+ .sub(hullOrigin)
+ .sub(turretOrigin)
+ .applyAxisAngle(new Vector3(0, 0, 1), yaw);
+ turretRotation.set(0, 0, yaw);
+
+ if (tankModelDefinition.turretRotation) {
+ const initialPitch = -degToRad(
+ tankModelDefinition.turretRotation.pitch,
+ );
+ const initialYaw = -degToRad(tankModelDefinition.turretRotation.yaw);
+ const initialRoll = -degToRad(
+ tankModelDefinition.turretRotation.roll,
+ );
+
+ turretPosition
+ .applyAxisAngle(I_HAT, initialPitch)
+ .applyAxisAngle(J_HAT, initialRoll)
+ .applyAxisAngle(K_HAT, initialYaw);
+ turretRotation.x += initialPitch;
+ turretRotation.y += initialRoll;
+ turretRotation.z += initialYaw;
+ }
+
+ turretPosition.add(turretOrigin).add(hullOrigin);
+ turretContainer.current?.position.copy(turretPosition);
+ turretContainer.current?.rotation.copy(turretRotation);
+ }
+
+ handleModelTransform(useTankopediaTemporary.getState().model.pose);
+ modelTransformEvent.on(handleModelTransform);
+
+ return () => {
+ modelTransformEvent.off(handleModelTransform);
+ };
+ });
+
+ useEffect(() => {
+ const unsubscribe = useTankopediaTemporary.subscribe(
+ (state) => state.mode,
+ (mode) => {
+ if (wrapper.current) wrapper.current.visible = mode === 'armor';
+ },
+ );
+
+ return unsubscribe;
+ });
+
+ const armorGltf = useArmor(protagonist.tank.id);
+ const { gltf: modelGltf } = useModel(protagonist.tank.id);
+
+ const armorNodes = Object.values(armorGltf.nodes);
+ const modelNodes = Object.values(modelGltf.nodes);
+ const tankModelDefinition = modelDefinitions[protagonist.tank.id];
+ const turretModelDefinition =
+ tankModelDefinition.turrets[protagonist.turret.id];
+ const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id];
+ const maxThickness = Math.max(
+ tankModelDefinition.trackThickness,
+ gunModelDefinition.barrelThickness,
+ ...armorNodes
+ .map((node) => {
+ const armorId = nameToArmorId(node.name);
+ return resolveArmor(tankModelDefinition.armor, armorId).thickness;
+ })
+ .filter(Boolean),
+ );
const hullOrigin = new Vector3(
tankModelDefinition.hullOrigin[0],
tankModelDefinition.hullOrigin[1],
@@ -52,165 +161,20 @@ export const SpacedArmorDepth = memo(() => {
turretModelDefinition.gunOrigin[1],
-turretModelDefinition.gunOrigin[2],
).applyAxisAngle(I_HAT, Math.PI / 2);
- const turretPosition = new Vector3();
- const turretRotation = new Euler();
- const gunPosition = new Vector3();
- const gunRotation = new Euler();
- function handleModelTransform({ yaw, pitch }: ModelTransformEventData) {
- gunPosition
- .set(0, 0, 0)
- .sub(hullOrigin)
- .sub(turretOrigin)
- .sub(gunOrigin)
- .applyAxisAngle(I_HAT, pitch)
- .add(gunOrigin)
- .add(turretOrigin)
- .add(hullOrigin);
- gunRotation.set(pitch, 0, 0);
- gunContainer.current?.position.copy(gunPosition);
- gunContainer.current?.rotation.copy(gunRotation);
-
- if (yaw === undefined) return;
-
- turretPosition
- .set(0, 0, 0)
- .sub(hullOrigin)
- .sub(turretOrigin)
- .applyAxisAngle(new Vector3(0, 0, 1), yaw);
- turretRotation.set(0, 0, yaw);
-
- if (tankModelDefinition.turretRotation) {
- const initialPitch = -degToRad(
- tankModelDefinition.turretRotation.pitch,
- );
- const initialYaw = -degToRad(tankModelDefinition.turretRotation.yaw);
- const initialRoll = -degToRad(tankModelDefinition.turretRotation.roll);
-
- turretPosition
- .applyAxisAngle(I_HAT, initialPitch)
- .applyAxisAngle(J_HAT, initialRoll)
- .applyAxisAngle(K_HAT, initialYaw);
- turretRotation.x += initialPitch;
- turretRotation.y += initialRoll;
- turretRotation.z += initialYaw;
- }
-
- turretPosition.add(turretOrigin).add(hullOrigin);
- turretContainer.current?.position.copy(turretPosition);
- turretContainer.current?.rotation.copy(turretRotation);
- }
-
- handleModelTransform(useTankopediaTemporary.getState().model.pose);
- modelTransformEvent.on(handleModelTransform);
-
- return () => {
- modelTransformEvent.off(handleModelTransform);
- };
- });
-
- useEffect(() => {
- const unsubscribe = useTankopediaTemporary.subscribe(
- (state) => state.mode,
- (mode) => {
- if (wrapper.current) wrapper.current.visible = mode === 'armor';
- },
- );
-
- return unsubscribe;
- });
-
- const armorGltf = useArmor(protagonist.tank.id);
- const { gltf: modelGltf } = useModel(protagonist.tank.id);
-
- const armorNodes = Object.values(armorGltf.nodes);
- const modelNodes = Object.values(modelGltf.nodes);
- const tankModelDefinition = modelDefinitions[protagonist.tank.id];
- const turretModelDefinition =
- tankModelDefinition.turrets[protagonist.turret.id];
- const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id];
- const maxThickness = Math.max(
- tankModelDefinition.trackThickness,
- gunModelDefinition.barrelThickness,
- ...armorNodes
- .map((node) => {
- const armorId = nameToArmorId(node.name);
- return resolveArmor(tankModelDefinition.armor, armorId).thickness;
- })
- .filter(Boolean),
- );
- const hullOrigin = new Vector3(
- tankModelDefinition.hullOrigin[0],
- tankModelDefinition.hullOrigin[1],
- -tankModelDefinition.hullOrigin[2],
- ).applyAxisAngle(I_HAT, Math.PI / 2);
- const turretOrigin = new Vector3(
- tankModelDefinition.turretOrigin[0],
- tankModelDefinition.turretOrigin[1],
- -tankModelDefinition.turretOrigin[2],
- ).applyAxisAngle(I_HAT, Math.PI / 2);
- const gunOrigin = new Vector3(
- turretModelDefinition.gunOrigin[0],
- turretModelDefinition.gunOrigin[1],
- -turretModelDefinition.gunOrigin[2],
- ).applyAxisAngle(I_HAT, Math.PI / 2);
-
- return (
-
-
- {armorNodes.map((node) => {
- const isHull = node.name.startsWith('hull_');
- const isVisible = isHull;
- const armorId = nameToArmorId(node.name);
- const { spaced, thickness } = resolveArmor(
- tankModelDefinition.armor,
- armorId,
- );
-
- if (!isVisible || thickness === undefined) return null;
-
- return (
-
- );
- })}
-
- {modelNodes.map((node) => {
- const isWheel = node.name.startsWith('chassis_wheel_');
- const isTrack = node.name.startsWith('chassis_track_');
- const isVisible = isWheel || isTrack;
-
- if (!isVisible) return null;
-
- return (
-
- );
- })}
-
-
+ return (
+
{armorNodes.map((node) => {
- const isCurrentTurret = node.name.startsWith(
- `turret_${turretModelDefinition.model.toString().padStart(2, '0')}`,
- );
- const isVisible = isCurrentTurret;
+ const isHull = node.name.startsWith('hull_');
+ const isVisible = isHull;
const armorId = nameToArmorId(node.name);
const { spaced, thickness } = resolveArmor(
- turretModelDefinition.armor,
+ tankModelDefinition.armor,
armorId,
);
@@ -218,27 +182,44 @@ export const SpacedArmorDepth = memo(() => {
return (
);
})}
-
+ {modelNodes.map((node) => {
+ const isWheel = node.name.startsWith('chassis_wheel_');
+ const isTrack = node.name.startsWith('chassis_track_');
+ const isVisible = isWheel || isTrack;
+
+ if (!isVisible) return null;
+
+ return (
+
+ );
+ })}
+
+
{armorNodes.map((node) => {
- const isCurrentGun = node.name.startsWith(
- `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`,
+ const isCurrentTurret = node.name.startsWith(
+ `turret_${turretModelDefinition.model.toString().padStart(2, '0')}`,
);
- const isVisible = isCurrentGun;
+ const isVisible = isCurrentTurret;
const armorId = nameToArmorId(node.name);
const { spaced, thickness } = resolveArmor(
- gunModelDefinition.armor,
+ turretModelDefinition.armor,
armorId,
);
@@ -246,36 +227,68 @@ export const SpacedArmorDepth = memo(() => {
return (
);
})}
+
+
+ {armorNodes.map((node) => {
+ const isCurrentGun = node.name.startsWith(
+ `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`,
+ );
+ const isVisible = isCurrentGun;
+ const armorId = nameToArmorId(node.name);
+ const { spaced, thickness } = resolveArmor(
+ gunModelDefinition.armor,
+ armorId,
+ );
- {modelNodes.map((node) => {
- const isCurrentGun =
- node.name ===
- `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`;
- const isVisible = isCurrentGun;
+ if (!isVisible || thickness === undefined) return null;
- if (!isVisible) return null;
+ return (
+
+ );
+ })}
+
- return (
-
- );
- })}
+ {modelNodes.map((node) => {
+ const isCurrentGun =
+ node.name ===
+ `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`;
+ const isVisible = isCurrentGun;
+
+ if (!isVisible) return null;
+
+ return (
+
+ );
+ })}
+
-
- );
-});
+ );
+ },
+);
diff --git a/src/components/ArmorMesh/components/Armor/index.tsx b/src/components/ArmorMesh/components/Armor/index.tsx
index 17d433d49..ab7e0a246 100644
--- a/src/components/ArmorMesh/components/Armor/index.tsx
+++ b/src/components/ArmorMesh/components/Armor/index.tsx
@@ -6,7 +6,10 @@ import { canSplash } from '../../../../core/blitz/canSplash';
import { isExplosive } from '../../../../core/blitz/isExplosive';
import { resolveNearPenetration } from '../../../../core/blitz/resolveNearPenetration';
import { useDuel } from '../../../../stores/duel';
-import { useTankopediaPersistent } from '../../../../stores/tankopedia';
+import {
+ useTankopediaPersistent,
+ useTankopediaTemporary,
+} from '../../../../stores/tankopedia';
import { externalModuleMaskRenderTarget } from '../ExternalModuleMask';
import { spacedArmorDepthRenderTarget } from '../SpacedArmorDepth';
import fragmentShader from './shaders/fragment.glsl';
@@ -17,6 +20,11 @@ interface ArmorMeshProps extends MeshProps {
maxThickness: number;
}
+export type ArmorMeshUserData = {
+ type: 'coreArmor' | 'spacedArmor' | 'externalModule';
+ thickness: number;
+};
+
export function ArmorMesh({
thickness,
maxThickness,
@@ -109,7 +117,26 @@ export function ArmorMesh({
-
+ {
+ if (useTankopediaTemporary.getState().mode !== 'armor') return;
+
+ event.intersections
+ .filter(({ object }) => Boolean(object.userData.type))
+ .map(({ object }) => {
+ const data = object.userData as ArmorMeshUserData;
+ console.log(data.type, data.thickness);
+ });
+ }}
+ >
- {props.exclude && (
+ {(props.exclude || ornamental) && (
)}
{!props.exclude && (
-
+ {} : undefined}
+ userData={
+ {
+ type: 'externalModule',
+ thickness: props.thickness,
+ } satisfies ArmorMeshUserData
+ }
+ >
)}
diff --git a/src/components/ArmorMesh/components/SpacedArmorDepth/index.tsx b/src/components/ArmorMesh/components/SpacedArmorDepth/index.tsx
index 9ed611384..a28da6a13 100644
--- a/src/components/ArmorMesh/components/SpacedArmorDepth/index.tsx
+++ b/src/components/ArmorMesh/components/SpacedArmorDepth/index.tsx
@@ -1,12 +1,14 @@
import { MeshProps } from '@react-three/fiber';
import { WebGLRenderTarget } from 'three';
+import { ArmorMeshUserData } from '../Armor';
import fragmentShader from './shaders/fragment.glsl';
import vertexShader from './shaders/vertex.glsl';
export const spacedArmorDepthRenderTarget = new WebGLRenderTarget();
-type ArmorMeshSpacedArmorDepthProps = MeshProps &
- (
+type ArmorMeshSpacedArmorDepthProps = MeshProps & {
+ ornamental?: boolean;
+} & (
| {
include?: false;
isExternalModule: boolean;
@@ -18,27 +20,44 @@ type ArmorMeshSpacedArmorDepthProps = MeshProps &
}
);
-export function ArmorMeshSpacedArmorDepth(
- props: ArmorMeshSpacedArmorDepthProps,
-) {
+export function ArmorMeshSpacedArmorDepth({
+ ornamental = false,
+ ...props
+}: ArmorMeshSpacedArmorDepthProps) {
return (
<>
- {!props.include && (
+ {!props.include && !ornamental && (
)}
{props.include && (
-
-
+ {} : undefined}
+ userData={
+ {
+ type: 'spacedArmor',
+ thickness: props.thickness,
+ } satisfies ArmorMeshUserData
+ }
+ >
+ {!ornamental && (
+
+ )}
+
+ {ornamental && (
+
+ )}
)}
>