feat: explosive shells under spaced armor

This commit is contained in:
TrèsAbhi committed 2024-01-15 21:55:09 -06:00
1 parent 80b161b9fc
commit 730ad56677
7 files changed
+373 -37

No files matched your search

@@ -1,4 +1,4 @@
import { MeshProps, useFrame } from '@react-three/fiber';
import { MeshProps, useFrame, useThree } from '@react-three/fiber';
import { useRef } from 'react';
import { MeshStandardMaterial, ShaderMaterial, Vector2 } from 'three';
import ThreeCustomShaderMaterial from 'three-custom-shader-material';
@@ -8,6 +8,7 @@ import { canSplash } from '../../../../core/blitz/canSplash';
import { isExplosive } from '../../../../core/blitz/isExplosive';
import { resolveNearPenetration } from '../../../../core/blitz/resolveNearPenetration';
import { externalModuleMaskRenderTarget } from '../ExternalModuleMask';
import { spacedArmorDepthRenderTarget } from '../SpacedArmorDepth';
import fragmentShader from './shaders/fragment.glsl';
import vertexShader from './shaders/vertex.glsl';
@@ -25,18 +26,23 @@ export function ArmorMesh({
duel,
...props
}: ArmorMeshProps) {
const camera = useThree((state) => state.camera);
const { shell } = duel.antagonist;
const material = useRef<ShaderMaterial>(null);
const resolution = new Vector2();
useFrame(({ gl }) => {
useFrame(({ gl, camera }) => {
if (material.current) {
material.current.uniforms.externalModuleMask.value =
externalModuleMaskRenderTarget.texture;
material.current.uniforms.resolution.value = resolution.set(
gl.domElement.width,
gl.domElement.height,
);
material.current.uniforms.externalModuleMask.value =
externalModuleMaskRenderTarget.texture;
material.current.uniforms.spacedArmorDepth.value =
spacedArmorDepthRenderTarget.depthTexture;
material.current.uniforms.projectionMatrixInverse.value =
camera.projectionMatrixInverse;
}
});
@@ -56,8 +62,12 @@ export function ArmorMesh({
fragmentShader={fragmentShader}
vertexShader={vertexShader}
uniforms={{
externalModuleMask: { value: null },
resolution: { value: null },
externalModuleMask: { value: null },
spacedArmorDepth: { value: null },
projectionMatrixInverse: { value: null },
zNear: { value: camera.near },
zFar: { value: camera.far },
isSpaced: { value: isSpaced },
isExplosive: { value: isExplosive(shell.type) },
canSplash: { value: canSplash(shell.type) },
@@ -73,23 +83,6 @@ export function ArmorMesh({
},
}}
/>
{/* <shaderMaterial
ref={material}
depthFunc={EqualDepth}
depthWrite={false}
transparent
args={[
{
vertexShader,
fragmentShader,
uniforms: {
externalModuleMask: { value: null },
resolution: { value: null },
isSpaced: { value: isSpaced },
},
},
]}
/> */}
</mesh>
</>
);
@@ -9,10 +9,27 @@ uniform float caliber;
uniform float ricochet;
uniform float normalization;
uniform sampler2D externalModuleMask;
uniform sampler2D spacedArmorDepth;
uniform vec2 resolution;
varying mat4 vProjectionMatrix;
float depthToDistance(float depth) {
mat4 projectionMatrixInverse = inverse(vProjectionMatrix);
vec4 clipPosition = vec4(gl_FragCoord.xy / resolution * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
vec4 eyePosition = projectionMatrixInverse * clipPosition;
vec3 NDCPosition = eyePosition.xyz / eyePosition.w;
float worldDistance = length(NDCPosition);
return worldDistance;
}
void main() {
vec4 externalModuleMaskColor = texture2D(externalModuleMask, gl_FragCoord.xy / resolution);
vec2 screenCoordinates = gl_FragCoord.xy / resolution;
float spacedArmorDepthValue = texture2D(spacedArmorDepth, screenCoordinates).r;
float currentDistance = depthToDistance(gl_FragCoord.z);
float spacedArmorDistance = depthToDistance(spacedArmorDepthValue);
float distanceFromSpacedArmor = currentDistance - spacedArmorDistance;
vec4 externalModuleMaskColor = texture2D(externalModuleMask, screenCoordinates);
bool isUnderExternalModule = externalModuleMaskColor.r == 1.0;
vec3 normalizedNormal = normalize(vNormal);
vec3 normalizedViewPosition = normalize(vCSMViewPosition);
@@ -27,11 +44,25 @@ void main() {
penetrationChance = 0.0;
splashChance = 0.0;
} else {
float piercedPenetration = penetration;
// if (isUnderExternalModule) {
// // TODO: ADD
// piercedPenetration -= 50.0;
// }
if (isExplosive) {
// 50% loss of remaining penetration per meter
piercedPenetration -= 0.5 * piercedPenetration * distanceFromSpacedArmor;
}
piercedPenetration = max(piercedPenetration, 0.0);
bool twoCalibersRule = caliber > 2.0 * thickness;
float finalNormalization = twoCalibersRule ? (normalization * 1.4 * caliber) / (2.0 * thickness) : normalization;
float finalThickness = thickness / cos(angle - finalNormalization);
float delta = finalThickness - penetration;
float randomRadius = penetration * 0.05;
float delta = finalThickness - piercedPenetration;
float randomRadius = piercedPenetration * 0.05;
if (delta > randomRadius) {
penetrationChance = 0.0;
@@ -43,7 +74,7 @@ void main() {
if (canSplash) {
float reducedFinalThickness = finalThickness * (5.0 / 11.0);
float splashDelta = reducedFinalThickness - penetration;
float splashDelta = reducedFinalThickness - piercedPenetration;
if (splashDelta > randomRadius) {
splashChance = 0.0;
@@ -58,15 +89,17 @@ void main() {
}
if (isSpaced) {
if (isExternalModule) {
csm_FragColor = vec4(0.5, 0.0, 1.0, 0.5);
} else {
if (isExplosive) {
csm_FragColor = vec4(1.0, 0.0, 1.0, 0.5);
} else {
csm_FragColor = vec4(1.0, 0.0, 1.0, (1.0 - penetrationChance) * 0.5);
}
}
// if (isExternalModule) {
// csm_FragColor = vec4(0.5, 0.0, 1.0, 0.5);
// } else {
// if (isExplosive) {
// csm_FragColor = vec4(1.0, 0.0, 1.0, 0.5);
// } else {
// csm_FragColor = vec4(1.0, 0.0, 1.0, (1.0 - penetrationChance) * 0.5);
// }
// }
csm_FragColor = vec4(0.0);
} else {
csm_FragColor = vec4(1.0, splashChance * 0.392, 0.0, (1.0 - penetrationChance) * 0.5);
}
@@ -1,6 +1,12 @@
varying vec3 vCSMViewPosition;
varying float vZ;
varying mat4 vProjectionMatrix;
void main() {
vec4 vViewPosition4 = modelViewMatrix * vec4(position, 1.0);
vCSMViewPosition = vViewPosition4.xyz;
vZ = -(modelViewMatrix * vec4(position, 1.0)).z;
vProjectionMatrix = projectionMatrix;
}
@@ -0,0 +1,19 @@
import { MeshProps } from '@react-three/fiber';
import { WebGLRenderTarget } from 'three';
export const spacedArmorDepthRenderTarget = new WebGLRenderTarget();
interface ArmorMeshSpacedArmorDepthProps extends MeshProps {
exclude?: boolean;
}
export function ArmorMeshSpacedArmorDepth({
exclude = false,
...props
}: ArmorMeshSpacedArmorDepthProps) {
return (
<mesh {...props}>
<meshBasicMaterial />
</mesh>
);
}