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',