feat(web): lighten tabletop scene and tune contact shadows
Replace the dark surface plane with a grey background and a spotlight, size the contact shadow to the table, and scale its blur and fade with the shadow plane. Disable depth test on the stacking curve overlay.
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
resolveMountTree,
|
||||
serializedToPackage,
|
||||
useTabletopStore,
|
||||
MM_TO_WORLD,
|
||||
} from '@tts/tabletop';
|
||||
import Scene from '../viewers/Scene';
|
||||
|
||||
@@ -35,11 +36,26 @@ export default function TabletopScene({
|
||||
[packageData, surfaces],
|
||||
);
|
||||
|
||||
// Size the contact shadow to cover 2x the largest enabled surface, so the
|
||||
// shadow plane always extends past the table. Surface sizes are in mm;
|
||||
// `MM_TO_WORLD` converts to world units.
|
||||
const shadowScale = useMemo(() => {
|
||||
let maxMm = 0;
|
||||
for (const [id, enabled] of Object.entries(surfaces)) {
|
||||
if (!enabled) continue;
|
||||
const surface = packageData.surfaces.get(id);
|
||||
if (!surface?.size) continue;
|
||||
maxMm = Math.max(maxMm, ...surface.size);
|
||||
}
|
||||
return maxMm > 0 ? maxMm * 2 * MM_TO_WORLD : 22;
|
||||
}, [packageData, surfaces]);
|
||||
|
||||
return (
|
||||
<Scene
|
||||
autoRotate={false}
|
||||
enablePan
|
||||
fullscreen
|
||||
shadowScale={shadowScale}
|
||||
overlay={
|
||||
<button
|
||||
onClick={() => setShowSurface((v) => !v)}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Suspense, useEffect, useRef, useState, type ReactNode } from 'react';
|
||||
import { Icon } from '@iconify/react';
|
||||
import { Canvas } from '@react-three/fiber';
|
||||
import { Bounds, ContactShadows, OrbitControls, useProgress } from '@react-three/drei';
|
||||
import { Bloom, EffectComposer, Vignette } from '@react-three/postprocessing';
|
||||
import { EffectComposer, Vignette } from '@react-three/postprocessing';
|
||||
|
||||
/**
|
||||
* Shared 3D scene wrapper for object viewers. Provides a consistent camera,
|
||||
@@ -24,6 +24,7 @@ export default function Scene({
|
||||
enablePan = false,
|
||||
fullscreen = false,
|
||||
overlay,
|
||||
shadowScale = 22,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
autoRotate?: boolean;
|
||||
@@ -31,6 +32,8 @@ export default function Scene({
|
||||
fullscreen?: boolean;
|
||||
/** HTML rendered inside the scene container (e.g. controls), shown in fullscreen. */
|
||||
overlay?: ReactNode;
|
||||
/** Contact shadow plane size in world units; defaults to a generous 22. */
|
||||
shadowScale?: number;
|
||||
}) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||
@@ -49,7 +52,7 @@ export default function Scene({
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="relative h-80 w-full overflow-hidden rounded-lg bg-linear-to-b from-zinc-900 to-zinc-950"
|
||||
className="relative h-80 w-full overflow-hidden rounded-lg bg-linear-to-b from-zinc-300 to-zinc-400"
|
||||
>
|
||||
<LoadingOverlay />
|
||||
{fullscreen && (
|
||||
@@ -66,7 +69,7 @@ export default function Scene({
|
||||
<Canvas
|
||||
camera={{ position: [2.2, 1.8, 2.6], fov: 40 }}
|
||||
dpr={[1, 2]}
|
||||
gl={{ antialias: true }}
|
||||
gl={{ antialias: true, alpha: true }}
|
||||
>
|
||||
<ambientLight intensity={0.5} />
|
||||
<directionalLight position={[4, 6, 3]} intensity={1.4} />
|
||||
@@ -78,12 +81,13 @@ export default function Scene({
|
||||
</Suspense>
|
||||
|
||||
<ContactShadows
|
||||
position={[0, -0.5, 0]}
|
||||
opacity={0.55}
|
||||
scale={8}
|
||||
blur={2.4}
|
||||
far={3}
|
||||
resolution={256}
|
||||
position={[0, -0.01, 0]}
|
||||
opacity={0.2}
|
||||
scale={shadowScale}
|
||||
blur={shadowScale * 0.005}
|
||||
far={shadowScale * 0.01}
|
||||
resolution={1024}
|
||||
color="#000000"
|
||||
/>
|
||||
<OrbitControls
|
||||
enablePan={enablePan}
|
||||
@@ -94,7 +98,6 @@ export default function Scene({
|
||||
/>
|
||||
|
||||
<EffectComposer>
|
||||
<Bloom intensity={0.25} luminanceThreshold={0.85} mipmapBlur />
|
||||
<Vignette eskil={false} offset={0.25} darkness={0.6} />
|
||||
</EffectComposer>
|
||||
</Canvas>
|
||||
|
||||
Reference in New Issue
Block a user