mirror of
https://github.com/exogen/t2-mapper.git
synced 2026-03-25 23:29:26 +00:00
split up demo modules, improve death support
This commit is contained in:
parent
359a036558
commit
c5b43f2e55
39 changed files with 2269 additions and 3942 deletions
125
src/components/DemoShapeModel.tsx
Normal file
125
src/components/DemoShapeModel.tsx
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
import { useMemo } from "react";
|
||||
import { Quaternion, Vector3 } from "three";
|
||||
import {
|
||||
_r90,
|
||||
_r90inv,
|
||||
getPosedNodeTransform,
|
||||
} from "../demo/demoPlaybackUtils";
|
||||
import {
|
||||
ShapeRenderer,
|
||||
useStaticShape,
|
||||
} from "./GenericShape";
|
||||
import { ShapeInfoProvider } from "./ShapeInfoProvider";
|
||||
import type { TorqueObject } from "../torqueScript";
|
||||
|
||||
/** Renders a shape model for a demo entity using the existing shape pipeline. */
|
||||
export function DemoShapeModel({
|
||||
shapeName,
|
||||
entityId,
|
||||
}: {
|
||||
shapeName: string;
|
||||
entityId: number | string;
|
||||
}) {
|
||||
const torqueObject = useMemo<TorqueObject>(
|
||||
() => ({
|
||||
_class: "player",
|
||||
_className: "Player",
|
||||
_id: typeof entityId === "number" ? entityId : 0,
|
||||
}),
|
||||
[entityId],
|
||||
);
|
||||
|
||||
return (
|
||||
<ShapeInfoProvider
|
||||
object={torqueObject}
|
||||
shapeName={shapeName}
|
||||
type="StaticShape"
|
||||
>
|
||||
<ShapeRenderer loadingColor="#00ff88" />
|
||||
</ShapeInfoProvider>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a mounted weapon using the Torque engine's mount system.
|
||||
*
|
||||
* The weapon's `Mountpoint` node is aligned to the player's `Mount0` node
|
||||
* (right hand). Both nodes come from the GLB skeleton in its idle ("Root"
|
||||
* animation) pose. The mount transform is conjugated by ShapeRenderer's 90° Y
|
||||
* rotation: T_mount = R90 * M0 * MP^(-1) * R90^(-1).
|
||||
*/
|
||||
export function DemoWeaponModel({
|
||||
shapeName,
|
||||
playerShapeName,
|
||||
}: {
|
||||
shapeName: string;
|
||||
playerShapeName: string;
|
||||
}) {
|
||||
const playerGltf = useStaticShape(playerShapeName);
|
||||
const weaponGltf = useStaticShape(shapeName);
|
||||
|
||||
const mountTransform = useMemo(() => {
|
||||
// Get Mount0 from the player's posed (Root animation) skeleton.
|
||||
const m0 = getPosedNodeTransform(
|
||||
playerGltf.scene,
|
||||
playerGltf.animations,
|
||||
"Mount0",
|
||||
);
|
||||
if (!m0) return { position: undefined, quaternion: undefined };
|
||||
|
||||
// Get Mountpoint from weapon (may not be animated).
|
||||
const mp = getPosedNodeTransform(
|
||||
weaponGltf.scene,
|
||||
weaponGltf.animations,
|
||||
"Mountpoint",
|
||||
);
|
||||
|
||||
// Compute T_mount = R90 * M0 * MP^(-1) * R90^(-1)
|
||||
// This conjugates the GLB-space mount transform by ShapeRenderer's 90° Y
|
||||
// rotation so the weapon is correctly oriented in entity space.
|
||||
let combinedPos: Vector3;
|
||||
let combinedQuat: Quaternion;
|
||||
|
||||
if (mp) {
|
||||
// MP^(-1)
|
||||
const mpInvQuat = mp.quaternion.clone().invert();
|
||||
const mpInvPos = mp.position.clone().negate().applyQuaternion(mpInvQuat);
|
||||
|
||||
// M0 * MP^(-1)
|
||||
combinedQuat = m0.quaternion.clone().multiply(mpInvQuat);
|
||||
combinedPos = mpInvPos
|
||||
.clone()
|
||||
.applyQuaternion(m0.quaternion)
|
||||
.add(m0.position);
|
||||
} else {
|
||||
combinedPos = m0.position.clone();
|
||||
combinedQuat = m0.quaternion.clone();
|
||||
}
|
||||
|
||||
// R90 * combined * R90^(-1)
|
||||
const mountPos = combinedPos.applyQuaternion(_r90);
|
||||
const mountQuat = _r90.clone().multiply(combinedQuat).multiply(_r90inv);
|
||||
|
||||
return { position: mountPos, quaternion: mountQuat };
|
||||
}, [playerGltf, weaponGltf]);
|
||||
|
||||
const torqueObject = useMemo<TorqueObject>(
|
||||
() => ({
|
||||
_class: "weapon",
|
||||
_className: "Weapon",
|
||||
_id: 0,
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
return (
|
||||
<ShapeInfoProvider object={torqueObject} shapeName={shapeName} type="Item">
|
||||
<group
|
||||
position={mountTransform.position}
|
||||
quaternion={mountTransform.quaternion}
|
||||
>
|
||||
<ShapeRenderer loadingColor="#4488ff" />
|
||||
</group>
|
||||
</ShapeInfoProvider>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue