mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-25 03:29:51 +01:00
feat: transition skeleton
This commit is contained in:
1 parent
64d346ccb6
commit
da704e6181
5 files changed
+147
-3
No files matched your search
+116
@@ -0,0 +1,116 @@
|
|||||||
|
import { useEffect, useRef } from 'react';
|
||||||
|
import { Group, ShaderMaterial, UniformsLib, UniformsUtils } from 'three';
|
||||||
|
import { jsxTree } from '../../../../../../../core/blitzkit/jsxTree';
|
||||||
|
import { useModel } from '../../../../../../../hooks/useModel';
|
||||||
|
import { useTankModelDefinition } from '../../../../../../../hooks/useTankModelDefinition';
|
||||||
|
import { useTankTransform } from '../../../../../../../hooks/useTankTransform';
|
||||||
|
import { Duel } from '../../../../../../../stores/duel';
|
||||||
|
import {
|
||||||
|
ShootingRangeZoom,
|
||||||
|
TankopediaEphemeral,
|
||||||
|
} from '../../../../../../../stores/tankopediaEphemeral';
|
||||||
|
import { ModelTankWrapper } from '../../../../../../Armor/components/ModelTankWrapper';
|
||||||
|
import fragmentShader from './shaders/fragment.glsl?raw';
|
||||||
|
import vertexShader from './shaders/vertex.glsl?raw';
|
||||||
|
|
||||||
|
const skeletonMaterial = new ShaderMaterial({
|
||||||
|
vertexShader,
|
||||||
|
fragmentShader,
|
||||||
|
wireframe: true,
|
||||||
|
fog: true,
|
||||||
|
transparent: true,
|
||||||
|
uniforms: UniformsUtils.merge([UniformsLib.common, UniformsLib.fog]),
|
||||||
|
depthWrite: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
export function TransitionSkeleton() {
|
||||||
|
const protagonist = Duel.use((draft) => draft.protagonist);
|
||||||
|
const tankopediaEphemeralStore = TankopediaEphemeral.useStore();
|
||||||
|
const track = Duel.use((state) => state.protagonist.track);
|
||||||
|
const turret = Duel.use((state) => state.protagonist.turret);
|
||||||
|
const hullContainer = useRef<Group>(null);
|
||||||
|
const turretContainer = useRef<Group>(null);
|
||||||
|
const gunContainer = useRef<Group>(null);
|
||||||
|
const tankModelDefinition = useTankModelDefinition();
|
||||||
|
const turretModelDefinition =
|
||||||
|
tankModelDefinition.turrets[protagonist.turret.id];
|
||||||
|
const gunModelDefinition =
|
||||||
|
turretModelDefinition.guns[protagonist.gun.gun_type!.value.base.id];
|
||||||
|
const { gltf } = useModel(protagonist.tank.id);
|
||||||
|
const nodes = Object.values(gltf.nodes);
|
||||||
|
const revealed = tankopediaEphemeralStore((state) => state.revealed);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const unsubscribeShootingRangeZoom = tankopediaEphemeralStore.subscribe(
|
||||||
|
(state) => state.shootingRangeZoom,
|
||||||
|
(zoom) => {
|
||||||
|
if (!hullContainer.current) return;
|
||||||
|
hullContainer.current.visible = zoom === ShootingRangeZoom.Arcade;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return unsubscribeShootingRangeZoom;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useTankTransform(track, turret, turretContainer, gunContainer);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ModelTankWrapper ref={hullContainer} visible={revealed}>
|
||||||
|
{nodes.map((node) => {
|
||||||
|
const isHull = node.name === 'hull';
|
||||||
|
const isWheel = node.name.startsWith('chassis_wheel_');
|
||||||
|
const isTrack = node.name.startsWith('chassis_track_');
|
||||||
|
const isVisible = isHull || isWheel || isTrack;
|
||||||
|
|
||||||
|
if (!isVisible) return null;
|
||||||
|
|
||||||
|
return jsxTree(node, {
|
||||||
|
mesh(_, props, key) {
|
||||||
|
return <mesh {...props} key={key} material={skeletonMaterial} />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})}
|
||||||
|
|
||||||
|
<group ref={turretContainer}>
|
||||||
|
{nodes.map((node) => {
|
||||||
|
const isCurrentTurret =
|
||||||
|
node.name ===
|
||||||
|
`turret_${turretModelDefinition.model_id.toString().padStart(2, '0')}`;
|
||||||
|
const isVisible = isCurrentTurret;
|
||||||
|
|
||||||
|
if (!isVisible) return null;
|
||||||
|
|
||||||
|
return jsxTree(node, {
|
||||||
|
mesh(_, props, key) {
|
||||||
|
return <mesh {...props} key={key} material={skeletonMaterial} />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})}
|
||||||
|
|
||||||
|
<group ref={gunContainer}>
|
||||||
|
{nodes.map((node) => {
|
||||||
|
const isCurrentMantlet =
|
||||||
|
node.name ===
|
||||||
|
`gun_${gunModelDefinition.model_id
|
||||||
|
.toString()
|
||||||
|
.padStart(2, '0')}_mask`;
|
||||||
|
const isCurrentGun =
|
||||||
|
node.name ===
|
||||||
|
`gun_${gunModelDefinition.model_id.toString().padStart(2, '0')}`;
|
||||||
|
const isVisible = isCurrentGun || isCurrentMantlet;
|
||||||
|
|
||||||
|
if (!isVisible) return null;
|
||||||
|
|
||||||
|
return jsxTree(node, {
|
||||||
|
mesh(_, props, key) {
|
||||||
|
return (
|
||||||
|
<mesh {...props} key={key} material={skeletonMaterial} />
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})}
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</ModelTankWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
#define USE_FOG
|
||||||
|
|
||||||
|
#include <fog_pars_fragment>
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
float fogFactor = smoothstep(fogNear, fogFar, vFogDepth);
|
||||||
|
gl_FragColor = vec4(0.75, 0.75, 0.75, fogFactor);
|
||||||
|
gl_FragColor.rgb = mix(gl_FragColor.rgb, fogColor, 1.0 - fogFactor);
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
#define USE_FOG
|
||||||
|
|
||||||
|
#include <fog_pars_vertex>
|
||||||
|
|
||||||
|
varying vec3 vNormal;
|
||||||
|
varying vec3 vViewPosition;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
|
||||||
|
|
||||||
|
vViewPosition = mvPosition.xyz;
|
||||||
|
vNormal = normalMatrix * normal;
|
||||||
|
|
||||||
|
gl_Position = projectionMatrix * mvPosition;
|
||||||
|
|
||||||
|
#include <fog_vertex>
|
||||||
|
}
|
||||||
+4
-2
@@ -32,17 +32,18 @@ import { InitialFogReveal } from './components/InitialFogReveal';
|
|||||||
import { Lighting } from './components/Lighting';
|
import { Lighting } from './components/Lighting';
|
||||||
import { SceneProps } from './components/SceneProps';
|
import { SceneProps } from './components/SceneProps';
|
||||||
import { TankModel } from './components/TankModel';
|
import { TankModel } from './components/TankModel';
|
||||||
|
import { TransitionSkeleton } from './components/TransitionSkeleton';
|
||||||
|
|
||||||
interface TankSandboxProps {
|
interface TankSandboxProps {
|
||||||
thicknessRange: ThicknessRange;
|
thicknessRange: ThicknessRange;
|
||||||
naked?: boolean;
|
naked?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const forNear0 = 15;
|
export const forNear0 = 20;
|
||||||
export const fogFar0 = 25;
|
export const fogFar0 = 25;
|
||||||
export const forNear1 = 0;
|
export const forNear1 = 0;
|
||||||
export const fogFar1 = 0;
|
export const fogFar1 = 0;
|
||||||
export const fogAnimationTime = 0.5;
|
export const fogAnimationTime = 1.5;
|
||||||
|
|
||||||
export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
||||||
({ thicknessRange, naked }, ref) => {
|
({ thicknessRange, naked }, ref) => {
|
||||||
@@ -237,6 +238,7 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
|||||||
{(display === TankopediaDisplay.Model ||
|
{(display === TankopediaDisplay.Model ||
|
||||||
(display === TankopediaDisplay.DynamicArmor &&
|
(display === TankopediaDisplay.DynamicArmor &&
|
||||||
!hideTankModelUnderArmor)) && <TankModel />}
|
!hideTankModelUnderArmor)) && <TankModel />}
|
||||||
|
<TransitionSkeleton />
|
||||||
<ShotDisplay />
|
<ShotDisplay />
|
||||||
<ArmorPlateDisplay />
|
<ArmorPlateDisplay />
|
||||||
<AutoClear />
|
<AutoClear />
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ export function HeroSection({ skeleton }: MaybeSkeletonComponentProps) {
|
|||||||
</Heading>
|
</Heading>
|
||||||
|
|
||||||
<Heading
|
<Heading
|
||||||
weight="regular"
|
weight="medium"
|
||||||
size={
|
size={
|
||||||
disturbed
|
disturbed
|
||||||
? { initial: '7', lg: '8' }
|
? { initial: '7', lg: '8' }
|
||||||
|
|||||||
Reference in new issue
Block a user