diff --git a/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor.tsx b/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor.tsx index 14d8f242e..60c377794 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor.tsx @@ -7,6 +7,7 @@ import { HeadsUpDisplay } from '../../../../../../../components/HeadsUpDisplay'; import { X_AXIS } from '../../../../../../../constants/axis'; import { canRicochet } from '../../../../../../../core/blitz/canRicochet'; import { canSplash } from '../../../../../../../core/blitz/canSplash'; +import { isAffectedBySpaced } from '../../../../../../../core/blitz/isAffectedBySpaced'; import { numericPenetration } from '../../../../../../../core/blitz/numericPenetration'; import { asset } from '../../../../../../../core/blitzkrieg/asset'; import { @@ -36,10 +37,14 @@ export function TankArmor({ ...props }: TankArmorProps) { if (!protagonist || !antagonist) return null; - const gltf = useLoader( + const armorGltf = useLoader( GLTFLoader, asset(`3d/tanks/armor/${protagonist.tank.id}.glb`), ); + const modelGltf = useLoader( + GLTFLoader, + asset(`3d/tanks/models/${protagonist.tank.id}.glb`), + ); const model = useTankopedia((state) => state.model); useEffect(() => { @@ -50,7 +55,8 @@ export function TankArmor({ ...props }: TankArmorProps) { if (!awaitedModelDefinitions) return null; - const nodes = Object.values(gltf.nodes); + const armorNodes = Object.values(armorGltf.nodes); + const modelNodes = Object.values(modelGltf.nodes); const tankModelDefinition = awaitedModelDefinitions[protagonist.tank.id]; const turretModelDefinition = tankModelDefinition.turrets[protagonist.turret.id]; @@ -71,6 +77,7 @@ export function TankArmor({ ...props }: TankArmorProps) { const turretRotation = new Euler(0, 0, model.turretYaw); const ricochetCapable = canRicochet(antagonist.shell.type); const splashCapable = canSplash(antagonist.shell.type); + const affectedBySpacedCapable = isAffectedBySpaced(antagonist.shell.type); if (tankModelDefinition.turretRotation) { const pitch = -tankModelDefinition.turretRotation.pitch * (Math.PI / 180); @@ -97,7 +104,7 @@ export function TankArmor({ ...props }: TankArmorProps) { rotation={[-Math.PI / 2, 0, model.hullYaw]} visible={controlsEnabled} > - {nodes.map((node) => { + {armorNodes.map((node) => { const isHull = node.name.startsWith('hull_'); const armorId = parseInt(node.name.match(/.+_armor_(\d+)/)![1]); const isVisible = isHull; @@ -113,6 +120,7 @@ export function TankArmor({ ...props }: TankArmorProps) { return ( { + const isWheel = node.name.startsWith('chassis_wheel_'); + const isTrack = node.name.startsWith('chassis_track_'); + const isVisible = isWheel || isTrack; + const thickness = 50; + + if (!isVisible || !showSpacedArmor) return null; + + return ( + + ); + })} + - {nodes.map((node) => { + {armorNodes.map((node) => { const isCurrentTurret = node.name.startsWith( `turret_${turretModelDefinition.model .toString() @@ -157,6 +198,7 @@ export function TankArmor({ ...props }: TankArmorProps) { return ( - {nodes.map((node) => { + {armorNodes.map((node) => { const isCurrentGun = node.name.startsWith( `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`, ); @@ -207,6 +249,7 @@ export function TankArmor({ ...props }: TankArmorProps) { return null; return ( ); })} + + {modelNodes.map((node) => { + const isCurrentGun = + node.name === + `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`; + const isVisible = isCurrentGun; + const thickness = 50; + + if (!isVisible || !showSpacedArmor) return null; + + return ( + + ); + })} diff --git a/src/components/ArmorMesh/index.tsx b/src/components/ArmorMesh/index.tsx index 2eecf6644..21848a2f1 100644 --- a/src/components/ArmorMesh/index.tsx +++ b/src/components/ArmorMesh/index.tsx @@ -15,6 +15,7 @@ interface ArmorMeshProps extends MeshProps { canSplash: boolean; ricochet?: number; normalization?: number; + isAffectedBySpaced: boolean; } // shader split: https://github.com/FarazzShaikh/THREE-CustomShaderMaterial/issues/48 @@ -26,6 +27,7 @@ export function ArmorMesh({ canRicochet, ricochet, canSplash, + isAffectedBySpaced, normalization, spaced = false, ...props @@ -62,6 +64,7 @@ export function ArmorMesh({ spaced: { value: spaced ?? false }, canRicochet: { value: canRicochet }, canSplash: { value: canSplash }, + isAffectedBySpaced: { value: isAffectedBySpaced }, }} vertexShader={vertex} fragmentShader={opaqueArmor && !spaced ? fragmentOpaque : fragment} diff --git a/src/components/ArmorMesh/shaders/fragment.glsl b/src/components/ArmorMesh/shaders/fragment.glsl index e14ce3382..86a1a6a1d 100644 --- a/src/components/ArmorMesh/shaders/fragment.glsl +++ b/src/components/ArmorMesh/shaders/fragment.glsl @@ -9,6 +9,7 @@ uniform float normalization; uniform bool spaced; uniform bool canRichochet; uniform bool canSplash; +uniform bool isAffectedBySpaced; void main() { vec3 normalizedNormal = normalize(vNormal); @@ -45,14 +46,22 @@ void main() { if (canSplash) { if (spaced) { - csm_FragColor = vec4(1.0, 0.0, 0.0, alpha); + if (isAffectedBySpaced) { + csm_FragColor = vec4(1.0, 0.0, 0.0, 0.5); + } else { + csm_FragColor = vec4(1.0, 0.0, 0.0, alpha); + } } else { // color taken directly from the game csm_FragColor = vec4(1.0, 0.392, 0.0, alpha); } } else { if (spaced) { - csm_FragColor = vec4(0.0, 0.0, 1.0, alpha); + if (isAffectedBySpaced) { + csm_FragColor = vec4(0.0, 0.0, 1.0, 0.5); + } else { + csm_FragColor = vec4(0.0, 0.0, 1.0, alpha); + } } else { csm_FragColor = vec4(1.0, 0.0, 0.0, alpha); } diff --git a/src/core/blitz/isAffectedBySpaced.ts b/src/core/blitz/isAffectedBySpaced.ts new file mode 100644 index 000000000..7be3b84c6 --- /dev/null +++ b/src/core/blitz/isAffectedBySpaced.ts @@ -0,0 +1,7 @@ +import { ShellDefinition } from '../blitzkrieg/tankDefinitions'; + +export function isAffectedBySpaced( + type: ShellDefinition['type'], +): type is 'he' | 'hc' { + return type === 'he' || type === 'hc'; +}