mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
feat: overhead lighting
This commit is contained in:
1 parent
fced1e96ef
commit
344e7caa81
3 files changed
+55
-34
No files matched your search
@@ -12,6 +12,7 @@ import {
|
|||||||
EyeOpenIcon,
|
EyeOpenIcon,
|
||||||
ShadowInnerIcon,
|
ShadowInnerIcon,
|
||||||
ShadowNoneIcon,
|
ShadowNoneIcon,
|
||||||
|
SunIcon,
|
||||||
} from "@radix-ui/react-icons";
|
} from "@radix-ui/react-icons";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@@ -73,6 +74,7 @@ export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
|
|||||||
const { strings, unwrap } = useLocale();
|
const { strings, unwrap } = useLocale();
|
||||||
const revealed = Tankopedia.use((state) => state.revealed);
|
const revealed = Tankopedia.use((state) => state.revealed);
|
||||||
const disturbed = Tankopedia.use((state) => state.disturbed);
|
const disturbed = Tankopedia.use((state) => state.disturbed);
|
||||||
|
const highGraphics = TankopediaPersistent.use((state) => state.highGraphics);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -349,6 +351,20 @@ export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
|
|||||||
</DropdownMenu.Content>
|
</DropdownMenu.Content>
|
||||||
</DropdownMenu.Root>
|
</DropdownMenu.Root>
|
||||||
|
|
||||||
|
<IconButton
|
||||||
|
size="2"
|
||||||
|
highContrast
|
||||||
|
onClick={() => {
|
||||||
|
TankopediaPersistent.mutate((draft) => {
|
||||||
|
draft.highGraphics = !draft.highGraphics;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
color={highGraphics ? undefined : "gray"}
|
||||||
|
variant={highGraphics ? "solid" : "surface"}
|
||||||
|
>
|
||||||
|
<SunIcon />
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
<ScreenshotButton
|
<ScreenshotButton
|
||||||
color="gray"
|
color="gray"
|
||||||
size="2"
|
size="2"
|
||||||
|
|||||||
+37
-34
@@ -1,15 +1,24 @@
|
|||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
|
import { times } from "lodash-es";
|
||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { HemisphereLight, SpotLight, type Group } from "three";
|
import { SpotLight, type Group } from "three";
|
||||||
import { clamp } from "three/src/math/MathUtils.js";
|
import { clamp, degToRad, lerp } from "three/src/math/MathUtils.js";
|
||||||
import { Tankopedia } from "../../../../../../stores/tankopedia";
|
import { Tankopedia } from "../../../../../../stores/tankopedia";
|
||||||
|
import { TankopediaPersistent } from "../../../../../../stores/tankopediaPersistent";
|
||||||
import { HelpingSpotLight } from "../../../../../HelpingSpotLight";
|
import { HelpingSpotLight } from "../../../../../HelpingSpotLight";
|
||||||
|
|
||||||
const ANGLE = Math.PI / 3;
|
const ANGLE = Math.PI / 3;
|
||||||
const HEMISPHERE_INTENSITY = 4;
|
const REVEAL_ANIMATION_TIME = 3;
|
||||||
const REVEAL_ANIMATION_TIME = 5;
|
|
||||||
const TRANSITION_ANIMATION_TIME = 0.5;
|
const TRANSITION_ANIMATION_TIME = 0.5;
|
||||||
|
|
||||||
|
const LIGHTS_COUNT = 4;
|
||||||
|
const THETA_OFFSET = degToRad(-150);
|
||||||
|
const LIGHT_DISTANCE = 13;
|
||||||
|
const LIGHT_HEIGHT_0 = 4;
|
||||||
|
const LIGHT_HEIGHT_1 = 8;
|
||||||
|
const INTENSITY_0 = 70;
|
||||||
|
const INTENSITY_1 = 40;
|
||||||
|
|
||||||
export function Lighting() {
|
export function Lighting() {
|
||||||
const wrapper = useRef<Group>(null!);
|
const wrapper = useRef<Group>(null!);
|
||||||
const t0 = useRef(0);
|
const t0 = useRef(0);
|
||||||
@@ -17,6 +26,7 @@ export function Lighting() {
|
|||||||
const display = Tankopedia.use((state) => state.display);
|
const display = Tankopedia.use((state) => state.display);
|
||||||
const requestedDisplay = Tankopedia.use((state) => state.requestedDisplay);
|
const requestedDisplay = Tankopedia.use((state) => state.requestedDisplay);
|
||||||
const animationTime = useRef(REVEAL_ANIMATION_TIME);
|
const animationTime = useRef(REVEAL_ANIMATION_TIME);
|
||||||
|
const highGraphics = TankopediaPersistent.use((state) => state.highGraphics);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Tankopedia.mutate((draft) => {
|
Tankopedia.mutate((draft) => {
|
||||||
@@ -35,9 +45,7 @@ export function Lighting() {
|
|||||||
const t = 0.5 * Math.sin(Math.PI * (x + 0.5)) + 0.5;
|
const t = 0.5 * Math.sin(Math.PI * (x + 0.5)) + 0.5;
|
||||||
|
|
||||||
for (const child of wrapper.current.children) {
|
for (const child of wrapper.current.children) {
|
||||||
if (child instanceof HemisphereLight) {
|
if (child instanceof SpotLight) {
|
||||||
child.intensity = HEMISPHERE_INTENSITY * t;
|
|
||||||
} else if (child instanceof SpotLight) {
|
|
||||||
child.angle = ANGLE * t;
|
child.angle = ANGLE * t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,34 +68,29 @@ export function Lighting() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<group ref={wrapper}>
|
<group ref={wrapper}>
|
||||||
<hemisphereLight
|
{times(LIGHTS_COUNT, (index) => {
|
||||||
position={[0, 1, 0]}
|
const x = index / (LIGHTS_COUNT - 1);
|
||||||
color="#dadaff"
|
const theta = 2 * Math.PI * (index / LIGHTS_COUNT) + THETA_OFFSET;
|
||||||
groundColor="#856331"
|
const position = [
|
||||||
intensity={0}
|
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);
|
||||||
|
|
||||||
<HelpingSpotLight
|
return (
|
||||||
debug
|
<HelpingSpotLight
|
||||||
position={[-6, 6, -10]}
|
userData={{ index }}
|
||||||
intensity={4}
|
key={index}
|
||||||
penumbra={1}
|
position={position}
|
||||||
castShadow
|
intensity={intensity}
|
||||||
color="#ffffff"
|
penumbra={1}
|
||||||
decay={0}
|
castShadow={highGraphics}
|
||||||
angle={0}
|
decay={1}
|
||||||
/>
|
color="#ffffff"
|
||||||
|
/>
|
||||||
<HelpingSpotLight
|
);
|
||||||
debug
|
})}
|
||||||
position={[6, 6, -10]}
|
|
||||||
intensity={1}
|
|
||||||
penumbra={1}
|
|
||||||
castShadow
|
|
||||||
color="#ffffff"
|
|
||||||
decay={0}
|
|
||||||
angle={0}
|
|
||||||
/>
|
|
||||||
</group>
|
</group>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -15,6 +15,7 @@ export interface TankopediaPersistent {
|
|||||||
showPrimaryArmor: boolean;
|
showPrimaryArmor: boolean;
|
||||||
recentlyViewed: number[];
|
recentlyViewed: number[];
|
||||||
hideTankModelUnderArmor: boolean;
|
hideTankModelUnderArmor: boolean;
|
||||||
|
highGraphics: boolean;
|
||||||
|
|
||||||
sort: {
|
sort: {
|
||||||
by: TankopediaSortBy;
|
by: TankopediaSortBy;
|
||||||
@@ -33,6 +34,7 @@ export const TankopediaPersistent = new Varuna<TankopediaPersistent>(
|
|||||||
showExternalModules: true,
|
showExternalModules: true,
|
||||||
showPrimaryArmor: true,
|
showPrimaryArmor: true,
|
||||||
recentlyViewed: [],
|
recentlyViewed: [],
|
||||||
|
highGraphics: true,
|
||||||
sort: {
|
sort: {
|
||||||
by: "meta.none",
|
by: "meta.none",
|
||||||
direction: "ascending",
|
direction: "ascending",
|
||||||
|
|||||||
Reference in new issue
Block a user