This commit is contained in:
+33
-44
@@ -16,11 +16,11 @@ declare const __STEPVIEW__: {
|
||||
|
||||
// ---- Scene state ---------------------------------------------------------
|
||||
|
||||
let renderer: THREE.WebGLRenderer
|
||||
let scene: THREE.Scene
|
||||
let camera: THREE.PerspectiveCamera
|
||||
let controls: OrbitControls
|
||||
let keyLight: THREE.DirectionalLight
|
||||
let renderer: THREE.WebGLRenderer
|
||||
let scene: THREE.Scene
|
||||
let camera: THREE.PerspectiveCamera
|
||||
let controls: OrbitControls
|
||||
let viewingDist: number = 200 // updated by fitCamera; used by fog toggle
|
||||
|
||||
// ---- UI helpers ----------------------------------------------------------
|
||||
|
||||
@@ -71,29 +71,28 @@ function buildScene(canvas: HTMLCanvasElement) {
|
||||
|
||||
scene = new THREE.Scene()
|
||||
|
||||
// Subtle environment fog
|
||||
scene.fog = new THREE.FogExp2(0x0a0a0f, 0.0008)
|
||||
|
||||
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.001, 10000)
|
||||
camera.position.set(5, 3, 8)
|
||||
|
||||
// Lighting
|
||||
const ambient = new THREE.AmbientLight(0xffffff, 0.5)
|
||||
// Lighting — no fog: FogExp2 with a fixed density darkens large models
|
||||
// whose camera distance exceeds ~200 units, making them appear black.
|
||||
const ambient = new THREE.AmbientLight(0xffffff, 0.9)
|
||||
scene.add(ambient)
|
||||
|
||||
keyLight = new THREE.DirectionalLight(0xffffff, 2.0)
|
||||
keyLight.position.set(10, 20, 10)
|
||||
keyLight.castShadow = true
|
||||
keyLight.shadow.mapSize.set(2048, 2048)
|
||||
scene.add(keyLight)
|
||||
scene.add(keyLight.target)
|
||||
const key = new THREE.DirectionalLight(0xffffff, 1.8)
|
||||
key.position.set(1, 2, 1.5)
|
||||
key.castShadow = true
|
||||
key.shadow.mapSize.set(2048, 2048)
|
||||
key.shadow.camera.near = 0.1
|
||||
key.shadow.camera.far = 500
|
||||
scene.add(key)
|
||||
|
||||
const fill = new THREE.DirectionalLight(0x8899cc, 0.4)
|
||||
fill.position.set(-10, 5, -10)
|
||||
fill.position.set(-2, 0.5, -1)
|
||||
scene.add(fill)
|
||||
|
||||
const rim = new THREE.DirectionalLight(0xffffff, 0.2)
|
||||
rim.position.set(0, -5, -10)
|
||||
const rim = new THREE.DirectionalLight(0xffffff, 0.25)
|
||||
rim.position.set(0, -1, -2)
|
||||
scene.add(rim)
|
||||
|
||||
controls = new OrbitControls(camera, renderer.domElement)
|
||||
@@ -138,6 +137,8 @@ function fitCamera(object: THREE.Object3D) {
|
||||
const fovRad = camera.fov * (Math.PI / 180)
|
||||
const dist = (maxDim / (2 * Math.tan(fovRad / 2))) * 1.6
|
||||
|
||||
viewingDist = dist
|
||||
|
||||
camera.near = maxDim * 0.0005
|
||||
camera.far = maxDim * 200
|
||||
camera.updateProjectionMatrix()
|
||||
@@ -150,31 +151,6 @@ function fitCamera(object: THREE.Object3D) {
|
||||
camera.lookAt(center)
|
||||
controls.target.copy(center)
|
||||
controls.update()
|
||||
|
||||
// Scale fog so it stays subtle at any model size.
|
||||
// density = 0.19/dist keeps fog-factor ≈ 0.95 at the viewing distance.
|
||||
if (scene.fog instanceof THREE.FogExp2) {
|
||||
scene.fog.density = 0.19 / dist
|
||||
}
|
||||
|
||||
// Aim key light at the model center and fit its shadow frustum around
|
||||
// the model so shadows are correct regardless of scale.
|
||||
const lightDist = maxDim * 2
|
||||
keyLight.position.set(
|
||||
center.x + lightDist * 0.5,
|
||||
center.y + lightDist,
|
||||
center.z + lightDist * 0.5,
|
||||
)
|
||||
keyLight.target.position.copy(center)
|
||||
keyLight.target.updateMatrixWorld()
|
||||
|
||||
const sc = keyLight.shadow.camera
|
||||
const ext = maxDim * 1.5
|
||||
sc.left = -ext; sc.right = ext
|
||||
sc.top = ext; sc.bottom = -ext
|
||||
sc.near = lightDist * 0.1
|
||||
sc.far = lightDist * 4
|
||||
sc.updateProjectionMatrix()
|
||||
}
|
||||
|
||||
// ---- Ground grid ---------------------------------------------------------
|
||||
@@ -379,6 +355,19 @@ function wireToolbar() {
|
||||
})
|
||||
}
|
||||
|
||||
// Fog toggle — off by default; density scaled to the loaded model's viewing distance
|
||||
let fogOn = false
|
||||
const fogBtn = document.getElementById('fog-btn')
|
||||
if (fogBtn) {
|
||||
fogBtn.addEventListener('click', () => {
|
||||
fogOn = !fogOn
|
||||
scene.fog = fogOn
|
||||
? new THREE.FogExp2(0x0a0a0f, 0.19 / viewingDist)
|
||||
: null
|
||||
fogBtn.classList.toggle('text-accent', fogOn)
|
||||
})
|
||||
}
|
||||
|
||||
// Wireframe toggle
|
||||
let wireframe = false
|
||||
const wireBtn = document.getElementById('wireframe-btn')
|
||||
|
||||
@@ -32,6 +32,14 @@
|
||||
<!-- Top-right controls -->
|
||||
<div class="fixed top-5 right-5 flex items-center gap-2 z-20">
|
||||
|
||||
<!-- Fog toggle -->
|
||||
<button id="fog-btn" title="Toggle atmosphere fog"
|
||||
class="flex items-center justify-center w-10 h-10 md:w-8 md:h-8 bg-surface-900/90 backdrop-blur-sm border border-gray-700 hover:border-gray-600 text-gray-400 hover:text-white rounded-xl transition-all">
|
||||
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.75">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 15a4.5 4.5 0 004.5 4.5H18a3.75 3.75 0 001.332-7.257 3 3 0 00-3.758-3.848 5.25 5.25 0 00-10.233 2.33A4.502 4.502 0 002.25 15z" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!-- Wireframe toggle -->
|
||||
<button id="wireframe-btn" title="Toggle wireframe"
|
||||
class="flex items-center justify-center w-10 h-10 md:w-8 md:h-8 bg-surface-900/90 backdrop-blur-sm border border-gray-700 hover:border-gray-600 text-gray-400 hover:text-white rounded-xl transition-all">
|
||||
|
||||
Reference in New Issue
Block a user