11import { Canvas , useLoader } from "@react-three/fiber" ;
2- import { OrbitControls , Environment } from "@react-three/drei" ;
32import { Physics , RigidBody } from "@react-three/rapier" ;
43import { Suspense , useEffect , useState } from "react" ;
54import { STLLoader } from "three/examples/jsm/loaders/STLLoader.js" ;
@@ -20,8 +19,8 @@ interface PhysicsSTLProps {
2019// Generate a random pastel color
2120function generateRandomColor ( ) : string {
2221 const hue = Math . random ( ) * 360 ;
23- const saturation = 60 + Math . random ( ) * 20 ; // 60-80%
24- const lightness = 65 + Math . random ( ) * 15 ; // 65-80%
22+ const saturation = 90 ;
23+ const lightness = 70 ;
2524 return `hsl(${ hue } , ${ saturation } %, ${ lightness } %)` ;
2625}
2726
@@ -39,7 +38,7 @@ function PhysicsSTL({ config, delay, color }: PhysicsSTLProps) {
3938 if ( ! isVisible ) return null ;
4039
4140 const position = [
42- ( Math . random ( ) - 0.5 ) * 4 ,
41+ ( Math . random ( ) - 0.5 ) * 7 ,
4342 15 ,
4443 ( Math . random ( ) - 0.5 ) * 3 ,
4544 ] as const ;
@@ -57,12 +56,7 @@ function PhysicsSTL({ config, delay, color }: PhysicsSTLProps) {
5756 canSleep = { true }
5857 >
5958 < mesh geometry = { geometry } scale = { scale } castShadow receiveShadow >
60- < meshStandardMaterial
61- color = { color }
62- roughness = { 0.35 }
63- metalness = { 0.0 }
64- envMapIntensity = { 0.6 }
65- />
59+ < meshStandardMaterial color = { color } roughness = { 0.5 } metalness = { 0.1 } />
6660 </ mesh >
6761 </ RigidBody >
6862 ) ;
@@ -71,9 +65,67 @@ function PhysicsSTL({ config, delay, color }: PhysicsSTLProps) {
7165function Ground ( ) {
7266 return (
7367 < RigidBody type = "fixed" colliders = "cuboid" friction = { 0.4 } >
74- < mesh position = { [ 0 , - 2 , 0 ] } receiveShadow >
75- < boxGeometry args = { [ 10 , 0.5 , 6 ] } />
76- < meshStandardMaterial color = "#b2b2b2ff" roughness = { 0.9 } />
68+ < mesh position = { [ 0 , - 3 , 0 ] } receiveShadow rotation = { [ - Math . PI / 2 , 0 , 0 ] } >
69+ < boxGeometry args = { [ 10 , 6 , 0.25 ] } />
70+ < meshStandardMaterial
71+ color = "#f5dcb1"
72+ roughness = { 0.7 }
73+ metalness = { 0.0 }
74+ onBeforeCompile = { ( shader ) => {
75+ shader . vertexShader = `
76+ varying vec2 vUv;
77+ varying vec3 vPosition;
78+ ${ shader . vertexShader }
79+ ` . replace (
80+ `#include <begin_vertex>` ,
81+ `#include <begin_vertex>
82+ vUv = uv;
83+ vPosition = position;
84+ ` ,
85+ ) ;
86+
87+ shader . fragmentShader = `
88+ varying vec2 vUv;
89+ varying vec3 vPosition;
90+ ${ shader . fragmentShader }
91+ ` . replace (
92+ `#include <color_fragment>` ,
93+ `#include <color_fragment>
94+ // Round the corners by discarding fragments near edges
95+ vec2 pos = vPosition.xy;
96+ float width = 10.0;
97+ float height = 6.0;
98+ float radius = 0.5;
99+
100+ // Calculate distance from corner
101+ vec2 corner = abs(pos) - vec2(width/2.0 - radius, height/2.0 - radius);
102+ float cornerDist = length(max(corner, 0.0));
103+
104+ // Discard fragments outside the rounded rectangle
105+ if (cornerDist > radius) {
106+ discard;
107+ }
108+
109+ // Birch plywood texture
110+ // Subtle horizontal grain
111+ float noise1 = fract(sin(dot(vUv * vec2(2.0, 30.0), vec2(12.9898, 78.233))) * 43758.5453);
112+ float grain = sin(vUv.y * 60.0 + noise1 * 4.0) * 0.08;
113+
114+ // Random knots and imperfections
115+ float noise2 = fract(sin(dot(vUv * 15.0, vec2(93.989, 67.345))) * 28474.3347);
116+ float knots = smoothstep(0.97, 1.0, noise2) * -0.2;
117+
118+ // Slight color variation across surface
119+ float variation = sin(vUv.x * 2.5 + vUv.y * 1.5) * 0.04;
120+
121+ // Lighter streaks (characteristic of birch)
122+ float streaks = step(0.85, fract(sin(vUv.y * 25.0) * 43.0)) * 0.1;
123+
124+ diffuseColor.rgb *= (1.0 + grain + knots + variation + streaks);
125+ ` ,
126+ ) ;
127+ } }
128+ />
77129 </ mesh >
78130 </ RigidBody >
79131 ) ;
@@ -119,19 +171,35 @@ export default function STLPileViewer({
119171 } }
120172 >
121173 < Canvas
122- camera = { { position : [ 0 , 1.2 , 6.9 ] , fov : 50 } }
174+ camera = { { position : [ 0 , 3 , 15 ] , fov : 35 } }
123175 shadows
124176 style = { { background : backgroundColor } }
125177 >
126- { /* <ambientLight intensity={0.1} castShadow/> */ }
178+ { /* Ambient light for overall scene brightness */ }
179+ < ambientLight intensity = { 0.4 } />
180+
181+ { /* Main key light - simulates overhead/window light */ }
127182 < directionalLight
128183 castShadow
129- position = { [ 10 , 10 , 10 ] }
130- intensity = { 0.02 }
131- shadow-mapSize = { [ 1024 , 1024 ] }
184+ position = { [ 5 , 8 , 5 ] }
185+ intensity = { 1.2 }
186+ shadow-mapSize = { [ 2048 , 2048 ] }
187+ shadow-camera-far = { 50 }
188+ shadow-camera-left = { - 10 }
189+ shadow-camera-right = { 10 }
190+ shadow-camera-top = { 10 }
191+ shadow-camera-bottom = { - 10 }
192+ shadow-bias = { - 0.0001 }
132193 />
133- < directionalLight position = { [ - 10 , - 10 , - 10 ] } intensity = { 0.4 } />
134- < Environment preset = "city" />
194+
195+ { /* Fill light - softens shadows from the opposite side */ }
196+ < directionalLight position = { [ - 3 , 3 , - 5 ] } intensity = { 0.3 } />
197+
198+ { /* Rim/back light - adds definition and separates objects from background */ }
199+ < directionalLight position = { [ - 5 , 5 , - 8 ] } intensity = { 0.5 } />
200+
201+ { /* Subtle top light for additional depth */ }
202+ < pointLight position = { [ 0 , 10 , 0 ] } intensity = { 0.3 } distance = { 15 } />
135203
136204 < Suspense fallback = { null } >
137205 < Physics gravity = { [ 0 , - 9.81 , 0 ] } >
@@ -146,17 +214,6 @@ export default function STLPileViewer({
146214 ) ) }
147215 </ Physics >
148216 </ Suspense >
149-
150- { /* <OrbitControls
151- enableDamping
152- dampingFactor={0.05}
153- autoRotate={false}
154- enablePan={true}
155- enableZoom={false}
156- minDistance={3}
157- maxDistance={15}
158- target={[0, 0, 0]}
159- /> */ }
160217 </ Canvas >
161218 </ div >
162219 </ div >
0 commit comments