mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: correct he calculations
This commit is contained in:
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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user