feat: correct he calculations

This commit is contained in:
TrèsAbhi committed 2024-01-20 15:21:30 -06:00
1 parent 417858f21a
commit e724069cbd
2 files changed
+54 -50

No files matched your search

@@ -15,13 +15,11 @@ import vertexShader from './shaders/vertex.glsl';
interface ArmorMeshProps extends MeshProps { interface ArmorMeshProps extends MeshProps {
duel: Duel; duel: Duel;
isExternalModule?: boolean;
thickness: number; thickness: number;
maxThickness: number; maxThickness: number;
} }
export function ArmorMesh({ export function ArmorMesh({
isExternalModule = false,
thickness, thickness,
maxThickness, maxThickness,
duel, duel,
@@ -52,6 +50,8 @@ export function ArmorMesh({
} }
}); });
console.log(resolveNearPenetration(shell.penetration));
return ( return (
<> <>
<mesh {...props} renderOrder={0}> <mesh {...props} renderOrder={0}>
@@ -79,16 +79,18 @@ export function ArmorMesh({
maxThickness: { value: maxThickness }, maxThickness: { value: maxThickness },
isExplosive: { value: isExplosive(shell.type) }, isExplosive: { value: isExplosive(shell.type) },
canSplash: { value: canSplash(shell.type) }, canSplash: { value: canSplash(shell.type) },
isExternalModule: { value: isExternalModule },
thickness: { value: thickness }, thickness: { value: thickness },
penetration: { penetration: {
value: resolveNearPenetration(shell.penetration), // value: resolveNearPenetration(shell.penetration),
value: 0,
}, },
caliber: { value: shell.caliber }, caliber: { value: shell.caliber },
ricochet: { value: degToRad(shell.ricochet ?? 90) }, ricochetAngle: { value: degToRad(shell.ricochet ?? 90) },
normalization: { normalization: {
value: degToRad(shell.normalization ?? 0), value: degToRad(shell.normalization ?? 0),
}, },
damage: { value: shell.damage.armor },
explosionRadius: { value: shell.explosionRadius ?? 0 },
}} }}
/> />
</mesh> </mesh>
@@ -1,11 +1,10 @@
varying vec3 vCSMViewPosition; varying vec3 vCSMViewPosition;
uniform bool isExplosive; uniform bool isExplosive;
uniform bool canSplash; uniform bool canSplash;
uniform bool isExternalModule;
uniform float thickness; uniform float thickness;
uniform float penetration; uniform float penetration;
uniform float caliber; uniform float caliber;
uniform float ricochet; uniform float ricochetAngle;
uniform float normalization; uniform float normalization;
uniform sampler2D externalModuleMask; uniform sampler2D externalModuleMask;
uniform sampler2D spacedArmorDepth; uniform sampler2D spacedArmorDepth;
@@ -14,6 +13,8 @@ uniform vec2 resolution;
varying mat4 vProjectionMatrix; varying mat4 vProjectionMatrix;
uniform float maxThickness; uniform float maxThickness;
uniform bool greenPenetration; uniform bool greenPenetration;
uniform float damage;
uniform float explosionRadius;
float depthToDistance(float depth) { float depthToDistance(float depth) {
mat4 projectionMatrixInverse = inverse(vProjectionMatrix); mat4 projectionMatrixInverse = inverse(vProjectionMatrix);
@@ -26,78 +27,79 @@ float depthToDistance(float depth) {
} }
void main() { void main() {
float penetrationChance = -1.0;
float splashChance = -1.0;
vec3 normalizedViewPosition = normalize(vCSMViewPosition);
float dotProduct = dot(vNormal, -normalizedViewPosition);
float coreArmorangle = acos(dotProduct);
vec2 screenCoordinates = gl_FragCoord.xy / resolution; vec2 screenCoordinates = gl_FragCoord.xy / resolution;
float spacedArmorDepth = texture2D(spacedArmorDepth, screenCoordinates).r;
float currentDistance = depthToDistance(gl_FragCoord.z);
float spacedArmorDistance = depthToDistance(spacedArmorDepth);
float distanceFromSpacedArmor = currentDistance - spacedArmorDistance;
vec4 externalModuleMaskColor = texture2D(externalModuleMask, screenCoordinates); vec4 externalModuleMaskColor = texture2D(externalModuleMask, screenCoordinates);
vec4 spacedArmorMaskColor = texture2D(spacedArmorMask, screenCoordinates); vec4 spacedArmorMaskColor = texture2D(spacedArmorMask, screenCoordinates);
bool isUnderExternalModule = externalModuleMaskColor.r == 1.0; bool isUnderExternalModule = externalModuleMaskColor.r == 1.0;
bool isUnderSpacedArmor = spacedArmorMaskColor.a == 1.0; bool isUnderSpacedArmor = spacedArmorMaskColor.a == 1.0;
vec3 normalizedNormal = normalize(vNormal);
vec3 normalizedViewPosition = normalize(vCSMViewPosition);
float dotProduct = dot(normalizedNormal, -normalizedViewPosition);
float angle = acos(dotProduct);
float spacedArmorAngle = spacedArmorMaskColor.r * PI; float spacedArmorAngle = spacedArmorMaskColor.r * PI;
float penetrationChance = -1.0;
float splashChance = -1.0;
bool threeCalibersRule = caliber > 3.0 * thickness;
float normalizedSpacedArmorThickness = spacedArmorMaskColor.g;
float spacedArmorNominalThickness = normalizedSpacedArmorThickness * maxThickness;
bool spadedArmorThreeCalibersRule = isUnderSpacedArmor && caliber > 3.0 * spacedArmorNominalThickness;
bool ricochetSpacedArmor = isUnderSpacedArmor && !spadedArmorThreeCalibersRule && spacedArmorAngle >= ricochet;
bool ricochetCoreArmor = !ricochetSpacedArmor && !isUnderExternalModule && !isExternalModule && !isExplosive && !threeCalibersRule && angle >= ricochet;
if (ricochetCoreArmor || ricochetSpacedArmor) { bool coreArmorThreeCalibersRule = caliber > 3.0 * thickness;
float spacedArmorNominalThickness = spacedArmorMaskColor.g * maxThickness;
bool spacedArmorThreeCalibersRule = isUnderSpacedArmor && caliber > 3.0 * spacedArmorNominalThickness;
bool hasRicochetedSpacedArmor = !isExplosive && isUnderSpacedArmor && !spacedArmorThreeCalibersRule && spacedArmorAngle >= ricochetAngle;
bool isUnderAnything = isUnderExternalModule || isUnderSpacedArmor;
bool hasRicochetedCoreArmor = !isExplosive && !isUnderAnything && !coreArmorThreeCalibersRule && coreArmorangle >= ricochetAngle;
if (hasRicochetedCoreArmor || hasRicochetedSpacedArmor) {
penetrationChance = 0.0; penetrationChance = 0.0;
splashChance = 0.0; splashChance = 0.0;
} else { } else {
float piercedPenetration = penetration; // time to chip away at the penetration, one case at a time
float remainingPenetration = penetration;
if (isUnderExternalModule) { if (isUnderExternalModule) {
float normalizedExternalModuleThickness = externalModuleMaskColor.g; // external modules don't care about angle, they'll reduce penetration by their thickness
float externalModuleThickness = normalizedExternalModuleThickness * maxThickness; float externalModuleThickness = externalModuleMaskColor.g * maxThickness;
piercedPenetration -= externalModuleThickness; remainingPenetration -= externalModuleThickness;
} }
if (isUnderSpacedArmor) { if (isUnderSpacedArmor) {
// spaced armor on the other hand, does care about angle
float spacedArmorThickness = spacedArmorNominalThickness / cos(spacedArmorAngle); float spacedArmorThickness = spacedArmorNominalThickness / cos(spacedArmorAngle);
piercedPenetration -= spacedArmorThickness; remainingPenetration -= spacedArmorThickness;
} }
float spacedArmorDepth = texture2D(spacedArmorDepth, screenCoordinates).r;
float spacedArmorDistance = depthToDistance(spacedArmorDepth);
float coreArmorDistance = depthToDistance(gl_FragCoord.z);
float distanceFromSpacedArmor = abs(coreArmorDistance - spacedArmorDistance);
if (isExplosive) { if (isExplosive) {
// 50% loss of remaining penetration per meter // there is a 50% penetration loss per meter for HE based shells
piercedPenetration -= 0.5 * piercedPenetration * distanceFromSpacedArmor; remainingPenetration -= 0.5 * remainingPenetration * distanceFromSpacedArmor;
} }
piercedPenetration = max(piercedPenetration, 0.0); // clamp to 0 because negative penetration causes guaranteed penetrations for some reason
remainingPenetration = max(remainingPenetration, 0.0);
bool twoCalibersRule = caliber > 2.0 * thickness; bool coreArmorTwoCalibersRule = caliber > 2.0 * thickness;
float finalNormalization = twoCalibersRule ? (normalization * 1.4 * caliber) / (2.0 * thickness) : normalization; float finalNormalization = coreArmorTwoCalibersRule ? (normalization * 1.4 * caliber) / (2.0 * thickness) : normalization;
float finalThickness = thickness / cos(angle - finalNormalization); float finalCoreArmorThickness = thickness / cos(coreArmorangle - finalNormalization);
float delta = finalThickness - piercedPenetration; float deltaPenetration = finalCoreArmorThickness - remainingPenetration;
float randomRadius = piercedPenetration * 0.05; float randomRadius = remainingPenetration * 0.05;
if (delta > randomRadius) { if (deltaPenetration > randomRadius) {
// even with a 5% buff to the penetration, can't penetrate
penetrationChance = 0.0; penetrationChance = 0.0;
} else if (delta < -randomRadius) { } else if (deltaPenetration < -randomRadius) {
// even with a 5% nerf, can penetrate
penetrationChance = 1.0; penetrationChance = 1.0;
} else { } else {
penetrationChance = max(1.0 - (delta + randomRadius) / (2.0 * randomRadius), 0.0); // transition area
penetrationChance = max(1.0 - (deltaPenetration + randomRadius) / (2.0 * randomRadius), 0.0);
} }
if (canSplash) { if (canSplash) {
float reducedFinalThickness = finalThickness * (1.0 / 10.0); // only allow splasing if the damage equation deals more than 0 damage
float splashDelta = reducedFinalThickness - piercedPenetration; float finalDamage = 0.5 * damage * (1.0 - distanceFromSpacedArmor / explosionRadius) - 1.1 * finalCoreArmorThickness;
splashChance = finalDamage > 0.0 ? 1.0 : 0.0;
if (splashDelta > randomRadius) {
splashChance = 0.0;
} else if (splashDelta < -randomRadius) {
splashChance = 1.0;
} else {
splashChance = 1.0 - (splashDelta + randomRadius) / (2.0 * randomRadius);
}
} else { } else {
splashChance = 0.0; splashChance = 0.0;
} }