From 4a6b5e3aa90d4a2ae0ae9cc5c2e384157b75af54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 9 Jan 2024 22:31:34 -0600 Subject: [PATCH] feat: custom shaders --- .../tankopedia/[id]/components/Lighting.tsx | 19 +++++++++ .../[id]/components/Model/TankDisplay.tsx | 5 ++- .../components/Model/components/TankArmor.tsx | 1 + .../TankModel/components/GunContainer.tsx | 28 +++++++++++-- .../TankModel/components/HullContainer.tsx | 42 ++++++++++++++++--- .../TankModel/components/TurretContainer.tsx | 28 +++++++++++-- .../Model/components/TankModel/index.tsx | 15 +++++-- .../tankopedia/[id]/components/SceneProps.tsx | 42 ++++++------------- src/components/ArmorHighlightMaterial.tsx | 42 +++++++++++++++++++ 9 files changed, 176 insertions(+), 46 deletions(-) create mode 100644 src/app/tools/tankopedia/[id]/components/Lighting.tsx create mode 100644 src/components/ArmorHighlightMaterial.tsx diff --git a/src/app/tools/tankopedia/[id]/components/Lighting.tsx b/src/app/tools/tankopedia/[id]/components/Lighting.tsx new file mode 100644 index 000000000..9b6a178f2 --- /dev/null +++ b/src/app/tools/tankopedia/[id]/components/Lighting.tsx @@ -0,0 +1,19 @@ +export function Lighting() { + return ( + <> + + + + + ); +} diff --git a/src/app/tools/tankopedia/[id]/components/Model/TankDisplay.tsx b/src/app/tools/tankopedia/[id]/components/Model/TankDisplay.tsx index abd477c6e..6396db4e6 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TankDisplay.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TankDisplay.tsx @@ -17,9 +17,9 @@ import mutateTankopedia, { } from '../../../../../../stores/tankopedia'; import { Loader } from '../../../../components/Loader'; import { Controls } from '../Control'; +import { Lighting } from '../Lighting'; import { RotationInputs } from '../RotationInputs'; import { SceneProps } from '../SceneProps'; -import { TankArmor } from './components/TankArmor'; import { TankModel } from './components/TankModel'; export function TankDisplay() { @@ -117,9 +117,11 @@ export function TankDisplay() { ref={canvas} camera={{ fov: 20 }} onPointerDown={handlePointerDown} + gl={{ logarithmicDepthBuffer: true }} > + - {mode === 'armor' && } diff --git a/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor.tsx b/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor.tsx index a0e1e29fa..d237b93e6 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor.tsx @@ -68,6 +68,7 @@ export const TankArmor = forwardRef((_props, ref) => { return ( ( pitch, initialTurretRotation, yaw, - objects, + modelObjects, yawLimits, onPitchStart, turretContainer, + armorObjects, pitchLimits, model, onPitchEnd, @@ -59,7 +62,7 @@ export const GunContainer = forwardRef( rotation={[pitch, 0, 0]} ref={gunContainer} > - {objects.map((object) => { + {modelObjects.map((object) => { const isCurrentMantlet = object.name === `gun_${model.toString().padStart(2, '0')}_mask`; const isCurrentGun = @@ -143,6 +146,25 @@ export const GunContainer = forwardRef( /> ); })} + + {armorObjects.map((object) => { + const isCurrentGun = object.name.startsWith( + `gun_${model.toString().padStart(2, '0')}`, + ); + const isVisible = isCurrentGun; + + if (!isVisible) return null; + + return ( + + + + ); + })} ); }, diff --git a/src/app/tools/tankopedia/[id]/components/Model/components/TankModel/components/HullContainer.tsx b/src/app/tools/tankopedia/[id]/components/Model/components/TankModel/components/HullContainer.tsx index a681ad0ed..e3ab0f071 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/components/TankModel/components/HullContainer.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/components/TankModel/components/HullContainer.tsx @@ -1,13 +1,22 @@ import { ThreeEvent, useThree } from '@react-three/fiber'; import { ReactNode, forwardRef, useImperativeHandle, useRef } from 'react'; -import { Group, Mesh, MeshStandardMaterial, Object3D, Vector2 } from 'three'; +import { + Euler, + Group, + Mesh, + MeshStandardMaterial, + Object3D, + Vector2, +} from 'three'; +import { ArmorHighlightMaterial } from '../../../../../../../../../components/ArmorHighlightMaterial'; import { resolveJsxTree } from '../../../../../../../../../core/blitzkrieg/resolveJsxTree'; import { normalizeAnglePI } from '../../../../../../../../../core/math/normalizeAngle180'; interface HullContainerProps { children: ReactNode; yaw: number; - objects: Object3D[]; + modelObjects: Object3D[]; + armorObjects: Object3D[]; onYawStart: () => void; onYawEnd: (yaw: number) => void; onTrackStart: () => void; @@ -16,17 +25,27 @@ interface HullContainerProps { export const HullContainer = forwardRef( ( - { children, yaw, objects, onYawStart, onYawEnd, onTrackEnd, onTrackStart }, + { + children, + yaw, + armorObjects, + modelObjects, + onYawStart, + onYawEnd, + onTrackEnd, + onTrackStart, + }, ref, ) => { const canvas = useThree((state) => state.gl.domElement); const hullContainer = useRef(null); + const rotation = [-Math.PI / 2, 0, yaw] as unknown as Euler; useImperativeHandle(ref, () => hullContainer.current!); return ( - - {objects.map((object) => { + + {modelObjects.map((object) => { const isHull = object.name === 'hull'; const isWheel = object.name.startsWith('chassis_wheel_'); const isTrack = object.name.startsWith('chassis_track_'); @@ -96,6 +115,19 @@ export const HullContainer = forwardRef( ); })} + {armorObjects.map((object) => { + const isHull = object.name.startsWith('hull_'); + const isVisible = isHull; + + if (!isVisible) return null; + + return ( + + + + ); + })} + {children} ); diff --git a/src/app/tools/tankopedia/[id]/components/Model/components/TankModel/components/TurretContainer.tsx b/src/app/tools/tankopedia/[id]/components/Model/components/TankModel/components/TurretContainer.tsx index 1c55c4e78..41e43ba57 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/components/TankModel/components/TurretContainer.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/components/TankModel/components/TurretContainer.tsx @@ -7,6 +7,7 @@ import { useRef, } from 'react'; import { Euler, Group, Mesh, Object3D, Vector3 } from 'three'; +import { ArmorHighlightMaterial } from '../../../../../../../../../components/ArmorHighlightMaterial'; import { applyPitchYawLimits } from '../../../../../../../../../core/blitz/applyPitchYawLimits'; import { InitialTurretRotation, @@ -19,7 +20,8 @@ import { normalizeAnglePI } from '../../../../../../../../../core/math/normalize interface TurretContainerProps { turretOrigin: Vector3; gunOrigin: Vector3; - objects: Object3D[]; + modelObjects: Object3D[]; + armorObjects: Object3D[]; children: ReactNode; yaw: number; pitch: number; @@ -39,12 +41,13 @@ export const TurretContainer = forwardRef( turretOrigin, yaw, children, - objects, + modelObjects, yawLimits, model, onYawEnd, pitch, gunOrigin, + armorObjects, pitchLimits, onYawStart, initialTurretRotation, @@ -78,7 +81,7 @@ export const TurretContainer = forwardRef( return ( - {objects.map((object) => { + {modelObjects.map((object) => { const isTurret = object.name.startsWith('turret_'); const isCurrentTurret = object.name === `turret_${model.toString().padStart(2, '0')}`; @@ -162,6 +165,25 @@ export const TurretContainer = forwardRef( ); })} + {armorObjects.map((object) => { + const isCurrentTurret = object.name.startsWith( + `turret_${model.toString().padStart(2, '0')}`, + ); + const isVisible = isCurrentTurret; + + if (!isVisible) return null; + + return ( + + + + ); + })} + {children} ); diff --git a/src/app/tools/tankopedia/[id]/components/Model/components/TankModel/index.tsx b/src/app/tools/tankopedia/[id]/components/Model/components/TankModel/index.tsx index 427bf1ebf..e5cb06b57 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/components/TankModel/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/components/TankModel/index.tsx @@ -34,10 +34,14 @@ export const TankModel = forwardRef((_props, ref) => { if (!protagonist) return null; - const gltf = useLoader( + const modelGltf = useLoader( GLTFLoader, asset(`3d/tanks/models/${protagonist.tank.id}.glb`), ); + const armorGltf = useLoader( + GLTFLoader, + asset(`3d/tanks/armor/${protagonist.tank.id}.glb`), + ); const model = useTankopedia((state) => state.model); const hullContainer = useRef(null); const turretContainer = useRef(null); @@ -69,7 +73,8 @@ export const TankModel = forwardRef((_props, ref) => { return ( @@ -95,10 +100,11 @@ export const TankModel = forwardRef((_props, ref) => { }} > mutateTankopedia((state) => { @@ -121,6 +127,7 @@ export const TankModel = forwardRef((_props, ref) => { > { mutateTankopedia((state) => { @@ -141,7 +148,7 @@ export const TankModel = forwardRef((_props, ref) => { gunOrigin={gunOrigin} pitch={model.gunPitch} model={gunModelDefinition.model} - objects={Object.values(gltf.nodes)} + modelObjects={Object.values(modelGltf.nodes)} turretOrigin={turretOrigin} /> diff --git a/src/app/tools/tankopedia/[id]/components/SceneProps.tsx b/src/app/tools/tankopedia/[id]/components/SceneProps.tsx index b5d183ae8..f27f34c4c 100644 --- a/src/app/tools/tankopedia/[id]/components/SceneProps.tsx +++ b/src/app/tools/tankopedia/[id]/components/SceneProps.tsx @@ -5,39 +5,23 @@ import { useTankopedia } from '../../../../../stores/tankopedia'; export function SceneProps() { const showGrid = useTankopedia((state) => state.model.showGrid); + if (!showGrid) return null; + return ( <> - {showGrid && ( - <> - - - - )} - - - - ); } diff --git a/src/components/ArmorHighlightMaterial.tsx b/src/components/ArmorHighlightMaterial.tsx new file mode 100644 index 000000000..c7772ee37 --- /dev/null +++ b/src/components/ArmorHighlightMaterial.tsx @@ -0,0 +1,42 @@ +import { GreaterEqualDepth } from 'three'; + +const INFLATE = '0.0'; + +export function ArmorHighlightMaterial() { + return ( + + ); +}