mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
lighting
This commit is contained in:
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 />
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in new issue
Block a user