feat: more advanced armor highlighting

This commit is contained in:
TrèsAbhi committed 2024-01-12 13:57:32 -06:00
1 parent 909474d4cb
commit d469f990f6
10 files changed
+119 -199

No files matched your search

+21 -32
View File
@@ -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 && (
<mesh {...props}>
<meshBasicMaterial colorWrite={false} />
</mesh>
)}
<mesh {...props} renderOrder={spaced ? 3 : 1}>
<mesh {...props} renderOrder={1}>
<CustomShaderMaterial
silent
baseMaterial={MeshStandardMaterial}
transparent
silent
depthWrite={false}
fragmentShader={fragmentShader}
uniforms={{
isExplosive: { value: isExplosive },
canSplash: { value: canSplash },
isSpaced: { value: isSpaced },
isArmor: { value: isArmor },
thickness: { value: thickness },
penetration: { value: penetration },
ricochet: {
value: ricochet === undefined ? 0 : ricochet * (Math.PI / 180),
},
normalization: {
value:
normalization === undefined
? 0
: normalization * (Math.PI / 180),
},
caliber: { value: caliber },
spaced: { value: spaced ?? false },
canRicochet: { value: canRicochet },
canSplash: { value: canSplash },
isAffectedBySpaced: { value: isAffectedBySpaced },
ricochet: { value: ricochet * (Math.PI / 180) },
normalization: { value: normalization * (Math.PI / 180) },
}}
vertexShader={vertex}
fragmentShader={fragment}
/>
</mesh>
</>
+42 -53
View File
@@ -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);
}
}
}
@@ -1,6 +0,0 @@
varying vec3 vCSMViewPosition;
void main() {
vec4 vViewPosition4 = modelViewMatrix * vec4(position, 1.0);
vCSMViewPosition = vViewPosition4.xyz;
}