feat: accurate external module thickness

This commit is contained in:
TrèsAbhi committed 2024-01-16 09:05:07 -06:00
1 parent ae267adf27
commit 578f6f4d0f
5 files changed
+53 -19

No files matched your search

@@ -115,13 +115,8 @@ export function ArmorHighlighting({ duel }: ArmorHighlightingProps) {
GLTFLoader,
asset(`3d/tanks/armor/${duel.protagonist.tank.id}.glb`),
);
const modelGltf = useLoader(
GLTFLoader,
asset(`3d/tanks/models/${duel.protagonist.tank.id}.glb`),
);
const armorNodes = Object.values(armorGltf.nodes);
const modelNodes = Object.values(modelGltf.nodes);
const tankModelDefinition = awaitedModelDefinitions[duel.protagonist.tank.id];
const turretModelDefinition =
tankModelDefinition.turrets[duel.protagonist.turret.id];
@@ -137,6 +132,10 @@ export function ArmorHighlighting({ duel }: ArmorHighlightingProps) {
turretModelDefinition.gunOrigin[1],
-turretModelDefinition.gunOrigin[2],
).applyAxisAngle(X_AXIS, Math.PI / 2);
const maxExternalModuleThickness = Math.max(
tankModelDefinition.trackThickness,
gunModelDefinition.barrelThickness,
);
return (
<group
@@ -162,6 +161,7 @@ export function ArmorHighlighting({ duel }: ArmorHighlightingProps) {
return (
<ArmorMesh
maxExternalModuleThickness={maxExternalModuleThickness}
duel={duel}
key={node.uuid}
geometry={(node as Mesh).geometry}
@@ -192,6 +192,7 @@ export function ArmorHighlighting({ duel }: ArmorHighlightingProps) {
return (
<ArmorMesh
maxExternalModuleThickness={maxExternalModuleThickness}
duel={duel}
key={node.uuid}
geometry={(node as Mesh).geometry}
@@ -222,6 +223,7 @@ export function ArmorHighlighting({ duel }: ArmorHighlightingProps) {
return (
<ArmorMesh
maxExternalModuleThickness={maxExternalModuleThickness}
duel={duel}
key={node.uuid}
geometry={(node as Mesh).geometry}
@@ -24,6 +24,13 @@ interface ExternalModuleMaskProps {
duel: Duel;
}
/**
* When rendered, generates a mask and thickness buffer for external modules.
* - R: 0 means not external module
* - G: normalized thickness; multiply with max thickness to get nominal thickness
* - B: no data
* - A: 1 means is armor; 0 is background
*/
export const ExternalModuleMask = memo<ExternalModuleMaskProps>(({ duel }) => {
const wrapper = useRef<Group>(null);
const awaitedModelDefinitions = useModelDefinitions();
@@ -127,6 +134,10 @@ export const ExternalModuleMask = memo<ExternalModuleMaskProps>(({ duel }) => {
tankModelDefinition.turrets[duel.protagonist.turret.id];
const gunModelDefinition =
turretModelDefinition.guns[duel.protagonist.gun.id];
const maxThickness = Math.max(
tankModelDefinition.trackThickness,
gunModelDefinition.barrelThickness,
);
const turretOrigin = new Vector3(
tankModelDefinition.turretOrigin[0],
tankModelDefinition.turretOrigin[1],
@@ -178,6 +189,8 @@ export const ExternalModuleMask = memo<ExternalModuleMaskProps>(({ duel }) => {
return (
<ArmorMeshExternalModuleMask
maxThickness={maxThickness}
thickness={tankModelDefinition.trackThickness}
key={node.uuid}
geometry={(node as Mesh).geometry}
/>
@@ -251,6 +264,8 @@ export const ExternalModuleMask = memo<ExternalModuleMaskProps>(({ duel }) => {
return (
<ArmorMeshExternalModuleMask
maxThickness={maxThickness}
thickness={gunModelDefinition.barrelThickness}
key={node.uuid}
geometry={(node as Mesh).geometry}
/>
@@ -17,12 +17,14 @@ interface ArmorMeshProps extends MeshProps {
isSpaced: boolean;
isExternalModule?: boolean;
thickness: number;
maxExternalModuleThickness: number;
}
export function ArmorMesh({
isSpaced,
isExternalModule = false,
thickness,
maxExternalModuleThickness,
duel,
...props
}: ArmorMeshProps) {
@@ -68,6 +70,7 @@ export function ArmorMesh({
projectionMatrixInverse: { value: null },
zNear: { value: camera.near },
zFar: { value: camera.far },
maxExternalModuleThickness: { value: maxExternalModuleThickness },
isSpaced: { value: isSpaced },
isExplosive: { value: isExplosive(shell.type) },
canSplash: { value: canSplash(shell.type) },
@@ -12,6 +12,7 @@ uniform sampler2D externalModuleMask;
uniform sampler2D spacedArmorDepth;
uniform vec2 resolution;
varying mat4 vProjectionMatrix;
uniform float maxExternalModuleThickness;
float depthToDistance(float depth) {
mat4 projectionMatrixInverse = inverse(vProjectionMatrix);
@@ -46,10 +47,11 @@ void main() {
} else {
float piercedPenetration = penetration;
// if (isUnderExternalModule) {
// // TODO: ADD
// piercedPenetration -= 50.0;
// }
if (isUnderExternalModule) {
float normalizedExternalModuleThickness = externalModuleMaskColor.g;
float externalModuleThickness = normalizedExternalModuleThickness * maxExternalModuleThickness;
piercedPenetration -= externalModuleThickness;
}
if (isExplosive) {
// 50% loss of remaining penetration per meter
@@ -3,25 +3,37 @@ import { WebGLRenderTarget } from 'three';
export const externalModuleMaskRenderTarget = new WebGLRenderTarget();
interface ArmorMeshExternalModuleMaskProps extends MeshProps {
exclude?: boolean;
}
type ArmorMeshExternalModuleMaskProps = MeshProps &
(
| {
exclude?: false;
maxThickness: number;
thickness: number;
}
| {
exclude: true;
}
);
export function ArmorMeshExternalModuleMask({
exclude = false,
...props
}: ArmorMeshExternalModuleMaskProps) {
export function ArmorMeshExternalModuleMask(
props: ArmorMeshExternalModuleMaskProps,
) {
return (
<>
{exclude && (
{props.exclude && (
<mesh {...props} renderOrder={0}>
<meshBasicMaterial colorWrite={false} />
</mesh>
)}
{!exclude && (
{!props.exclude && (
<mesh {...props} renderOrder={1}>
<meshBasicMaterial color="#ff0000" depthWrite={false} />
<meshBasicMaterial
color={`rgb(255, ${
(props.thickness / props.maxThickness) * 255
}, 0)`}
depthWrite={false}
/>
</mesh>
)}
</>