fix: directional clip

This commit is contained in:
TrèsAbhi committed 2024-08-02 13:48:24 -05:00
1 parent b559878667
commit 6bcf5c25dc
6 files changed
+149 -31

No files matched your search

+2
View File
@@ -41,6 +41,7 @@
"CUBETEXCOORD",
"customperiod",
"datasource",
"Dava",
"dbid",
"Ddpf",
"Ddsd",
@@ -169,6 +170,7 @@
"UNORM",
"unpickled",
"Unregistering",
"unrotate",
"vickers",
"vitepress",
"Vovko",
@@ -1,4 +1,4 @@
import { useThree } from '@react-three/fiber';
import { MeshProps, useThree } from '@react-three/fiber';
import { clamp } from 'lodash';
import { useEffect, useMemo } from 'react';
import {
@@ -12,8 +12,15 @@ import {
Object3D,
Plane,
Quaternion,
Vector3,
} from 'three';
import { I_HAT, J_HAT } from '../../../constants/axis';
import { unrotateDavaVector } from '../../../core/blitz/unrotateDavaVector';
import { jsxTree } from '../../../core/blitzkit/jsxTree';
import {
modelTransformEvent,
ModelTransformEventData,
} from '../../../core/blitzkit/modelTransform';
import { discardClippingPlane } from '../../../core/three/discardClippingPlane';
import * as TankopediaEphemeral from '../../../stores/tankopediaEphemeral';
import { ThicknessRange } from '../../StaticArmor';
@@ -25,10 +32,10 @@ import {
type StaticArmorSceneComponentProps = {
name: string;
clip?: Plane;
thickness: number;
thicknessRange: ThicknessRange;
node: Object3D;
onPointerDown?: MeshProps['onPointerDown'];
} & (
| {
type: Exclude<ArmorType, ArmorType.External>;
@@ -37,7 +44,18 @@ type StaticArmorSceneComponentProps = {
type: ArmorType.External;
variant: ExternalModuleVariant;
}
);
) &
(
| {
clip?: undefined;
}
| {
clip: Plane;
hullOrigin: Vector3;
turretOrigin: Vector3;
gunOrigin: Vector3;
}
);
const unselectedColor = new Color(0x404040);
const externalModuleColor = new Color(0, 1 / 4, 1 / 2);
@@ -47,13 +65,13 @@ export function StaticArmorSceneComponent({
thickness,
thicknessRange,
node,
clip,
onPointerDown,
...props
}: StaticArmorSceneComponentProps) {
const mutateTankopediaEphemeralStore = TankopediaEphemeral.useMutation();
const tankopediaEphemeralStore = TankopediaEphemeral.useStore();
const camera = useThree((state) => state.camera);
const scene = useThree((state) => state.scene);
const x = thickness / thicknessRange.value;
const xClamped = clamp(x, 0, 1);
let color: Color;
@@ -95,7 +113,7 @@ export function StaticArmorSceneComponent({
opacity,
transparent: opacity < 1,
depthWrite,
...(clip ? { clippingPlanes: [clip] } : {}),
...(props.clip ? { clippingPlanes: [props.clip] } : {}),
}),
[thickness],
);
@@ -109,19 +127,6 @@ export function StaticArmorSceneComponent({
[thickness],
);
// if (clip) {
// /**
// * hook inside an if statement?? don't panic! I assure you the clip prop
// * never mutates :)
// */
// useFrame(() => {
// surfaceMaterial.clippingPlanes!.forEach((plane) => {
// // console.log(plane.normal);
// plane.applyMatrix4(node.matrix);
// });
// });
// }
useEffect(() => {
function handleHighlightArmor(selectedName?: string) {
if (selectedName === undefined) {
@@ -160,18 +165,59 @@ export function StaticArmorSceneComponent({
surfaceMaterial.needsUpdate = true;
}
const unsubscribe = tankopediaEphemeralStore.subscribe(
(state) => state.highlightArmor?.name,
handleHighlightArmor,
);
const unsubscribes = [
tankopediaEphemeralStore.subscribe(
(state) => state.highlightArmor?.name,
handleHighlightArmor,
),
];
return unsubscribe;
if (props.clip) {
/**
* hook inside an if statement?? don't panic! I assure you the clip prop
* never mutates :)
*/
const { clip } = props;
const gunOrigin = unrotateDavaVector(props.gunOrigin.clone());
const neckOrigin = unrotateDavaVector(props.hullOrigin.clone()).add(
unrotateDavaVector(props.turretOrigin.clone()),
);
const barrelOrigin = neckOrigin.clone().add(gunOrigin);
const distanceToBarrel = clip.distanceToPoint(barrelOrigin);
const point = new Vector3();
function handleModelTransform(data: ModelTransformEventData) {
clip.normal
.set(0, 0, -1)
.applyAxisAngle(I_HAT, data.pitch)
.applyAxisAngle(J_HAT, data.yaw ?? 0);
clip.constant = 0;
point
.copy(gunOrigin)
.applyAxisAngle(J_HAT, data.yaw ?? 0)
.add(clip.normal.multiplyScalar(-distanceToBarrel))
.add(neckOrigin);
clip.normal.normalize();
clip.constant -= clip.distanceToPoint(point);
}
modelTransformEvent.on(handleModelTransform);
unsubscribes.push(() => modelTransformEvent.off(handleModelTransform));
}
return () => {
unsubscribes.forEach((unsubscribe) => unsubscribe());
};
}, [thickness]);
return (
<>
{jsxTree(node, {
material: surfaceMaterial,
onPointerDown,
userData: {
type: props.type,
variant: props.type === ArmorType.External ? props.variant : 'gun',
+63 -2
View File
@@ -197,7 +197,7 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
}
return (
<group position={hullOrigin} onPointerDown={onPointerDown}>
<group position={hullOrigin}>
<group key={node.uuid} position={turretOrigin}>
<StaticArmorSceneComponent
name={node.name}
@@ -206,6 +206,7 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
type={spaced ? ArmorType.Spaced : ArmorType.Primary}
thickness={thickness}
node={node}
onPointerDown={onPointerDown}
/>
</group>
</group>
@@ -289,7 +290,7 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
}
return (
<group position={hullOrigin} onPointerDown={onPointerDown}>
<group position={hullOrigin}>
<group
key={node.uuid}
position={turretOrigin.clone().add(gunOrigin)}
@@ -300,6 +301,7 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
type={spaced ? ArmorType.Spaced : ArmorType.Primary}
thickness={thickness}
node={node}
onPointerDown={onPointerDown}
/>
</group>
</group>
@@ -315,6 +317,61 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
if (!isVisible || !showExternalModules) return null;
const position = new Vector2();
const delta = new Vector2();
let pitch = 0;
let yaw = 0;
function onPointerDown(event: ThreeEvent<PointerEvent>) {
event.stopPropagation();
mutateTankopediaEphemeral((draft) => {
draft.controlsEnabled = false;
});
mutateTankopediaEphemeral((draft) => {
draft.shot = undefined;
draft.highlightArmor = undefined;
});
position.set(event.clientX, event.clientY);
pitch = protagonist.pitch;
yaw = protagonist.yaw;
window.addEventListener('pointermove', handlePointerMove);
window.addEventListener('pointerup', handlePointerUp);
}
async function handlePointerMove(event: PointerEvent) {
const duel = duelStore.getState();
const hasImprovedVerticalStabilizer = await hasEquipment(
122,
duel.protagonist.tank.equipment,
duel.protagonist.equipmentMatrix,
);
const boundingRect = canvas.getBoundingClientRect();
delta.set(event.clientX, event.clientY).sub(position);
position.set(event.clientX, event.clientY);
[pitch, yaw] = applyPitchYawLimits(
pitch - delta.y * (Math.PI / boundingRect.height),
yaw + delta.x * (Math.PI / boundingRect.width),
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
);
modelTransformEvent.emit({ pitch, yaw });
}
function handlePointerUp() {
mutateTankopediaEphemeral((draft) => {
draft.controlsEnabled = true;
});
mutateDuel((draft) => {
draft.protagonist.pitch = normalizeAngleRad(pitch);
draft.protagonist.yaw = normalizeAngleRad(yaw);
});
window.removeEventListener('pointermove', handlePointerMove);
window.removeEventListener('pointerup', handlePointerUp);
}
return (
<StaticArmorSceneComponent
name={node.name}
@@ -329,6 +386,10 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
? undefined
: new Plane(new Vector3(0, 0, -1), -maskOrigin)
}
hullOrigin={hullOrigin}
turretOrigin={turretOrigin}
gunOrigin={gunOrigin}
onPointerDown={onPointerDown}
/>
);
})}
+2 -5
View File
@@ -1,9 +1,6 @@
import { Vector3, Vector3Tuple } from 'three';
import { I_HAT } from '../../constants/axis';
import { rotateDavaVector } from './rotateDavaVector';
export function correctZYTuple(tuple: Vector3Tuple) {
return new Vector3(tuple[0], tuple[1], -tuple[2]).applyAxisAngle(
I_HAT,
Math.PI / 2,
);
return rotateDavaVector(new Vector3(tuple[0], tuple[1], -tuple[2]));
}
+6
View File
@@ -0,0 +1,6 @@
import { Vector3 } from 'three';
import { I_HAT } from '../../constants/axis';
export function rotateDavaVector(vector: Vector3) {
return vector.applyAxisAngle(I_HAT, Math.PI / 2);
}
+6
View File
@@ -0,0 +1,6 @@
import { Vector3 } from 'three';
import { I_HAT } from '../../constants/axis';
export function unrotateDavaVector(vector: Vector3) {
return vector.applyAxisAngle(I_HAT, -Math.PI / 2);
}