From d469f990f6b40dcf7f829f784bcc6517bc5ec4f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 12 Jan 2024 13:57:32 -0600 Subject: [PATCH] feat: more advanced armor highlighting --- scripts/buildAssets/tankArmors.ts | 2 +- scripts/buildAssets/tankModels.ts | 2 +- .../components/Model/components/TankArmor.tsx | 134 ++++++------------ src/app/tools/tankopedia/[id]/page.tsx | 2 +- src/components/ArmorMesh/index.tsx | 53 +++---- .../ArmorMesh/shaders/fragment.glsl | 95 ++++++------- src/components/ArmorMesh/shaders/vertex.glsl | 6 - src/core/blitz/canRicochet.ts | 7 - .../{isAffectedBySpaced.ts => isExplosive.ts} | 2 +- src/core/blitzkrieg/tankDefinitions.ts | 15 +- 10 files changed, 119 insertions(+), 199 deletions(-) delete mode 100644 src/components/ArmorMesh/shaders/vertex.glsl delete mode 100644 src/core/blitz/canRicochet.ts rename src/core/blitz/{isAffectedBySpaced.ts => isExplosive.ts} (82%) diff --git a/scripts/buildAssets/tankArmors.ts b/scripts/buildAssets/tankArmors.ts index e2ccc282f..fcc25f8d7 100644 --- a/scripts/buildAssets/tankArmors.ts +++ b/scripts/buildAssets/tankArmors.ts @@ -20,7 +20,7 @@ export async function buildTankArmors() { await Promise.all( nations.map(async (nation) => { - if (nation !== 'china') return; + if (nation !== 'france') return; const tanks = await readXMLDVPL<{ root: VehicleDefinitionList }>( `${DATA}/${DOI.vehicleDefinitions}/${nation}/list.xml.dvpl`, diff --git a/scripts/buildAssets/tankModels.ts b/scripts/buildAssets/tankModels.ts index 4a982c42f..659bb42d8 100644 --- a/scripts/buildAssets/tankModels.ts +++ b/scripts/buildAssets/tankModels.ts @@ -27,7 +27,7 @@ export async function buildTankModels() { await Promise.all( nations.map(async (nation) => { - if (nation !== 'china') return; + if (nation !== 'france') return; const tanks = await readXMLDVPL<{ root: VehicleDefinitionList }>( `${DATA}/${DOI.vehicleDefinitions}/${nation}/list.xml.dvpl`, 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 c8ee3ee8e..2c1d621f8 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor.tsx @@ -5,16 +5,14 @@ import { GLTFLoader } from 'three-stdlib'; import { ArmorMesh } from '../../../../../../../components/ArmorMesh'; 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 { isExplosive } from '../../../../../../../core/blitz/isExplosive'; import { numericPenetration } from '../../../../../../../core/blitz/numericPenetration'; import { asset } from '../../../../../../../core/blitzkrieg/asset'; import { ModelDefinitions, modelDefinitions, } from '../../../../../../../core/blitzkrieg/modelDefinitions'; -import { RicochetCapableShell } from '../../../../../../../core/blitzkrieg/tankDefinitions'; import { useTankopedia } from '../../../../../../../stores/tankopedia'; import { Lighting } from '../../Lighting'; @@ -77,9 +75,11 @@ export function TankArmor({ ...props }: TankArmorProps) { .sub(turretOrigin) .applyAxisAngle(new Vector3(0, 0, 1), model.turretYaw); 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); + const explosiveCapable = isExplosive(antagonist.shell.type); + const penetration = numericPenetration(antagonist.shell.penetration); + const ricochet = antagonist.shell.ricochet ?? Math.PI / 2; + const normalization = antagonist.shell.normalization ?? 0; if (tankModelDefinition.turretRotation) { const pitch = -tankModelDefinition.turretRotation.pitch * (Math.PI / 180); @@ -122,25 +122,17 @@ export function TankArmor({ ...props }: TankArmorProps) { return ( ); })} @@ -155,25 +147,17 @@ export function TankArmor({ ...props }: TankArmorProps) { return ( ); })} @@ -200,26 +184,18 @@ export function TankArmor({ ...props }: TankArmorProps) { return ( ); })} @@ -252,26 +228,18 @@ export function TankArmor({ ...props }: TankArmorProps) { return ( ); })} @@ -287,25 +255,17 @@ export function TankArmor({ ...props }: TankArmorProps) { return ( ); })} diff --git a/src/app/tools/tankopedia/[id]/page.tsx b/src/app/tools/tankopedia/[id]/page.tsx index cb427b6d2..711960985 100644 --- a/src/app/tools/tankopedia/[id]/page.tsx +++ b/src/app/tools/tankopedia/[id]/page.tsx @@ -24,7 +24,7 @@ export default function Page({ params }: { params: { id: string } }) { draft.model.hullYaw = 0; draft.model.turretYaw = 0; draft.model.gunPitch = 0; - draft.mode = 'model'; + draft.mode = 'armor'; draft.areTanksAssigned = true; if (!draft.areTanksAssigned) return; diff --git a/src/components/ArmorMesh/index.tsx b/src/components/ArmorMesh/index.tsx index 0c320d30b..2dc9fd622 100644 --- a/src/components/ArmorMesh/index.tsx +++ b/src/components/ArmorMesh/index.tsx @@ -1,69 +1,58 @@ import { MeshProps } from '@react-three/fiber'; import { MeshStandardMaterial } from 'three'; import CustomShaderMaterial from 'three-custom-shader-material'; -import fragment from './shaders/fragment.glsl'; -import vertex from './shaders/vertex.glsl'; +import fragmentShader from './shaders/fragment.glsl'; interface ArmorMeshProps extends MeshProps { + isExplosive: boolean; + canSplash: boolean; + isSpaced: boolean; + isArmor: boolean; thickness: number; penetration: number; caliber: number; - spaced?: boolean; - canRicochet: boolean; - canSplash: boolean; - ricochet?: number; - normalization?: number; - isAffectedBySpaced: boolean; + ricochet: number; + normalization: number; } -// shader split: https://github.com/FarazzShaikh/THREE-CustomShaderMaterial/issues/48 - export function ArmorMesh({ + isExplosive, + canSplash, + isSpaced, + isArmor, thickness, penetration, caliber, - canRicochet, ricochet, - canSplash, - isAffectedBySpaced, normalization, - spaced = false, ...props }: ArmorMeshProps) { return ( <> - {!spaced && ( + {!isSpaced && ( )} - + diff --git a/src/components/ArmorMesh/shaders/fragment.glsl b/src/components/ArmorMesh/shaders/fragment.glsl index 12866bf0d..279efe746 100644 --- a/src/components/ArmorMesh/shaders/fragment.glsl +++ b/src/components/ArmorMesh/shaders/fragment.glsl @@ -1,75 +1,64 @@ -// split shaders due to https://github.com/FarazzShaikh/THREE-CustomShaderMaterial/issues/48 - -varying vec3 vCSMViewPosition; +uniform bool isExplosive; +uniform bool canSplash; +uniform bool isSpaced; +uniform bool isArmor; uniform float thickness; uniform float penetration; -uniform float ricochet; uniform float caliber; +uniform float ricochet; uniform float normalization; -uniform bool spaced; -uniform bool canRichochet; -uniform bool canSplash; -uniform bool isAffectedBySpaced; + +vec3 zPositive = vec3(0.0, 0.0, 1.0); void main() { - vec3 normalizedNormal = normalize(vNormal); - vec3 normalizedViewPosition = normalize(vCSMViewPosition); - float dotProduct = dot(normalizedNormal, -normalizedViewPosition); - float angle = acos(dotProduct); + float cosAngle = dot(zPositive, vNormal); + float angle = acos(cosAngle); float penetrationChance = -1.0; - bool threeCaliberRule = caliber > 3.0 * thickness; + float splashChance = -1.0; + bool threeCalibersRule = caliber > 3.0 * thickness; - if (canRichochet && !threeCaliberRule && angle >= ricochet) { - // auto ricochet angle and three caliber rule not met + if (isArmor && !isExplosive && !threeCalibersRule && angle >= ricochet) { penetrationChance = 0.0; + splashChance = 0.0; } else { - bool twoCaliberRule = caliber > 2.0 * thickness; - float finalNormalization = twoCaliberRule ? (normalization * 1.4 * caliber) / (2.0 * thickness) : normalization; - float effectiveArmor = thickness / cos(angle - finalNormalization); - float penetrationRandomRadius = penetration * 0.05; - float penetrationDifference = effectiveArmor - penetration; + bool twoCalibersRule = caliber > 2.0 * thickness; + float finalNormalization = twoCalibersRule ? (normalization * 1.4 * caliber) / (2.0 * thickness) : normalization; + float finalThickness = thickness / cos(angle - finalNormalization); - if (penetrationDifference > penetrationRandomRadius) { - // even with a +5% buff, can't penetrate - penetrationChance = 0.0; - } else if (penetrationDifference < -penetrationRandomRadius) { - // event with a -5% nerf, can penetrate - penetrationChance = 1.0; + if (canSplash) { + if (finalThickness * (5.0 / 11.0) > penetration) { + penetrationChance = 0.0; + splashChance = 0.0; + } else if (finalThickness > penetration) { + penetrationChance = 0.0; + splashChance = 1.0; + } else { + penetrationChance = 1.0; + splashChance = 1.0; + } } else { - // penetration gradiant - penetrationChance = 1.0 - (penetrationDifference + penetrationRandomRadius) / (2.0 * penetrationRandomRadius); + if (finalThickness > penetration) { + penetrationChance = 0.0; + splashChance = 0.0; + } else { + penetrationChance = 1.0; + splashChance = 0.0; + } } } - float alpha = (1.0 - penetrationChance) * 0.5; - - if (canSplash) { - // he - if (spaced) { - csm_FragColor = vec4(1.0, 0.0, 1.0, 0.5); - } else { - float angledThickness = thickness / cos(angle); - - if (angledThickness * (5.0 / 11.0) > penetration) { - csm_FragColor = vec4(1.0, 0.0, 0.0, alpha); - } else { - csm_FragColor = vec4(1.0, 0.392, 0.0, alpha); - } - - } - } else { - if (spaced) { - if (isAffectedBySpaced) { - // hc + if (isSpaced) { + if (isArmor) { + if (isExplosive) { csm_FragColor = vec4(1.0, 0.0, 1.0, 0.5); } else { - // ap, ap_cr - csm_FragColor = vec4(1.0, 0.0, 1.0, alpha); + csm_FragColor = vec4(1.0, 0.0, 1.0, (1.0 - penetrationChance) * 0.5); } } else { - // ap, ap_cr, hc - csm_FragColor = vec4(1.0, 0.0, 0.0, alpha); + csm_FragColor = vec4(0.5, 0.0, 1.0, 0.5); } + } else { + csm_FragColor = vec4(1.0, splashChance * 0.392, 0.0, (1.0 - penetrationChance) * 0.5); } -} +} \ No newline at end of file diff --git a/src/components/ArmorMesh/shaders/vertex.glsl b/src/components/ArmorMesh/shaders/vertex.glsl deleted file mode 100644 index afaeda2c0..000000000 --- a/src/components/ArmorMesh/shaders/vertex.glsl +++ /dev/null @@ -1,6 +0,0 @@ -varying vec3 vCSMViewPosition; - -void main() { - vec4 vViewPosition4 = modelViewMatrix * vec4(position, 1.0); - vCSMViewPosition = vViewPosition4.xyz; -} \ No newline at end of file diff --git a/src/core/blitz/canRicochet.ts b/src/core/blitz/canRicochet.ts deleted file mode 100644 index 26baf57b5..000000000 --- a/src/core/blitz/canRicochet.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ShellDefinition } from '../blitzkrieg/tankDefinitions'; - -export function canRicochet( - type: ShellDefinition['type'], -): type is 'ap' | 'ap_cr' { - return type === 'ap' || type === 'ap_cr'; -} diff --git a/src/core/blitz/isAffectedBySpaced.ts b/src/core/blitz/isExplosive.ts similarity index 82% rename from src/core/blitz/isAffectedBySpaced.ts rename to src/core/blitz/isExplosive.ts index 7be3b84c6..cd0e0984f 100644 --- a/src/core/blitz/isAffectedBySpaced.ts +++ b/src/core/blitz/isExplosive.ts @@ -1,6 +1,6 @@ import { ShellDefinition } from '../blitzkrieg/tankDefinitions'; -export function isAffectedBySpaced( +export function isExplosive( type: ShellDefinition['type'], ): type is 'he' | 'hc' { return type === 'he' || type === 'hc'; diff --git a/src/core/blitzkrieg/tankDefinitions.ts b/src/core/blitzkrieg/tankDefinitions.ts index 7c7cb816e..116f9f375 100644 --- a/src/core/blitzkrieg/tankDefinitions.ts +++ b/src/core/blitzkrieg/tankDefinitions.ts @@ -58,15 +58,7 @@ interface GunDefinitionAutoReloader { interClip: number; count: number; } -export interface RicochetCapableShell { - type: 'ap' | 'ap_cr'; - normalization: number; - ricochet: number; -} -export interface RicochetIncapableShell { - type: 'hc' | 'he'; -} -export type ShellDefinition = { +export interface ShellDefinition { id: number; name: string; speed: number; @@ -74,7 +66,10 @@ export type ShellDefinition = { caliber: number; icon: string; penetration: number | Vector2Tuple; -} & (RicochetCapableShell | RicochetIncapableShell); + type: ShellType; + normalization?: number; + ricochet?: number; +} export const tankDefinitions = fetch(asset('definitions/tanks.json'), { cache: 'no-cache',