mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
fix: directional clip
This commit is contained in:
1 parent
b559878667
commit
6bcf5c25dc
6 files changed
+149
-31
No files matched your search
Vendored
+2
@@ -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',
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -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]));
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
Reference in new issue
Block a user