summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-21 20:12:44 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-21 20:12:44 +0800
commit8d594b6a541c5ee2ab3ddf9fe870df790d0bb357 (patch)
treef01c242ae826fb74add371bdb650f16603d433ad /src
parent8a1e79e46605291234314bd1a02dcab7a8c9bdc1 (diff)
downloadsomhairles-dream-fsharp-8d594b6a541c5ee2ab3ddf9fe870df790d0bb357.tar.gz
feat(detail): engineering detail pass on both models + PBR studio pipeline (ACES, env reflections, rim/bounce lights)
Diffstat (limited to 'src')
-rw-r--r--src/SomhairlesDream.Frontend/App.fs18
-rw-r--r--src/SomhairlesDream.Frontend/Bindings.fs27
2 files changed, 44 insertions, 1 deletions
diff --git a/src/SomhairlesDream.Frontend/App.fs b/src/SomhairlesDream.Frontend/App.fs
index dbb267c..315a0fc 100644
--- a/src/SomhairlesDream.Frontend/App.fs
+++ b/src/SomhairlesDream.Frontend/App.fs
@@ -241,17 +241,33 @@ let initializeView () =
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(width, height, false)
+ // PBR pipeline: ACES tone mapping + a procedural studio environment map
+ // so metalness/roughness from the GLB materials read as machined
+ // hardware instead of flat plastic.
+ setToneMappingACES renderer
+ setToneMappingExposure (renderer, 1.15)
+ setSRGBOutput renderer
let scene = createScene()
scene.background <- createColor("#11171a")
+ let envScene = createEnvScene()
+ let pmrem = createPMREMGenerator renderer
+ let envTexture = pmremFromScene (pmrem, envScene)
+ setSceneEnvironment (scene, envTexture)
+ setSceneEnvironmentIntensity (scene, 0.55)
let camera = createPerspectiveCamera(34.0, width / height, 0.1, 100.0)
camera.position.set(6.4, 4.6, 7.2) |> ignore
camera.lookAt(0.0, 0.0, 0.0)
let group = createGroup()
scene.add(group)
- scene.add(createAmbientLight("#f0e6c8", 1.9))
+ scene.add(createAmbientLight("#f0e6c8", 0.55))
let keyLight = createDirectionalLight("#f2c76b", 2.8)
keyLight.position.set(4.0, 7.0, 5.0) |> ignore
scene.add(keyLight)
+ let rimLight = createDirectionalLight("#7fa8ff", 1.4)
+ rimLight.position.set(-6.0, -3.0, -4.0) |> ignore
+ scene.add(rimLight)
+ let bounceLight = createHemisphereLight("#3d4a56", "#141a1e", 0.9)
+ scene.add(bounceLight)
let controls = createOrbitControls camera canvas
setControlsTarget controls 0.0 0.0 0.0
diff --git a/src/SomhairlesDream.Frontend/Bindings.fs b/src/SomhairlesDream.Frontend/Bindings.fs
index 19056a5..b6c4353 100644
--- a/src/SomhairlesDream.Frontend/Bindings.fs
+++ b/src/SomhairlesDream.Frontend/Bindings.fs
@@ -154,6 +154,33 @@ let createAmbientLight (color: string, intensity: float) : ThreeNode = jsNative
[<Emit("new THREE.DirectionalLight($0, $1)")>]
let createDirectionalLight (color: string, intensity: float) : ThreeNode = jsNative
+[<Emit("new THREE.HemisphereLight($0, $1, $2)")>]
+let createHemisphereLight (skyColor: string, groundColor: string, intensity: float) : ThreeNode = jsNative
+
+[<Emit("$0.toneMapping = THREE.ACESFilmicToneMapping")>]
+let setToneMappingACES (renderer: obj) : unit = jsNative
+
+[<Emit("$0.toneMappingExposure = $1")>]
+let setToneMappingExposure (renderer: obj, exposure: float) : unit = jsNative
+
+[<Emit("$0.outputColorSpace = THREE.SRGBColorSpace")>]
+let setSRGBOutput (renderer: obj) : unit = jsNative
+
+[<Emit("new THREE.PMREMGenerator($0)")>]
+let createPMREMGenerator (renderer: obj) : obj = jsNative
+
+[<Emit("new THREE.Scene()")>]
+let createEnvScene () : obj = jsNative
+
+[<Emit("$0.fromScene($1, 0.04).texture")>]
+let pmremFromScene (generator: obj, scene: obj) : obj = jsNative
+
+[<Emit("$0.environment = $1")>]
+let setSceneEnvironment (scene: obj, texture: obj) : unit = jsNative
+
+[<Emit("$0.environmentIntensity = $1")>]
+let setSceneEnvironmentIntensity (scene: obj, intensity: float) : unit = jsNative
+
[<Emit("new EventSource($0)")>]
let createEventSource (url: string) : EventSource = jsNative