This commit is contained in:
tresabhi committed 2026-06-12 20:59:43 -05:00
1 parent 91ac93670f
commit e3cf2d51cc
5 files changed
+120 -50

No files matched your search

@@ -0,0 +1,53 @@
import { times } from "lodash-es";
import { Quicklime } from "quicklime";
import { degToRad, lerp } from "three/src/math/MathUtils.js";
const ANGLE = Math.PI * 2 ** -2;
const LIGHTS_COUNT = 5;
const THETA_OFFSET = degToRad(-152);
const LIGHT_DISTANCE = 13;
const LIGHT_HEIGHT_0 = 4;
const LIGHT_HEIGHT_1 = 2;
const INTENSITY_0 = 3.5;
const INTENSITY_1 = 1.5;
const HEMISPHERE_INTENSITY = 2;
export const transitionEvent = new Quicklime<number>(0);
export function TankopediaLighting() {
return (
<group>
<hemisphereLight
intensity={HEMISPHERE_INTENSITY}
color="#ffffff"
groundColor="#afafaf"
/>
{times(LIGHTS_COUNT, (index) => {
const x = index / (LIGHTS_COUNT - 1);
const theta = 2 * Math.PI * (index / LIGHTS_COUNT) + THETA_OFFSET;
const position = [
LIGHT_DISTANCE * Math.sin(theta),
lerp(LIGHT_HEIGHT_0, LIGHT_HEIGHT_1, x),
LIGHT_DISTANCE * Math.cos(theta),
] as const;
const intensity = lerp(INTENSITY_0, INTENSITY_1, x);
return (
<spotLight
castShadow
userData={{ index }}
key={index}
position={position}
intensity={intensity}
penumbra={1}
decay={0}
color="#ffffff"
angle={ANGLE}
/>
);
})}
</group>
);
}
@@ -1,14 +1,11 @@
import {
VisualChanges_TankPart,
type StageParameters,
} from "@protos/blitz_static_tank_upgrade_single_stage";
import { type StageParameters } from "@protos/blitz_static_tank_upgrade_single_stage";
import { OrbitControls } from "@react-three/drei";
import { Canvas } from "@react-three/fiber";
import { useProtagonist } from "../../hooks/useProtagonist";
import { useTankChassisModel } from "../../hooks/useTankChassisModel";
import { useTankGunModel } from "../../hooks/useTankGunModel";
import { useTankHullModel } from "../../hooks/useTankHullModel";
import { useTankTurretModel } from "../../hooks/useTankTurretModel";
import { TankopediaLighting } from "../TankopediaLighting";
import styles from "./index.module.css";
interface TankopediaSandboxProps {
@@ -33,17 +30,6 @@ export function TankopediaSandbox({ parameters }: TankopediaSandboxProps) {
}
function Content({ parameters }: TankopediaSandboxProps) {
const tank = useProtagonist();
const selectedTurret = parameters.visual_changes.find(
({ tank_part }) => tank_part === VisualChanges_TankPart.TANK_PART_TURRET,
)!.name;
const selectedGun = parameters.visual_changes.find(
({ tank_part }) => tank_part === VisualChanges_TankPart.TANK_PART_GUN,
)!.name;
const collision = false;
const hull = useTankHullModel();
const chassis = useTankChassisModel();
const turret = useTankTurretModel(parameters);
@@ -64,23 +50,11 @@ function Content({ parameters }: TankopediaSandboxProps) {
<primitive object={gun} />
</group>
<spotLight
castShadow
position={[3, 10, 5]}
intensity={2 ** 10}
penumbra={1}
/>
<spotLight
castShadow
position={[-3, -10, -5]}
intensity={2 ** 10}
penumbra={1}
/>
<ambientLight />
<TankopediaLighting />
<mesh receiveShadow rotation={[-Math.PI / 2, 0, 0]}>
<planeGeometry args={[2 ** 8, 2 ** 8]} />
<meshStandardMaterial color="gray" />
<planeGeometry args={[2 ** 9, 2 ** 9]} />
<meshStandardMaterial color="black" />
</mesh>
<OrbitControls />
+27 -17
View File
@@ -1,33 +1,43 @@
import { useLoader } from "@react-three/fiber";
import { useEffect } from "react";
import { Mesh, MeshStandardMaterial } from "three";
import { GLTFLoader } from "three-stdlib";
import { OnObjectUpdate } from "three/src/nodes/utils/EventNode.js";
export function useTankModel(url: string, map: Record<string, boolean>) {
const gltf = useLoader(GLTFLoader, url);
const [root] = gltf.scene.children;
root.traverse((child) => {
if (
child instanceof Mesh &&
child.material instanceof MeshStandardMaterial
) {
// TODO: remove this hack and fix the gltf
child.material.vertexColors = false;
useEffect(() => {
for (const material of Object.values(gltf.materials)) {
if (material instanceof MeshStandardMaterial) {
// TODO: remove this hack and fix the gltf
material.vertexColors = false;
material.needsUpdate = true;
}
}
child.castShadow = true;
child.receiveShadow = true;
});
console.log(gltf.nodes);
for (const child of root.children) {
if (child.name in map) {
child.visible = map[child.name];
continue;
for (const node of Object.values(gltf.nodes)) {
if (node instanceof Mesh) {
node.castShadow = true;
node.receiveShadow = true;
}
}
}, [url]);
child.visible = false;
console.warn(`Root child ${child.name} isn't recognized`);
}
useEffect(() => {
for (const child of root.children) {
if (child.name in map) {
child.visible = map[child.name];
continue;
}
child.visible = false;
console.warn(`Root child ${child.name} isn't recognized`);
}
}, [url, map]);
return root;
}