mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
fix: use new model format
This commit is contained in:
1 parent
1c3e98678f
commit
c68df74943
5 files changed
+108
-185
No files matched your search
+20
-18
@@ -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,
|
||||
}),
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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})`,
|
||||
);
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user