fix: use new model format

This commit is contained in:
TrèsAbhi committed 2024-02-22 12:20:29 -06:00
1 parent 1c3e98678f
commit c68df74943
5 files changed
+108 -185

No files matched your search

@@ -1,5 +1,5 @@
import { memo, useEffect, useRef } from 'react';
import { Euler, Group, Mesh, Vector3 } from 'three';
import { Euler, Group, Vector3 } from 'three';
import { degToRad } from 'three/src/math/MathUtils';
import { ArmorMeshExternalModuleMask } from '../../../../../../../../../components/ArmorMesh';
import { I_HAT, J_HAT, K_HAT } from '../../../../../../../../../constants/axis';
@@ -181,7 +181,7 @@ export const ExternalModuleMask = memo<ExternalModuleMaskProps>(
ornamental={ornamental}
exclude
key={node.uuid}
geometry={(node as Mesh).geometry}
node={node}
/>
);
})}
@@ -200,7 +200,7 @@ export const ExternalModuleMask = memo<ExternalModuleMaskProps>(
maxThickness={maxThickness}
thickness={trackModelDefinition.thickness}
key={node.uuid}
geometry={(node as Mesh).geometry}
node={node}
/>
);
})}
@@ -221,13 +221,14 @@ export const ExternalModuleMask = memo<ExternalModuleMaskProps>(
if (!isVisible || thickness === undefined || spaced) return null;
return (
<ArmorMeshExternalModuleMask
ornamental={ornamental}
exclude
key={node.uuid}
geometry={(node as Mesh).geometry}
position={turretOrigin}
/>
<group position={turretOrigin}>
<ArmorMeshExternalModuleMask
ornamental={ornamental}
exclude
key={node.uuid}
node={node}
/>
</group>
);
})}
</group>
@@ -247,13 +248,14 @@ export const ExternalModuleMask = memo<ExternalModuleMaskProps>(
if (!isVisible || thickness === undefined || spaced) return null;
return (
<ArmorMeshExternalModuleMask
ornamental={ornamental}
exclude
key={node.uuid}
geometry={(node as Mesh).geometry}
position={turretOrigin.clone().add(gunOrigin)}
/>
<group position={turretOrigin.clone().add(gunOrigin)}>
<ArmorMeshExternalModuleMask
ornamental={ornamental}
exclude
key={node.uuid}
node={node}
/>
</group>
);
})}
@@ -271,7 +273,7 @@ export const ExternalModuleMask = memo<ExternalModuleMaskProps>(
maxThickness={maxThickness}
thickness={gunModelDefinition.thickness}
key={node.uuid}
geometry={(node as Mesh).geometry}
node={node}
/>
);
})}
@@ -1,16 +1,10 @@
import { ThreeEvent, useThree } from '@react-three/fiber';
import { memo, useEffect, useRef, useState } from 'react';
import {
Euler,
Group,
Mesh,
MeshStandardMaterial,
Vector2,
Vector3,
} from 'three';
import { Euler, Group, Vector3 } from 'three';
import { degToRad } from 'three/src/math/MathUtils';
import { I_HAT, J_HAT, K_HAT } from '../../../../../../../constants/axis';
import { applyPitchYawLimits } from '../../../../../../../core/blitz/applyPitchYawLimits';
import { jsxTree } from '../../../../../../../core/blitzkrieg/jsxTree';
import {
ModelDefinitions,
modelDefinitions,
@@ -19,7 +13,6 @@ import {
ModelTransformEventData,
modelTransformEvent,
} from '../../../../../../../core/blitzkrieg/modelTransform';
import { resolveJsxTree } from '../../../../../../../core/blitzkrieg/resolveJsxTree';
import { normalizeAnglePI } from '../../../../../../../core/math/normalizeAngle180';
import { useModel } from '../../../../../../../hooks/useModel';
import { useDuel } from '../../../../../../../stores/duel';
@@ -138,58 +131,12 @@ export const TankModel = memo(() => {
const isTrack = node.name.startsWith('chassis_track_');
const isVisible = isHull || isWheel || isTrack;
function handlePointerDown(event: ThreeEvent<PointerEvent>) {
event.stopPropagation();
if (isTrack) {
mutateTankopediaPersistent((draft) => {
draft.model.visual.controlsEnabled = false;
});
mutateTankopediaTemporary((draft) => {
draft.shot = undefined;
});
window.addEventListener('pointermove', handlePointerMove);
window.addEventListener('pointerup', handlePointerUp);
}
}
function handlePointerMove(event: PointerEvent) {
const mesh = node as Mesh;
const material = mesh.material as MeshStandardMaterial;
const offset = new Vector2(
0,
-event.movementY * (6 / canvas.height) -
event.movementX * (6 / canvas.width),
);
material.map?.offset.add(offset);
material.roughnessMap?.offset.add(offset);
material.normalMap?.offset.add(offset);
}
function handlePointerUp() {
mutateTankopediaPersistent((draft) => {
draft.model.visual.controlsEnabled = true;
});
window.removeEventListener('pointermove', handlePointerMove);
window.removeEventListener('pointerup', handlePointerUp);
}
if (!isVisible) return null;
return (
<mesh
children={resolveJsxTree(node)}
key={node.uuid}
castShadow
receiveShadow
geometry={(node as Mesh).geometry}
material={(node as Mesh).material}
position={node.position}
rotation={node.rotation}
scale={node.scale}
onPointerDown={handlePointerDown}
/>
);
return jsxTree(node, {
castShadow: true,
receiveShadow: true,
});
})}
<group ref={turretContainer}>
@@ -199,10 +146,13 @@ export const TankModel = memo(() => {
node.name ===
`turret_${turretModelDefinition.model.toString().padStart(2, '0')}`;
const isVisible = isCurrentTurret;
if (!isVisible) return null;
let pitch = 0;
let yaw = 0;
function handlePointerDown(event: ThreeEvent<PointerEvent>) {
function onPointerDown(event: ThreeEvent<PointerEvent>) {
event.stopPropagation();
if (isTurret) {
@@ -240,23 +190,11 @@ export const TankModel = memo(() => {
window.removeEventListener('pointerup', handlePointerUp);
}
if (!isVisible) return null;
return (
<mesh
visible={isVisible}
onPointerDown={handlePointerDown}
children={resolveJsxTree(node)}
key={node.uuid}
castShadow
receiveShadow
geometry={(node as Mesh).geometry}
material={(node as Mesh).material}
position={node.position}
rotation={node.rotation}
scale={node.scale}
/>
);
return jsxTree(node, {
castShadow: true,
receiveShadow: true,
onPointerDown,
});
})}
<group ref={gunContainer}>
@@ -270,10 +208,13 @@ export const TankModel = memo(() => {
node.name ===
`gun_${gunModelDefinition.model.toString().padStart(2, '0')}`;
const isVisible = isCurrentGun || isCurrentMantlet;
if (!isVisible) return null;
let pitch = 0;
let yaw = 0;
function handlePointerDown(event: ThreeEvent<PointerEvent>) {
function onPointerDown(event: ThreeEvent<PointerEvent>) {
event.stopPropagation();
mutateTankopediaPersistent((draft) => {
@@ -308,23 +249,11 @@ export const TankModel = memo(() => {
window.removeEventListener('pointerup', handlePointerUp);
}
if (!isVisible) return null;
return (
<mesh
visible={isVisible}
onPointerDown={handlePointerDown}
children={resolveJsxTree(node)}
key={node.uuid}
castShadow
receiveShadow
geometry={(node as Mesh).geometry}
material={(node as Mesh).material}
position={node.position}
rotation={node.rotation}
scale={node.scale}
/>
);
return jsxTree(node, {
castShadow: true,
receiveShadow: true,
onPointerDown,
});
})}
</group>
</group>
@@ -1,53 +1,52 @@
import { MeshProps } from '@react-three/fiber';
import { Color, WebGLRenderTarget } from 'three';
import { Color, MeshBasicMaterial, Object3D, WebGLRenderTarget } from 'three';
import { jsxTree } from '../../../core/blitzkrieg/jsxTree';
import { ArmorMeshUserData } from './Armor';
export const externalModuleMaskRenderTarget = new WebGLRenderTarget();
type ArmorMeshExternalModuleMaskProps = MeshProps & {
type ArmorMeshExternalModuleMaskProps = {
ornamental?: boolean;
node: Object3D;
} & (
| {
exclude?: false;
maxThickness: number;
thickness: number;
}
| {
exclude: true;
}
);
| {
exclude?: false;
maxThickness: number;
thickness: number;
}
| {
exclude: true;
}
);
const excludeMaterial = new MeshBasicMaterial({
colorWrite: false,
});
export function ArmorMeshExternalModuleMask({
ornamental = false,
node,
...props
}: ArmorMeshExternalModuleMaskProps) {
return (
<>
{props.exclude && !ornamental && (
<mesh {...props} renderOrder={0}>
<meshBasicMaterial colorWrite={false} />
</mesh>
)}
{props.exclude &&
!ornamental &&
jsxTree(node, { renderOrder: 0, material: excludeMaterial })}
{!props.exclude && (
<mesh
{...props}
renderOrder={1}
onClick={ornamental ? () => {} : undefined}
userData={
{
type: 'externalModule',
thickness: props.thickness,
} satisfies ArmorMeshUserData
}
>
<meshBasicMaterial
color={new Color(1, props.thickness / props.maxThickness, 0)}
depthWrite={false}
colorWrite={!ornamental}
/>
</mesh>
)}
{!props.exclude &&
jsxTree(node, {
renderOrder: 1,
onClick: ornamental ? () => {} : undefined,
userData: {
type: 'externalModule',
thickness: props.thickness,
} satisfies ArmorMeshUserData,
material: new MeshBasicMaterial({
color: new Color(1, props.thickness / props.maxThickness, 0),
depthWrite: false,
colorWrite: !ornamental,
}),
})}
</>
);
}
+29
View File
@@ -0,0 +1,29 @@
import { MeshProps } from '@react-three/fiber';
import { Mesh, Object3D } from 'three';
export function jsxTree(node: Object3D, mesh?: MeshProps) {
if (node instanceof Mesh) {
return (
<mesh
geometry={node.geometry}
material={node.material}
position={node.position}
rotation={node.rotation}
scale={node.scale}
{...mesh}
/>
);
} else if (node instanceof Object3D) {
return (
<group
position={node.position}
rotation={node.rotation}
scale={node.scale}
>
{node.children.map((child) => jsxTree(child, mesh))}
</group>
);
}
return null;
}
-36
View File
@@ -1,36 +0,0 @@
import { Mesh, Object3D } from 'three';
export function resolveJsxTree(parent: Object3D) {
return parent.children.map((child) => {
if (child.type === 'Mesh') {
return (
<mesh
key={child.uuid}
castShadow
receiveShadow
geometry={(child as Mesh).geometry}
material={(child as Mesh).material}
position={child.position}
rotation={child.rotation}
scale={child.scale}
children={resolveJsxTree(child)}
/>
);
}
if (child.type === 'Object3D') {
return (
<group
key={child.uuid}
position={child.position}
rotation={child.rotation}
scale={child.scale}
children={resolveJsxTree(child)}
/>
);
}
throw new TypeError(
`Unhandled three jsx type ${child.type} (${child.name})`,
);
});
}