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