From aedd8aa2773d10202d3c3d27dd71ddff6d2e9463 Mon Sep 17 00:00:00 2001 From: Micheal Parks Date: Thu, 7 Dec 2023 01:17:11 -0500 Subject: [PATCH] cleanup --- playground/frag.glsl | 8 - playground/main.css | 14 -- playground/main.ts | 217 -------------------------- playground/main2.ts | 251 ------------------------------- playground/vert.glsl | 7 - src_old/constants.ts | 4 - src_old/elements/gizmo.ts | 8 - src_old/elements/index.ts | 45 ------ src_old/elements/nav.ts | 67 --------- src_old/elements/stats.ts | 90 ----------- src_old/folders/scene.ts | 140 ----------------- src_old/inputs/lights.ts | 227 ---------------------------- src_old/inputs/material.ts | 228 ---------------------------- src_old/inputs/object3d.ts | 44 ------ src_old/inputs/postprocessing.ts | 125 --------------- src_old/inputs/renderer.ts | 123 --------------- src_old/inputs/texture.ts | 148 ------------------ src_old/inputs/transform.ts | 134 ----------------- src_old/inputs/userdata.ts | 18 --- src_old/lib/controls.ts | 50 ------ src_old/lib/event-dispatcher.ts | 64 -------- src_old/lib/image.ts | 18 --- src_old/lib/raycast.ts | 37 ----- src_old/lib/rectarealight.ts | 92 ----------- src_old/lib/resizable.ts | 119 --------------- src_old/main.css | 43 ------ src_old/main.ts | 108 ------------- src_old/objects.ts | 78 ---------- src_old/pane/index.ts | 18 --- src_old/patch/folders.ts | 38 ----- src_old/patch/object3d.ts | 47 ------ src_old/refs.ts | 20 --- src_old/scene.ts | 129 ---------------- src_old/update.ts | 39 ----- 34 files changed, 2798 deletions(-) delete mode 100644 playground/frag.glsl delete mode 100644 playground/main.css delete mode 100644 playground/main.ts delete mode 100644 playground/main2.ts delete mode 100644 playground/vert.glsl delete mode 100644 src_old/constants.ts delete mode 100644 src_old/elements/gizmo.ts delete mode 100644 src_old/elements/index.ts delete mode 100644 src_old/elements/nav.ts delete mode 100644 src_old/elements/stats.ts delete mode 100644 src_old/folders/scene.ts delete mode 100644 src_old/inputs/lights.ts delete mode 100644 src_old/inputs/material.ts delete mode 100644 src_old/inputs/object3d.ts delete mode 100644 src_old/inputs/postprocessing.ts delete mode 100644 src_old/inputs/renderer.ts delete mode 100644 src_old/inputs/texture.ts delete mode 100644 src_old/inputs/transform.ts delete mode 100644 src_old/inputs/userdata.ts delete mode 100644 src_old/lib/controls.ts delete mode 100644 src_old/lib/event-dispatcher.ts delete mode 100644 src_old/lib/image.ts delete mode 100644 src_old/lib/raycast.ts delete mode 100644 src_old/lib/rectarealight.ts delete mode 100644 src_old/lib/resizable.ts delete mode 100644 src_old/main.css delete mode 100644 src_old/main.ts delete mode 100644 src_old/objects.ts delete mode 100644 src_old/pane/index.ts delete mode 100644 src_old/patch/folders.ts delete mode 100644 src_old/patch/object3d.ts delete mode 100644 src_old/refs.ts delete mode 100644 src_old/scene.ts delete mode 100644 src_old/update.ts diff --git a/playground/frag.glsl b/playground/frag.glsl deleted file mode 100644 index e207b70..0000000 --- a/playground/frag.glsl +++ /dev/null @@ -1,8 +0,0 @@ -varying vec2 vUv; - -uniform vec3 color1; -uniform vec3 color2; - -void main () { - gl_FragColor = vec4(mix(color1, color2, vUv.x), 1.0); -} \ No newline at end of file diff --git a/playground/main.css b/playground/main.css deleted file mode 100644 index 7896240..0000000 --- a/playground/main.css +++ /dev/null @@ -1,14 +0,0 @@ -body { - margin: 0; - overflow: hidden; - height: 100vh; -} - -#canvas { - z-index: 1; - position: absolute; - top: 0; - left: 0; - width: 100vw; - height: 100vh; -} diff --git a/playground/main.ts b/playground/main.ts deleted file mode 100644 index e55295e..0000000 --- a/playground/main.ts +++ /dev/null @@ -1,217 +0,0 @@ -import './main.css' -import * as THREE from 'three' -import { trzy, useFrame, Trail } from 'trzy' -import { createNoise3D, NoiseFunction3D } from 'simplex-noise' -import Inspector from '../src/main' -import vertexShader from './vert.glsl' -import fragmentShader from './frag.glsl' - -const { scene, camera, renderer } = trzy(); - -renderer.domElement.id = 'canvas' - -document.body.append(renderer.domElement) - -scene.add(camera.current) - -camera.current.near = -200 -camera.current.far = 200 - -camera.current.position.set(5, 5, 5) -camera.current.lookAt(0, 0, 0) - -const ambient = new THREE.AmbientLight() -scene.add(ambient) - -{ - const directional = new THREE.DirectionalLight() - directional.castShadow = true - directional.shadow.normalBias = -0.1 - directional.shadow.camera.near = 0.4 - directional.shadow.camera.far = 47 - directional.shadow.camera.left = -22 - directional.shadow.camera.right = 22 - directional.shadow.camera.top = 21 - directional.shadow.camera.bottom = -21 - directional.position.set(5, 20, 2.5) - scene.add(directional) -} - -{ - const rect = new THREE.RectAreaLight(0xff0000) - rect.intensity = 0.5 - rect.position.y = 0.1 - rect.rotateX(Math.PI / 2) - rect.width = 30 - rect.height = 30 - scene.add(rect) -} - -{ - // Geometry - const geo = new THREE.BufferGeometry() - const count = 10000 - const vec3 = new THREE.Vector3() - - const positions = new Float32Array(count * 3) // Multiply by 3 because each position is composed of 3 values (x, y, z) - - // for (let i = 0; i < count * 3; i += 3) { - // let th = Math.random() * 2 * Math.PI - // let n = 1000 - // let r = 200 - // let x = r * Math.sin(th) * Math.cos(n * th) - // let y = r * Math.sin(th) * Math.sin(n * th) - // let z = r * Math.cos(th) - - // positions[i + 0] = x - // positions[i + 1] = y - // positions[i + 2] = z - // } - - let radius = 100 - - for (let i = 0; i < count * 3; i += 3) { - vec3.set(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5).normalize().multiplyScalar(radius) - positions[i + 0] = vec3.x - positions[i + 1] = vec3.y - positions[i + 2] = vec3.z - } - - // for(let i = 0; i < count * 3; i++) { - // positions[i] = (Math.random() - 0.5) * 10 // Math.random() - 0.5 to have a random value between -0.5 and +0.5 - // } - - geo.setAttribute('position', new THREE.BufferAttribute(positions, 3)) // Create the Three.js BufferAttribute and specify that each information is composed of 3 values - - const mat = new THREE.PointsMaterial({ - size: 5, - sizeAttenuation: true - }) - const points = new THREE.Points(geo, mat) - points.position.set(0, 0, 0) - points.name = 'points' - scene.add(points) -} - -{ - const count = 20 - const trails: { trail: Trail, noise3d: NoiseFunction3D }[] = [] - const v3 = new THREE.Vector3() - - for (let i = 0; i < count; i += 1) { - let j = 0 - const noise3d = createNoise3D(() => Math.random() * 2) - const trail = new Trail() - trail.decay = 3 - trail.geometry.attenuation = 'squared' - trail.position.set(0, 7, 0) - scene.add(trail) - trails.push({ trail, noise3d }) - } - - let time = 0 - - useFrame((_, delta) => { - time += delta - - for (let i = 0, l = trails.length; i < l; i += 1) { - const { trail, noise3d } = trails[i] - const x = noise3d(Math.sin(time / 10000) * 10, 0, 0) - const y = noise3d(0, Math.cos(time / 10000) * 10, 0) - const z = noise3d(0, 0, Math.sin(time / 10000) * 10) - v3.set(x * 5, y * 10, z * 10) - trail.target.position.lerp(v3, 0.05) - trail.update() - } - }) -} - -const euler = new THREE.Euler() -const m4 = new THREE.Matrix4() -const position = (symmetry = true) => (Math.random() - (symmetry ? 0.5 : 0)) * 20 -const rotation = () => Math.random() * Math.PI * 2 - -const geometry = new THREE.BoxGeometry(3, 3, 3) -const material = new THREE.MeshPhysicalMaterial() -const box = new THREE.Mesh(geometry, material) -box.name = 'Box' -box.castShadow = true -box.receiveShadow = true -box.position.set(0, 1.5, 0) -scene.add(box) - -useFrame(() => { - box.rotation.y += 0.01 -}) - -const count = 30 -{ - const geometry = new THREE.DodecahedronGeometry() - const material = new THREE.MeshPhysicalMaterial() - const mesh = new THREE.InstancedMesh(geometry, material, count) - mesh.name = 'Dodecahedrons' - mesh.castShadow = mesh.receiveShadow = true - box.add(mesh) - - for (let i = 0; i < count; i += 1) { - euler.set(rotation(), rotation(), rotation()) - m4.makeRotationFromEuler(euler) - m4.setPosition(position(), position(false), position()) - mesh.setMatrixAt(i, m4) - } - mesh.instanceMatrix.needsUpdate = true -} - -{ - const geometry = new THREE.PlaneGeometry(30, 30).rotateX(-Math.PI / 2) - const material = new THREE.MeshStandardMaterial() - const mesh = new THREE.Mesh(geometry, material) - mesh.name = 'Floor' - mesh.castShadow = mesh.receiveShadow = true - scene.add(mesh) -} - -{ - const colors = new Float32Array([ - 1, 0, 0, - 0, 1, 0, - 0, 0, 1, - 0, 1, 1, - ]) - - const size = 2 - const geometry = new THREE.BoxGeometry(size, size, size) - const material = new THREE.ShaderMaterial({ - uniforms: { - color1: { value: { x: 1, y: 1, z: 0 } }, - color2: { value: { x: 0, y: 1, z: 1 } }, - }, - vertexShader, - fragmentShader, - }) - - geometry.setAttribute('colors', new THREE.Float32BufferAttribute(colors, 3)) - - const mesh = new THREE.Mesh(geometry, material) - mesh.name = 'Shader Mesh' - mesh.castShadow = true - mesh.receiveShadow = true - mesh.position.set(10, 1, 0) - scene.add(mesh) -} - -let inspector: Inspector | undefined - -const toggle = () => { - if (inspector) { - inspector.dispose() - inspector = undefined - } else { - inspector = new Inspector({ THREE, scene, camera: camera.current, renderer }) - } -} - -toggle() - -const pane = inspector?.addPane('Game') -pane?.addInput({ test: '' }, 'test') diff --git a/playground/main2.ts b/playground/main2.ts deleted file mode 100644 index 031c70c..0000000 --- a/playground/main2.ts +++ /dev/null @@ -1,251 +0,0 @@ -import './main.css' -import * as THREE from 'three' -import { loadTexture, trzy, useFrame } from 'trzy' -import Inspector from '../src/main' -import vertexShader from './vert.glsl' -import fragmentShader from './frag.glsl' - -const { scene, camera, renderer } = trzy() - -renderer.domElement.id = 'canvas' - -const cam = camera.current as THREE.PerspectiveCamera - -cam.far = 300 -cam.position.set(0, 2, 10) - -const cubeTextureLoader = new THREE.CubeTextureLoader() - -const environmentMapTexture = cubeTextureLoader.load([ - '/textures/environmentMaps/0/px.jpg', - '/textures/environmentMaps/0/nx.jpg', - '/textures/environmentMaps/0/py.jpg', - '/textures/environmentMaps/0/ny.jpg', - '/textures/environmentMaps/0/pz.jpg', - '/textures/environmentMaps/0/nz.jpg' -]) - -let meshes: THREE.Object3D[] = [] -let materials: THREE.Material[] = [] - -// Create starfield -{ - const geometry = new THREE.BufferGeometry(); - const vec3 = new THREE.Vector3(); - - const count = 10_000 - const radius = 100 - - const vertices = new Float32Array(count * 3); - - for (let i = 0; i < count * 3; i += 3) { - vec3.set(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5).normalize().multiplyScalar(radius) - vertices[i + 0] = vec3.x - vertices[i + 1] = vec3.y - vertices[i + 2] = vec3.z - } - - // itemSize = 3 because there are 3 values (components) per vertex - geometry.setAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); - geometry.translate(0, 0.5, 0) - - const material = new THREE.PointsMaterial() - material.size = 0.2 - material.sizeAttenuation = true - const points = new THREE.Points(geometry, material) - points.name = 'Stars' - scene.add(points) -} - -// Add an ambient light -{ - const ambient = new THREE.AmbientLight() - ambient.intensity = 0.8 - scene.add(ambient) -} - -// Add a directional light -{ - const directional = new THREE.DirectionalLight() - directional.castShadow = true - directional.shadow.mapSize.height = 512 - directional.shadow.mapSize.width = 512 - directional.shadow.camera.far = 30 - directional.intensity = 1.5 - scene.add(directional) - directional.position.set(3, 5, 3) -} - -// Add the floor -{ - const geometry = new THREE.BoxGeometry(20, 5, 0.1).rotateX(Math.PI / 2).translate(0, -1, 0) - const material = new THREE.MeshPhysicalMaterial({ color: 'lightslategrey' }) - material.envMap = environmentMapTexture - material.transparent = true - material.opacity = 0.7 - material.envMapIntensity = 1 - material.reflectivity = 1 - material.clearcoat = 1 - material.clearcoatRoughness = 0.08 - material.transmission = 1 - materials.push(material) - - const mesh = new THREE.Mesh(geometry, material) - mesh.name = 'Floor' - mesh.castShadow = mesh.receiveShadow = true - scene.add(mesh) -} - -const size = 1 - -// Add a box -{ - const object = new THREE.Object3D() - const geometry = new THREE.BoxGeometry(size, size, size) - const material = new THREE.ShaderMaterial({ - uniforms: { - color1: { value: { x: 1, y: 1, z: 0 } }, - color2: { value: { x: 0, y: 1, z: 1 } }, - }, - vertexShader, - fragmentShader, - }) - materials.push(material) - - const mesh = new THREE.Mesh(geometry, material) - mesh.name = 'Box' - object.add(mesh) - scene.add(object) - meshes.push(object) -} - -// Add a cartoonish cone -{ - const geometry = new THREE.ConeGeometry(size / 2, size, 30, 30) - const material = new THREE.MeshToonMaterial({ color: 'hotpink' }) - materials.push(material) - - const mesh = new THREE.Mesh(geometry, material) - mesh.name = 'Cone' - mesh.position.x = 2 - scene.add(mesh) - meshes.push(mesh) -} - -// Add a sphere -{ - const geometry = new THREE.SphereGeometry(size / 2, 30, 30) - const material = new THREE.MeshStandardMaterial({ color: 'lightblue' }) - material.envMap = environmentMapTexture - material.envMapIntensity = 1 - material.roughness = 0 - material.metalness = 1 - materials.push(material) - - const mesh = new THREE.Mesh(geometry, material) - mesh.name = 'Sphere' - mesh.position.x = -2 - scene.add(mesh) - meshes.push(mesh) -} - -// Add a torus knot -const addTorusKnot = async () => { - const geometry = new THREE.TorusKnotGeometry(size / 2, size / 10, 70, 70) - const material = new THREE.MeshStandardMaterial({ color: 'darksalmon' }) - material.envMap = environmentMapTexture - material.envMapIntensity = 1 - materials.push(material) - - const repeatX = 10 - - const textures = await Promise.all([ - loadTexture('/textures/metal/weave_COL_1K_METALNESS.jpg'), - loadTexture('/textures/metal/weave_AO_1K_METALNESS.jpg'), - loadTexture('/textures/metal/weave_DISP_1K_METALNESS.jpg'), - loadTexture('/textures/metal/weave_NRM_1K_METALNESS.jpg'), - loadTexture('/textures/metal/weave_ROUGHNESS_1K_METALNESS.jpg'), - loadTexture('/textures/metal/weave_METALNESS_1K_METALNESS.jpg'), - ]) - - for (const texture of textures) { - texture.wrapS = texture.wrapT = THREE.RepeatWrapping - texture.repeat.x = repeatX - texture.anisotropy = renderer.capabilities.getMaxAnisotropy() - } - - material.map = textures[0] - material.aoMap = textures[1] - material.displacementMap = textures[2] - material.displacementScale = 0.005 - material.normalMap = textures[3] - material.roughnessMap = textures[4] - material.metalnessMap = textures[5] - - material.roughness = 0.17 - material.metalness = 0.95 - - const mesh = new THREE.Mesh(geometry, material) - mesh.name = 'Torus Knot' - mesh.position.x = -4 - mesh.castShadow = true - mesh.receiveShadow = true - scene.add(mesh) - meshes.push(mesh) -} - -addTorusKnot() - -// Add a torus / donut -{ - const geometry = new THREE.TorusGeometry(size / 2, size / 10, 10, 20) - const material = new THREE.MeshPhysicalMaterial() - material.envMap = environmentMapTexture - material.envMapIntensity = 1 - material.roughness = 0.17 - material.metalness = 1 - materials.push(material) - - const mesh = new THREE.Mesh(geometry, material) - mesh.name = 'Torus / Donut' - mesh.position.x = 4 - scene.add(mesh) - meshes.push(mesh) -} - -// Add a Cylinder -{ - const geometry = new THREE.CylinderGeometry(0.5, 0.5, 1, 20) - const edges = new THREE.EdgesGeometry(geometry, 1); - const line = new THREE.LineSegments(edges, new THREE.LineBasicMaterial({ color: 0xffffff })); - line.name = 'Cylinder' - line.position.x = 6 - - scene.add(line) - meshes.push(line) -} - -{ - const mesh = new THREE.Mesh( - new THREE.BoxGeometry(1, 1, 0.01), - new THREE.MeshPhysicalMaterial() - ) - - mesh.name = 'Plane' - mesh.position.x = -6 - scene.add(mesh) - meshes.push(mesh) -} - -for (const mesh of meshes) { - mesh.castShadow = true - mesh.receiveShadow = true -} - -useFrame(() => { - for (const mesh of meshes) { - mesh.rotation.y += 0.01 - } -}) - -new Inspector({ scene, camera: cam, renderer }) diff --git a/playground/vert.glsl b/playground/vert.glsl deleted file mode 100644 index 6e0bea4..0000000 --- a/playground/vert.glsl +++ /dev/null @@ -1,7 +0,0 @@ -varying vec2 vUv; - -void main() { - gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); - - vUv = uv; -} \ No newline at end of file diff --git a/src_old/constants.ts b/src_old/constants.ts deleted file mode 100644 index 6abc88e..0000000 --- a/src_old/constants.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const defaultMinMax = { - max: 1, - min: 0, -} diff --git a/src_old/elements/gizmo.ts b/src_old/elements/gizmo.ts deleted file mode 100644 index 1fa1c01..0000000 --- a/src_old/elements/gizmo.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { ViewHelper } from 'trzy' -import { refs } from '../refs' - -export const createViewHelper = () => { - const { camera, renderer } = refs - const gizmo = new ViewHelper(camera, renderer) - return () => gizmo.dispose() -} diff --git a/src_old/elements/index.ts b/src_old/elements/index.ts deleted file mode 100644 index 6b36b06..0000000 --- a/src_old/elements/index.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { createControls } from './controls' -import { createNav } from './nav' -import { initCanvas } from './canvas' -import { initScene } from '../scene' -import { initStats } from './stats' -import { refs } from '../refs' - -export const initElements = (options: { - location: 'right' | 'overlay' -}) => { - const disposers: Disposer[] = [] - const root = document.createElement('div') - root.className = options.location === 'right' - ? 'z-[100] absolute top-0 left-0 w-screen h-screen flex' - : 'z-[100] absolute top-0 right-0 w-[350px] h-screen flex' - refs.root = root - - if (options.location === 'right') { - const canvas = initCanvas() - root.append(canvas) - - let width = window.innerWidth - - const handleResize = () => { - const { innerWidth } = window - const delta = innerWidth - width - canvas.style.width = `${canvas.clientWidth + delta}px` - width = innerWidth - } - - window.addEventListener('resize', handleResize, { passive: true }) - - disposers.push(() => window.removeEventListener('resize', handleResize)) - } - - const { controls, nav, treeroot, treeview, pane } = createControls() - const { addPane } = createNav(controls, nav) - - disposers.push(initStats(controls), initScene(treeview, treeroot, pane)) - - root.append(controls) - document.body.append(root) - - return { addPane, disposers } -} diff --git a/src_old/elements/nav.ts b/src_old/elements/nav.ts deleted file mode 100644 index 2bbf4ff..0000000 --- a/src_old/elements/nav.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { load, save } from 'trzy' -import { createPane } from '../pane' -import { dispatcher } from '../lib/event-dispatcher' - -// eslint-disable-next-line max-len -const mouseSvg = '' - -export const createNav = (controls: HTMLElement, nav: HTMLElement) => { - let selected = '' - - const selectPane = (title: string) => { - if (selected === title) { - return - } - - save('three-inspect.selectedPane', title) - - controls.querySelector(`[data-pane="${selected}"]`)?.classList.add('hidden') - const current = nav.querySelector(`[data-nav="${selected}"]`) - current?.classList.remove('bg-zinc-400', 'text-zinc-800') - current?.classList.add('text-zinc-400') - - controls.querySelector(`[data-pane="${title}"]`)?.classList.remove('hidden') - const next = nav.querySelector(`[data-nav="${title}"]`) - next?.classList.add('bg-zinc-400', 'text-zinc-800') - next?.classList.remove('text-zinc-400') - - selected = title - } - - const createNavButton = (title: string) => { - const button = document.createElement('button') - button.className = 'py-1.5 px-2 text-zinc-400' - button.dataset.nav = title - button.textContent = title - button.addEventListener('click', () => selectPane(title), { passive: true }) - nav.append(button) - } - - const addPane = (title: string) => { - const container = document.createElement('section') - container.className = 'h-screen flex flex-col overflow-x-hidden overflow-y-auto hidden' - container.dataset.pane = title - controls.insertBefore(container, controls.children[controls.children.length - 2]) - createNavButton(title) - return createPane(container) - } - - const inspectButton = document.createElement('button') - inspectButton.title = 'Select an element to inspect it' - inspectButton.innerHTML = mouseSvg - inspectButton.className = 'w-6 fill-zinc-400 p-1 hover:fill-zinc-300 hover:bg-[rgba(255,255,255,0.05)]' - inspectButton.addEventListener('click', () => { - const enabled = inspectButton.classList.toggle('enabled') - inspectButton.classList.toggle('bg-zinc-600', enabled) - inspectButton.classList.toggle('hover:bg-zinc-600', enabled) - inspectButton.classList.toggle('fill-zinc-100', enabled) - inspectButton.classList.toggle('hover:fill-zinc-100', enabled) - dispatcher.dispatchEvent({ enabled, type: 'enable-select' }) - }, { passive: true }) - nav.append(inspectButton) - - createNavButton('World') - selectPane(load('three-inspect.selectedPane') ?? 'World') - - return { addPane } -} diff --git a/src_old/elements/stats.ts b/src_old/elements/stats.ts deleted file mode 100644 index 7a90298..0000000 --- a/src_old/elements/stats.ts +++ /dev/null @@ -1,90 +0,0 @@ -import * as EssentialsPlugin from '@tweakpane/plugin-essentials' -import { removeUpdate, update } from '../update' -import { Pane } from 'tweakpane' - -type PerformanceMemory = Performance & { - memory: undefined | { - usedJSHeapSize: number - jsHeapSizeLimit: number - } -} - -export const initStats = (root: HTMLElement) => { - const container = document.createElement('div') - container.className = 'sticky bottom-0 h-[105px]' - root.append(container) - - const stats = new Pane({ container }) - stats.registerPlugin(EssentialsPlugin) - - stats.addSeparator() - - const mb = 1_048_576 - const { memory } = performance as PerformanceMemory - - const parameters = { - memory: memory ? memory.usedJSHeapSize / mb : 0, - time: '', - } - - const start = performance.now() - let total = 0 - - const updateTime = () => { - const now = performance.now() - total = (now - start) / 1000 - - const seconds = (total % 60) | 0 - const minutes = (total / 60) | 0 - const hours = (total / 60 / 60) | 0 - - parameters.time = `${ - hours < 10 ? `0${hours}` : hours - }:${ - minutes < 10 ? `0${minutes}` : minutes - }:${ - seconds < 10 ? `0${seconds}` : seconds - }` - } - - updateTime() - const timeId = setInterval(updateTime, 1000) - - stats.addMonitor(parameters, 'time', { - interval: 1000, - }) - - const fpsGraph = stats.addBlade({ - label: 'fps', - lineCount: 2, - view: 'fpsgraph', - }) - - let memoryId = -1 - if (memory) { - stats.addMonitor(parameters, 'memory', { - max: memory.jsHeapSizeLimit / mb, - min: 0, - view: 'graph', - }) - - memoryId = setInterval(() => { - parameters.memory = memory.usedJSHeapSize / mb - }, 3000) - } - - const tick = () => { - const graph = fpsGraph as unknown as { begin(): void; end(): void } - graph.end() - graph.begin() - } - - update(tick) - - return () => { - stats.dispose() - clearInterval(timeId) - clearInterval(memoryId) - removeUpdate(tick) - } -} diff --git a/src_old/folders/scene.ts b/src_old/folders/scene.ts deleted file mode 100644 index f6c0a10..0000000 --- a/src_old/folders/scene.ts +++ /dev/null @@ -1,140 +0,0 @@ -import * as THREE from 'three' -import { GridHelper, load, save } from 'trzy' -import type { Pane } from '../pane' -import { addRendererInputs } from '../inputs/renderer' -import { addTextureInputs } from '../inputs/texture' -import { refs } from '../refs' -import { singlePixelImage } from '../lib/image' - -const params = { - axes: Boolean(load('three-inspect.axes')), - background: singlePixelImage, - fogColor: '#000000', - grid: Boolean(load('three-inspect.grid')), - gridCellSize: load('three-inspect.gridCellSize') ?? 1, - gridColor: load('three-inspect.gridColor') ?? '#ffffff', - gridDistance: load('three-inspect.gridDistance') ?? 100, - gridLargeCellSize: load('three-inspect.largeCellSize') ?? 10, -} - -const color = new THREE.Color() - -const helpers: { - axes: THREE.AxesHelper - grid: GridHelper -} = { - axes: new THREE.AxesHelper(1000), - grid: new GridHelper(params.gridCellSize, params.gridLargeCellSize, params.gridColor, params.gridDistance), -} - -export const initSceneHelpers = () => { - const { scene } = refs - - helpers.axes = new THREE.AxesHelper(1000) - helpers.axes.name = 'Axes helper' - helpers.axes.userData.THREE_INSPECT_OMIT = true - helpers.grid.name = 'Grid helper' - helpers.grid.userData.THREE_INSPECT_OMIT = true - - if (params.grid) { - scene.add(helpers.grid) - } - - if (params.axes) { - scene.add(helpers.axes) - } - - return () => { - scene.remove(helpers.grid, helpers.axes) - } -} - -export const addSceneInputs = (pane: Pane) => { - const { scene } = refs - const disposers: Disposer[] = [] - - const toggleHelper = (helper: 'axes' | 'grid') => { - scene[params[helper] ? 'add' : 'remove'](helpers[helper]) - - if (params[helper]) { - save(`three-inspect.${helper}`, true) - } else { - save(`three-inspect.${helper}`, false) - } - } - - const handleGridChange = (param: 'gridCellSize' | 'gridLargeCellSize' | 'gridColor' | 'gridDistance') => { - color.set(params.gridColor) - - helpers.grid.cellSize = params.gridCellSize - helpers.grid.largeCellSize = params.gridLargeCellSize - - if (helpers.grid.color instanceof THREE.Color) { - helpers.grid.color.copy(color) - } else { - helpers.grid.color = color - } - - helpers.grid.distance = params.gridDistance - - save(param, params[param]) - } - - pane - .addInput(params, 'axes', { label: 'axes' }) - .on('change', () => toggleHelper('axes')) - - pane - .addInput(params, 'grid', { label: 'grid' }) - .on('change', () => toggleHelper('grid')) - - pane - .addInput(params, 'gridCellSize', { label: 'cell size' }) - .on('change', () => handleGridChange('gridCellSize')) - - pane - .addInput(params, 'gridLargeCellSize', { label: 'large cell size', step: 1 }) - .on('change', () => handleGridChange('gridLargeCellSize')) - - pane - .addInput(params, 'gridColor', { label: 'color', step: 1 }) - .on('change', () => handleGridChange('gridColor')) - - pane - .addInput(params, 'gridDistance', { label: 'distance', step: 1 }) - .on('change', () => handleGridChange('gridDistance')) - - if (scene.fog !== null) { - params.fogColor = `#${scene.fog.color.getHexString().toUpperCase()}` - - const fogFolder = pane.addFolder({ title: 'Fog' }) - fogFolder.addInput(params, 'fogColor', { - label: 'color', - }).on('change', () => { - scene.fog?.color.set(params.fogColor) - }) - - if ('near' in scene.fog) { - fogFolder.addInput(scene.fog, 'near') - } - - if ('far' in scene.fog) { - fogFolder.addInput(scene.fog, 'far') - } - } - - pane.addSeparator() - - disposers.push(addTextureInputs(pane, scene, 'background')) - - pane.addSeparator() - - disposers.push( - addRendererInputs(pane), - () => { - scene.remove(helpers.grid) - helpers.axes.dispose() - } - ) - return disposers -} diff --git a/src_old/inputs/lights.ts b/src_old/inputs/lights.ts deleted file mode 100644 index 2ccc315..0000000 --- a/src_old/inputs/lights.ts +++ /dev/null @@ -1,227 +0,0 @@ -import * as THREE from 'three' -import type { Pane } from '../pane' -import { addTransformInputs } from './transform' -import { addUserdataInput } from './userdata' -import { createRectAreaLightHelper } from '../lib/rectarealight' -import { defaultMinMax } from '../constants' - -type LightHelper = - | THREE.SpotLightHelper - | THREE.DirectionalLightHelper - | THREE.HemisphereLightHelper - | THREE.PointLightHelper - | THREE.CameraHelper - | THREE.Line - -type TargetLight = - | THREE.DirectionalLight - | THREE.SpotLight - -const addTargetInput = (folder: Pane, light: TargetLight) => { - folder.addSeparator() - folder.addInput(light.target, 'position', { - label: 'target position', - step: 0.1, - }).on('change', () => { - light.target.updateMatrixWorld() - }) -} - -export const addLightInputs = (pane: Pane, light: THREE.Light) => { - let helper: LightHelper | undefined - let shadowHelper: THREE.CameraHelper | undefined - - const disposers: Disposer[] = [] - - const params = { - color: `#${light.color.getHexString().toUpperCase()}`, - helper: false, - shadowHelper: false, - } - - if (!(light instanceof THREE.AmbientLight)) { - pane - .addInput(params, 'helper') - .on('change', () => helper && light[params.helper ? 'add' : 'remove'](helper)) - } - - pane - .addInput(params, 'color') - .on('change', () => light.color.set(params.color)) - - pane.addInput(light, 'intensity') - - /** - * Directional - */ - if (light instanceof THREE.DirectionalLight) { - pane.addInput(light, 'castShadow') - - addTransformInputs(pane, light) - addTargetInput(pane, light) - - helper = new THREE.DirectionalLightHelper(light) - - /** - * Hemisphere - */ - } else if (light instanceof THREE.HemisphereLight) { - pane.addInput(light, 'groundColor') - - helper = new THREE.HemisphereLightHelper(light, 10) - - /** - * Point - */ - } else if (light instanceof THREE.PointLight) { - pane.addInput(light, 'decay') - pane.addInput(light, 'distance') - pane.addInput(light, 'power') - pane.addInput(light, 'castShadow') - - addTransformInputs(pane, light) - - helper = new THREE.PointLightHelper(light, 10) - - /** - * Spot - */ - } else if (light instanceof THREE.SpotLight) { - pane.addInput(light, 'angle', { - max: Math.PI / 2, - min: 0, - }) - pane.addInput(light, 'decay') - pane.addInput(light, 'distance') - pane.addInput(light, 'penumbra', defaultMinMax) - pane.addInput(light, 'power') - pane.addInput(light, 'castShadow') - - addTransformInputs(pane, light) - addTargetInput(pane, light) - - helper = new THREE.SpotLightHelper(light) - - /** - * Rect - */ - } else if (light instanceof THREE.RectAreaLight) { - pane.addInput(light, 'power') - pane.addInput(light, 'width') - pane.addInput(light, 'height') - - addTransformInputs(pane, light) - - helper = createRectAreaLightHelper(light) - } - - if (helper !== undefined) { - helper.userData.THREE_INSPECT_OMIT = true - } - - if (light.castShadow && light.shadow) { - const camFolder = pane.addFolder({ index: light.id, title: 'Shadow Camera' }) - - camFolder.addInput(light.shadow, 'autoUpdate') - - camFolder - .addInput(params, 'shadowHelper', { label: 'helper' }) - .on('change', () => shadowHelper && light[params.shadowHelper ? 'add' : 'remove'](shadowHelper)) - - const shadowMapParams = { - mapSize: light.shadow.mapSize.x, - } - - const handleShadowmapChange = () => { - if (!light.shadow) { - return - } - - light.shadow.mapSize.width = shadowMapParams.mapSize - light.shadow.mapSize.height = shadowMapParams.mapSize - light.shadow.dispose() - // eslint-disable-next-line unicorn/no-null - light.shadow.map = null - } - - const mapSizes = [ - 256, - 512, - 1024, - 2048, - ] - - camFolder - .addInput(shadowMapParams, 'mapSize', { - cells: (x: number) => ({ - title: mapSizes[x], - value: mapSizes[x], - }), - groupName: 'mapSize', - size: [4, 1], - view: 'radiogrid', - }).on('change', handleShadowmapChange) - - camFolder.addInput(light.shadow, 'bias', { - max: 0.09, - min: 0, - step: 0.001, - }) - - camFolder.addInput(light.shadow, 'normalBias').on('change', handleShadowmapChange) - camFolder.addInput(light.shadow, 'radius').on('change', handleShadowmapChange) - - /** - * Directional - */ - if (light instanceof THREE.DirectionalLight) { - const { camera } = light.shadow - camFolder.addInput(camera, 'near').on('change', handleShadowmapChange) - camFolder.addInput(camera, 'far').on('change', handleShadowmapChange) - camFolder.addInput(camera, 'left').on('change', handleShadowmapChange) - camFolder.addInput(camera, 'right').on('change', handleShadowmapChange) - camFolder.addInput(camera, 'top').on('change', handleShadowmapChange) - camFolder.addInput(camera, 'bottom').on('change', handleShadowmapChange) - - addTransformInputs(camFolder, camera) - - /** - * Spot - */ - } else if (light instanceof THREE.SpotLight) { - const { camera } = light.shadow - camFolder.addInput(camera, 'near').on('change', handleShadowmapChange) - camFolder.addInput(camera, 'far').on('change', handleShadowmapChange) - camFolder.addInput(camera, 'focus', defaultMinMax) - - addTransformInputs(camFolder, camera) - } - - shadowHelper = new THREE.CameraHelper(light.shadow.camera) - shadowHelper.userData.THREE_INSPECT_OMIT = true - } - - pane.on('change', () => { - // @ts-expect-error update() is not correctly typed - helper?.update?.() - shadowHelper?.update() - }) - - disposers.push( - addUserdataInput(pane, light), - () => { - if (helper !== undefined) { - light.remove(helper) - // @ts-expect-error exists - helper.dispose?.() - } - - if (shadowHelper !== undefined) { - light.remove(shadowHelper) - shadowHelper.dispose() - } - } - ) - - return disposers -} diff --git a/src_old/inputs/material.ts b/src_old/inputs/material.ts deleted file mode 100644 index ebd0158..0000000 --- a/src_old/inputs/material.ts +++ /dev/null @@ -1,228 +0,0 @@ -import * as THREE from 'three' -import type { Pane } from '../pane' -import { addTextureInputs } from '../inputs/texture' -import { defaultMinMax } from '../constants' - -export const addMaterialInputs = (pane: Pane, mesh: THREE.Mesh) => { - const material = mesh.material as THREE.Material - const folder = pane.addFolder({ - index: mesh.id, - title: `${material.name} (${material.type})`.trim(), - }) - - const normalMapTypeOptions = { - ObjectSpaceNormalMap: THREE.ObjectSpaceNormalMap, - TangentSpaceNormalMap: THREE.TangentSpaceNormalMap, - } - - const updateMaterial = () => { - material.needsUpdate = true - } - - const addColorInput = (prop: 'color' | 'emissive' | 'attenuationColor' | 'sheenColor') => { - const mat = material as THREE.MeshPhysicalMaterial - const colorParam = { [prop]: `#${mat[prop].getHexString()}` } - folder.addInput(colorParam, prop).on('change', () => mat[prop].set(colorParam.color)) - } - - folder.addInput(material, 'visible') - folder.addInput(material, 'transparent').on('change', updateMaterial) - folder.addInput(material, 'opacity', defaultMinMax) - - const sides = [ - ['Back', THREE.BackSide], - ['Double', THREE.DoubleSide], - ['Front', THREE.FrontSide], - ] - - folder - .addInput(material, 'side', { - cells: (x: number) => ({ - title: sides[x][0], - value: sides[x][1], - }), - groupName: 'side', - size: [3, 1], - view: 'radiogrid', - }) - - folder.addInput(material, 'vertexColors') - folder.addSeparator() - - /** - * PointsMaterial - */ - if (material instanceof THREE.PointsMaterial) { - addColorInput('color') - folder.addInput(material, 'size') - folder.addInput(material, 'sizeAttenuation') - - /** - * LineBasicMaterial - */ - } else if (material instanceof THREE.LineBasicMaterial || material instanceof THREE.LineDashedMaterial) { - addColorInput('color') - folder.addInput(material, 'fog') - folder.addInput(material, 'linewidth') - - /** - * MeshBasicMaterial - */ - } else if (material instanceof THREE.MeshBasicMaterial) { - addColorInput('color') - - folder.addInput(material, 'fog') - folder.addInput(material, 'reflectivity', defaultMinMax) - folder.addInput(material, 'refractionRatio', defaultMinMax) - folder.addInput(material, 'wireframe') - - /** - * MeshDepthMaterial - */ - } else if (material instanceof THREE.MeshDepthMaterial) { - folder.addInput(material, 'fog') - - /** - * MeshLambertMaterial - */ - } else if (material instanceof THREE.MeshLambertMaterial) { - addColorInput('color') - addColorInput('emissive') - folder.addInput(material, 'emissiveIntensity', { min: 0 }) - folder.addInput(material, 'flatShading').on('change', updateMaterial) - folder.addInput(material, 'fog') - folder.addInput(material, 'reflectivity', defaultMinMax) - folder.addInput(material, 'refractionRatio', defaultMinMax) - folder.addInput(material, 'wireframe') - - /** - * MeshPhongMaterial - */ - } else if (material instanceof THREE.MeshPhongMaterial) { - addColorInput('color') - addColorInput('emissive') - folder.addInput(material, 'emissiveIntensity', { min: 0 }) - folder.addInput(material, 'flatShading').on('change', updateMaterial) - folder.addInput(material, 'fog') - folder.addInput(material, 'reflectivity', defaultMinMax) - folder.addInput(material, 'refractionRatio', defaultMinMax) - folder.addInput(material, 'shininess', defaultMinMax) - folder.addInput(material, 'wireframe') - - /** - * MeshStandardMaterial / MeshPhysicalMaterial - */ - } else if (material instanceof THREE.MeshStandardMaterial) { - addColorInput('color') - addColorInput('emissive') - folder.addInput(material, 'emissiveIntensity', { min: 0 }) - folder.addInput(material, 'roughness', defaultMinMax) - folder.addInput(material, 'metalness', defaultMinMax) - folder.addInput(material, 'flatShading').on('change', updateMaterial) - folder.addInput(material, 'fog') - folder.addInput(material, 'wireframe') - folder.addInput(material, 'envMapIntensity') - - if (material instanceof THREE.MeshPhysicalMaterial) { - folder.addSeparator() - addColorInput('attenuationColor') - folder.addInput(material, 'clearcoat', defaultMinMax) - folder.addInput(material, 'clearcoatRoughness', defaultMinMax) - folder.addInput(material, 'transmission', defaultMinMax) - folder.addInput(material, 'ior', { max: 2.333, min: 1.0 }) - folder.addInput(material, 'reflectivity', defaultMinMax) - folder.addInput(material, 'sheen', defaultMinMax) - folder.addInput(material, 'sheenRoughness', defaultMinMax) - addColorInput('sheenColor') - } - - /** - * ShaderMaterial - */ - } else if (material instanceof THREE.ShaderMaterial) { - const shaderMatParams = { - uniforms: JSON.stringify(material.uniforms, null, 2), - } - - folder.addInput(shaderMatParams, 'uniforms', { view: 'textarea' }).on('change', () => { - try { - material.uniforms = JSON.parse(shaderMatParams.uniforms) - updateMaterial() - } catch { - /* Do nothing */ - } - }) - folder.addInput(material, 'vertexShader', { view: 'textarea' }).on('change', updateMaterial) - folder.addInput(material, 'fragmentShader', { view: 'textarea' }).on('change', updateMaterial) - } - - /** - * Textures - */ - if ( - material instanceof THREE.MeshBasicMaterial || - material instanceof THREE.MeshLambertMaterial || - material instanceof THREE.MeshPhongMaterial || - material instanceof THREE.MeshStandardMaterial || - material instanceof THREE.MeshPhysicalMaterial - ) { - /** - * @TODO add: - * - envMap - */ - folder.addSeparator() - addTextureInputs(folder, material, 'map') - addTextureInputs(folder, material, 'alphaMap') - addTextureInputs(folder, material, 'aoMap') - folder.addInput(material, 'aoMapIntensity', defaultMinMax) - addTextureInputs(folder, material, 'lightMap') - folder.addInput(material, 'lightMapIntensity', defaultMinMax) - - if ( - material instanceof THREE.MeshLambertMaterial || - material instanceof THREE.MeshPhongMaterial || - material instanceof THREE.MeshStandardMaterial || - material instanceof THREE.MeshPhysicalMaterial - ) { - addTextureInputs(folder, material, 'bumpMap') - folder.addInput(material, 'bumpScale', defaultMinMax) - addTextureInputs(folder, material, 'displacementMap') - folder.addInput(material, 'displacementScale') - folder.addInput(material, 'displacementBias') - addTextureInputs(folder, material, 'emissiveMap') - addTextureInputs(folder, material, 'normalMap') - folder.addInput(material, 'normalMapType', { options: normalMapTypeOptions }) - } - - if ( - material instanceof THREE.MeshStandardMaterial || - material instanceof THREE.MeshPhysicalMaterial - ) { - addTextureInputs(folder, material, 'metalnessMap') - addTextureInputs(folder, material, 'roughnessMap') - - if (material instanceof THREE.MeshPhysicalMaterial) { - addTextureInputs(folder, material, 'clearcoatMap') - addTextureInputs(folder, material, 'clearcoatNormalMap') - folder.addInput(material, 'clearcoatNormalScale', { x: defaultMinMax, y: defaultMinMax }) - addTextureInputs(folder, material, 'clearcoatRoughnessMap') - addTextureInputs(folder, material, 'sheenRoughnessMap') - } - } - } - - /** - * Rarely used inputs - */ - folder.addSeparator() - folder.addInput(material, 'alphaTest', defaultMinMax) - folder.addInput(material, 'blendDst') - folder.addInput(material, 'clipShadows') - folder.addInput(material, 'depthTest') - folder.addInput(material, 'depthWrite') - folder.addInput(material, 'polygonOffset') - folder.addInput(material, 'polygonOffsetFactor') - folder.addInput(material, 'dithering') - - return () => folder.dispose() -} diff --git a/src_old/inputs/object3d.ts b/src_old/inputs/object3d.ts deleted file mode 100644 index 3b0e374..0000000 --- a/src_old/inputs/object3d.ts +++ /dev/null @@ -1,44 +0,0 @@ -import * as THREE from 'three' -import type { Pane } from '../pane' -import { addForwardHelperInput } from './helper-forward' -import { addMaterialInputs } from './material' -import { addTransformInputs } from './transform' -import { addUserdataInput } from './userdata' - -type Disposer = () => void - -export const addObjectInputs = (pane: Pane, object3D: THREE.Object3D) => { - if (object3D instanceof THREE.Points) { - pane.addMonitor(object3D.geometry.attributes.position, 'count') - } - - pane.addInput(object3D, 'castShadow') - pane.addInput(object3D, 'receiveShadow') - pane.addInput(object3D, 'frustumCulled') - pane.addInput(object3D, 'matrixAutoUpdate') - pane.addInput(object3D, 'visible') - - const disposers: Disposer[] = [] - - if (!object3D.type.toLowerCase().includes('helper')) { - disposers.push(addForwardHelperInput(pane, object3D)) - } - - disposers.push(addTransformInputs(pane, object3D)) - - const mesh = object3D as THREE.Mesh - - if (Array.isArray(mesh.material)) { - for (let i = 0, l = mesh.material.length; i < l; i += 1) { - if (mesh.material[i] instanceof THREE.Material) { - disposers.push(addMaterialInputs(pane, mesh)) - } - } - } else if (mesh.material !== undefined && mesh.material instanceof THREE.Material) { - disposers.push(addMaterialInputs(pane, mesh)) - } - - disposers.push(addUserdataInput(pane, object3D)) - - return disposers -} diff --git a/src_old/inputs/postprocessing.ts b/src_old/inputs/postprocessing.ts deleted file mode 100644 index 088e73e..0000000 --- a/src_old/inputs/postprocessing.ts +++ /dev/null @@ -1,125 +0,0 @@ - -import type * as Postprocessing from 'postprocessing' -import type { Pane } from '../pane' -import { refs } from '../refs' - -export const addPostInputs = (pane: Pane) => { - const { composer } = refs - - if (composer === undefined) { - return () => 0 - } - - const postFolder = pane.addFolder({ title: 'Postprocessing' }) - const { passes } = composer - - let effectPass: Postprocessing.Pass | undefined - - for (let i = 0, l = passes.length; i < l; i += 1) { - const pass = passes[i] - - if ('effects' in pass) { - effectPass = pass as Postprocessing.Pass - break - } - } - - if (effectPass === undefined) { - return () => postFolder.dispose() - } - - // This crazy typecasting is done because .effects is private >:| - const { effects } = (effectPass as unknown as { effects: Postprocessing.Effect[]}) - - for (let i = 0, l = effects.length; i < l; i += 1) { - const effect = effects[i] - - /** - * SMAA - */ - if (effect.name === 'SMAAEffect') { - postFolder.addFolder({ title: 'smaa' }) - - /** - * Bloom - */ - } else if (effect.name === 'BloomEffect') { - const bloomEffect = effect as Postprocessing.BloomEffect - const bloomFolder = postFolder.addFolder({ title: 'bloom' }) - bloomFolder.addInput(bloomEffect, 'height') - bloomFolder.addInput(bloomEffect, 'width') - bloomFolder.addInput(bloomEffect, 'intensity') - - /** - * Noise - */ - } else if (effect.name === 'NoiseEffect') { - const noiseFolder = postFolder.addFolder({ title: 'noise' }) - noiseFolder.addInput(effect.blendMode.opacity, 'value', { label: 'opacity' }) - - /** - * Vignette - */ - } else if (effect.name === 'VignetteEffect') { - const vignetteEffect = effect as Postprocessing.VignetteEffect - const vignetteFolder = postFolder.addFolder({ title: 'vignette' }) - vignetteFolder.addInput(vignetteEffect, 'darkness') - vignetteFolder.addInput(vignetteEffect, 'technique', { - options: { - default: 0, - eskil: 1, - }, - }) - vignetteFolder.addInput(vignetteEffect, 'offset') - - /** - * SSR - */ - } else if (effect.name === 'SSREffect') { - const index = 0 - const ssrEffect = effect as any - const ssrFolder = postFolder.addFolder({ title: 'ssr' }) - ssrFolder.addInput(ssrEffect, 'intensity', { max: 3, min: 0, step: 0.01 }) - ssrFolder.addInput(ssrEffect, 'exponent', { max: 8, min: 0.125, step: 0.125 }) - ssrFolder.addInput(ssrEffect, 'distance', { max: 10, min: 0.001, step: 0.1 }) - ssrFolder.addInput(ssrEffect, 'fade', { max: 20, min: 0, step: 0.01 }) - ssrFolder.addInput(ssrEffect, 'roughnessFade', { max: 1, min: 0, step: 0.01 }) - ssrFolder.addInput(ssrEffect, 'thickness', { max: 10, min: 0, step: 0.01 }) - ssrFolder.addInput(ssrEffect, 'ior', { max: 2.3333, min: 1, step: 0.01 }) - ssrFolder.addInput(ssrEffect, 'maxRoughness', { max: 1, min: 0, step: 0.01 }) - ssrFolder.addInput(ssrEffect, 'maxDepthDifference', { max: 100, min: 0, step: 0.1 }) - - const temporalResolveFolder = ssrFolder.addFolder({ index, title: 'Temporal Resolve' }) - temporalResolveFolder.addInput(ssrEffect, 'blend', { max: 1, min: 0, step: 0.001 }) - temporalResolveFolder.addInput(ssrEffect, 'correction', { max: 1, min: 0, step: 0.0001 }) - temporalResolveFolder.addInput(ssrEffect, 'correctionRadius', { max: 4, min: 1, step: 1 }) - - const blurFolder = ssrFolder.addFolder({ index, title: 'Blur' }) - blurFolder.addInput(ssrEffect, 'blur', { max: 1, min: 0, step: 0.01 }) - blurFolder.addInput(ssrEffect, 'blurKernel', { max: 5, min: 0, step: 1 }) - blurFolder.addInput(ssrEffect, 'blurSharpness', { max: 100, min: 0, step: 1 }) - - const jitterFolder = ssrFolder.addFolder({ index, title: 'Jitter' }) - jitterFolder.addInput(ssrEffect, 'jitter', { max: 4, min: 0, step: 0.01 }) - jitterFolder.addInput(ssrEffect, 'jitterRoughness', { max: 4, min: 0, step: 0.01 }) - - const definesFolder = ssrFolder.addFolder({ index, title: 'Tracing' }) - definesFolder.addInput(ssrEffect, 'steps', { max: 256, min: 1, step: 1 }) - definesFolder.addInput(ssrEffect, 'refineSteps', { max: 16, min: 0, step: 1 }) - definesFolder.addInput(ssrEffect, 'missedRays') - - const resolutionFolder = ssrFolder.addFolder({ index, title: 'Resolution' }) - resolutionFolder.addInput(ssrEffect, 'resolutionScale', { max: 1, min: 0.125, step: 0.125 }) - resolutionFolder.addInput(ssrEffect, 'velocityResolutionScale', { max: 1, min: 0.125, step: 0.125 }) - - /** - * Unhandled - */ - } else { - // eslint-disable-next-line no-console - console.warn(`three-inspect does not yet support postprocessing effect: ${effect.name}`) - } - } - - return () => postFolder.dispose() -} diff --git a/src_old/inputs/renderer.ts b/src_old/inputs/renderer.ts deleted file mode 100644 index bdb64e8..0000000 --- a/src_old/inputs/renderer.ts +++ /dev/null @@ -1,123 +0,0 @@ -import * as THREE from 'three' -import type { MonitorBindingApi } from 'tweakpane' -import type { Pane } from '../pane' -import { refs } from '../refs' - -export const addRendererInputs = (pane: Pane) => { - const { renderer } = refs - - const color = new THREE.Color() - - renderer.getClearColor(color) - - const colorParams = { - clearColor: `#${color.getHexString().toUpperCase()}`, - } - - pane.addInput(colorParams, 'clearColor').on('change', () => { - renderer.setClearColor(colorParams.clearColor) - }) - - const shadowmapChange = () => { - renderer.shadowMap.needsUpdate = true - } - - pane.addSeparator() - pane - .addInput(renderer.shadowMap, 'enabled', { label: 'shadowmap' }) - .on('change', shadowmapChange) - pane - .addInput(renderer.shadowMap, 'autoUpdate') - .on('change', shadowmapChange) - pane.addInput(renderer.shadowMap, 'type', { - options: { - 'Basic': THREE.BasicShadowMap, - 'PCF': THREE.PCFShadowMap, - 'PCF Soft': THREE.PCFSoftShadowMap, - 'VSM': THREE.VSMShadowMap, - }, - }).on('change', () => { - renderer.shadowMap.needsUpdate = true - }) - - pane.addSeparator() - - pane.addInput(renderer, 'toneMapping', { - options: { - ACESFilmic: THREE.ACESFilmicToneMapping, - Cineon: THREE.CineonToneMapping, - Custom: THREE.CustomToneMapping, - Linear: THREE.LinearToneMapping, - None: THREE.NoToneMapping, - Reinhard: THREE.ReinhardToneMapping, - }, - }) - pane.addInput(renderer, 'toneMappingExposure', { label: 'exposure' }) - - pane.addSeparator() - - const params = { - calls: '', - geometries: '', - lines: '', - points: '', - textures: '', - triangles: '', - } - - const capabilities = { - maxAnisotropy: renderer.capabilities.getMaxAnisotropy().toString(), - maxAttributes: renderer.capabilities.maxAttributes.toFixed(0), - maxCubemapSize: `${renderer.capabilities.maxCubemapSize} (h * w)`, - maxFragmentUniforms: renderer.capabilities.maxFragmentUniforms.toFixed(0), - maxTextureSize: `${renderer.capabilities.maxTextureSize.toFixed(0)} (h * w)`, - maxTextures: renderer.capabilities.maxTextures.toFixed(0), - maxVaryings: renderer.capabilities.maxVaryings.toFixed(0), - maxVertexTextures: renderer.capabilities.maxVertexTextures.toFixed(0), - maxVertexUniforms: renderer.capabilities.maxVertexUniforms.toFixed(0), - } - - const interval = { interval: 1_000_000 } - const monitors: MonitorBindingApi[] = [] - - monitors.push( - pane.addMonitor(params, 'calls', interval), - pane.addMonitor(params, 'geometries', interval), - pane.addMonitor(params, 'lines', interval), - pane.addMonitor(params, 'points', interval), - pane.addMonitor(params, 'textures', interval), - pane.addMonitor(params, 'triangles', interval) - ) - - pane.addSeparator() - - pane.addMonitor(capabilities, 'maxAnisotropy', interval) - pane.addMonitor(capabilities, 'maxAttributes', interval) - pane.addMonitor(capabilities, 'maxCubemapSize', interval) - pane.addMonitor(capabilities, 'maxFragmentUniforms', interval) - pane.addMonitor(capabilities, 'maxTextureSize', interval) - pane.addMonitor(capabilities, 'maxTextures', interval) - pane.addMonitor(capabilities, 'maxVaryings', interval) - pane.addMonitor(capabilities, 'maxVertexTextures', interval) - pane.addMonitor(capabilities, 'maxVertexUniforms', interval) - pane.addMonitor(renderer.capabilities, 'precision', interval) - - const updateStats = () => { - const { render, memory } = renderer.info - params.calls = render.calls.toFixed(0) - params.geometries = memory.geometries.toFixed(0) - params.lines = render.lines.toFixed(0) - params.points = render.points.toFixed(0) - params.textures = memory.textures.toFixed(0) - params.triangles = render.triangles.toFixed(0) - - for (let i = 0, l = monitors.length; i < l; i += 1) { - monitors[i].refresh() - } - } - - const intervalId = setInterval(updateStats, 2000) - updateStats() - - return () => clearInterval(intervalId) -} diff --git a/src_old/inputs/texture.ts b/src_old/inputs/texture.ts deleted file mode 100644 index e4a7a7c..0000000 --- a/src_old/inputs/texture.ts +++ /dev/null @@ -1,148 +0,0 @@ -/* eslint-disable no-use-before-define */ -import * as THREE from 'three' -import type { Pane } from '../pane' -import { singlePixelImage } from '../lib/image' - -type Textures = - 'alphaMap' | 'aoMap' | 'bumpMap' | - 'displacementMap' | 'lightMap' | - 'emissiveMap' | 'map' | 'metalnessMap' | 'normalMap' | 'roughnessMap' | - 'clearcoatMap' | 'clearcoatNormalMap' | 'clearcoatRoughnessMap' | 'sheenRoughnessMap' | - 'background' - -type TextureObjects = - | THREE.Scene - | THREE.MeshBasicMaterial - | THREE.MeshStandardMaterial - -export const addTextureInputs = (pane: Pane, object: TextureObjects, property: Textures) => { - // @ts-expect-error @TODO Type this better - const tex = object[property] as THREE.Texture | null - - const disposer = { - current: () => { - /* No-op */ - }, - } - - const wrapOptions = { - ClampToEdgeWrapping: THREE.ClampToEdgeWrapping, - MirroredRepeatWrapping: THREE.MirroredRepeatWrapping, - RepeatWrapping: THREE.RepeatWrapping, - } - - const magFilterOptions = { - LinearFilter: THREE.LinearFilter, - NearestFilter: THREE.NearestFilter, - } - - const minFilterOptions = { - ...magFilterOptions, - LinearMipmapLinearFilter: THREE.LinearMipmapLinearFilter, - LinearMipmapNearestFilter: THREE.LinearMipmapNearestFilter, - NearestMipmapLinearFilter: THREE.NearestMipmapLinearFilter, - NearestMipmapNearestFilter: THREE.NearestMipmapNearestFilter, - } - - const anisotropyOptions = { - 0: 0, - 16: 16, - 2: 2, - 4: 4, - 8: 8, - } - - const formatOptions = { - AlphaFormat: THREE.AlphaFormat, - DepthFormat: THREE.DepthFormat, - DepthStencilFormat: THREE.DepthStencilFormat, - LuminanceAlphaFormat: THREE.LuminanceAlphaFormat, - LuminanceFormat: THREE.LuminanceFormat, - RGBAFormat: THREE.RGBAFormat, - RGBAIntegerFormat: THREE.RGBAIntegerFormat, - RGFormat: THREE.RGFormat, - RGIntegerFormat: THREE.RGIntegerFormat, - RedFormat: THREE.RedFormat, - RedIntegerFormat: THREE.RedIntegerFormat, - } - - const encodingOptions = { - BasicDepthPacking: THREE.BasicDepthPacking, - LinearEncoding: THREE.LinearEncoding, - RGBADepthPacking: THREE.RGBADepthPacking, - sRGBEncoding: THREE.sRGBEncoding, - } - - const params = { - map: tex?.image ?? singlePixelImage, - } - - const addInputs = (texture: THREE.Texture) => { - folder.hidden = false - folder.title = `${texture.name} (Texture)`.trim() - - const updateTexture = () => (texture.needsUpdate = true) - - folder.addInput(texture, 'wrapS', { options: wrapOptions }).on('change', updateTexture) - folder.addInput(texture, 'wrapT', { options: wrapOptions }).on('change', updateTexture) - folder.addInput(texture, 'magFilter', { options: magFilterOptions }) - folder.addInput(texture, 'minFilter', { options: minFilterOptions }) - folder.addInput(texture, 'offset', { step: 0.01 }) - folder.addInput(texture, 'rotation', { step: 0.01 }) - folder.addInput(texture, 'anisotropy', { options: anisotropyOptions }).on('change', updateTexture) - folder.addInput(texture, 'format', { options: formatOptions }).on('change', updateTexture) - folder.addInput(texture, 'repeat', { x: { step: 1 }, y: { step: 1 } }) - folder.addInput(texture, 'center') - folder.addInput(texture, 'flipY') - folder.addInput(texture, 'encoding', { options: encodingOptions }).on('change', () => { - updateTexture() - if (object instanceof THREE.Material) { - object.needsUpdate = true - } - }) - - disposer.current = () => { - for (const child of folder.children) { - child.dispose() - } - } - } - - pane.addInput(params, 'map', { - label: property, - view: 'input-image', - }).on('change', ({ value }) => { - if (value.src === singlePixelImage.src) { - return - } - - if (value.src === tex?.image.src) { - return - } - - // @ts-expect-error @TODO Type this better - const oldTexture = object[property] as THREE.Texture | null - oldTexture?.dispose() - - const texture = new THREE.Texture(value) - - // @ts-expect-error @TODO Type this better - object[property] = texture - texture.needsUpdate = true - - if (object instanceof THREE.Material) { - object.needsUpdate = true - } - - disposer.current() - addInputs(texture) - }) - - const folder = pane.addFolder({ hidden: true, title: '' }) - - if (tex) { - addInputs(tex) - } - - return () => disposer.current() -} diff --git a/src_old/inputs/transform.ts b/src_old/inputs/transform.ts deleted file mode 100644 index 968395a..0000000 --- a/src_old/inputs/transform.ts +++ /dev/null @@ -1,134 +0,0 @@ -import * as THREE from 'three' -import { removeUpdate, update } from '../update' -import type { Pane } from '../pane' - -const state = { - controlling: false, -} - -const rotationSettings = { - expanded: false, - picker: 'inline', - rotationMode: 'euler', - view: 'rotation', -} - -const addInstancedMeshInputs = (pane: Pane, mesh: THREE.InstancedMesh) => { - const m4 = new THREE.Matrix4() - - pane.addSeparator() - - const params = { - index: 0, - position: new THREE.Vector3(), - rotation: new THREE.Euler(), - scale: new THREE.Vector3(), - } - - const index = pane.addInput(params, 'index', { - label: 'instance index', - max: mesh.count - 1, - min: 0, - step: 1, - }) - const pos = pane.addInput(params, 'position', { index: 0 }) - const rot = pane.addInput(params, 'rotation', rotationSettings) - const scale = pane.addInput(params, 'scale', { index: 0 }) - - const instanceIndexChange = () => { - mesh.getMatrixAt(params.index, m4) - params.position.setFromMatrixPosition(m4) - params.rotation.setFromRotationMatrix(m4) - params.scale.setFromMatrixScale(m4) - pos.refresh() - rot.refresh() - scale.refresh() - } - - const instanceChange = () => { - m4.makeRotationFromEuler(params.rotation) - m4.setPosition(params.position) - m4.scale(params.scale) - mesh.setMatrixAt(params.index, m4) - mesh.instanceMatrix.needsUpdate = true - } - - index.on('change', instanceIndexChange) - pos.on('change', instanceChange) - rot.on('change', instanceChange) - scale.on('change', instanceChange) - - const handleInstancedMeshUpdate = () => { - if (!state.controlling) { - instanceIndexChange() - } - } - - update(handleInstancedMeshUpdate) - - return () => removeUpdate(handleInstancedMeshUpdate) -} - -const handleDown = () => { - state.controlling = true -} - -const handleUp = () => { - state.controlling = false -} - -export const addTransformInputs = (pane: Pane, object3D: THREE.Object3D) => { - const { element } = pane - - const params = { - rotation: new THREE.Euler(), - } - - const rotationChange = () => { - if (state.controlling) { - object3D.rotation.copy(params.rotation) - } - } - - pane.addSeparator() - const posInput = pane.addInput(object3D, 'position', { step: 0.1 }) - const rotInput = pane.addInput(params, 'rotation', rotationSettings) - .on('change', rotationChange) - const scaleInput = pane.addInput(object3D, 'scale', { step: 0.1 }) - - const handleTransformUpdate = () => { - if (state.controlling) { - return - } - - if (!object3D.rotation.equals(params.rotation)) { - params.rotation.copy(object3D.rotation) - rotInput.refresh() - } - - posInput.refresh() - scaleInput.refresh() - } - - update(handleTransformUpdate) - - let imeshDispose: (() => void) | undefined - - if ('isInstancedMesh' in object3D) { - imeshDispose = addInstancedMeshInputs(pane, object3D as THREE.InstancedMesh) - } - - element.addEventListener('mousedown', handleDown, { passive: true }) - element.addEventListener('mouseup', handleUp, { passive: true }) - - return () => { - element.removeEventListener('mousedown', handleDown) - element.removeEventListener('mouseup', handleUp) - - posInput.dispose() - rotInput.dispose() - scaleInput.dispose() - removeUpdate(handleTransformUpdate) - imeshDispose?.() - } -} diff --git a/src_old/inputs/userdata.ts b/src_old/inputs/userdata.ts deleted file mode 100644 index 7b2cbfb..0000000 --- a/src_old/inputs/userdata.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { Pane } from '../pane' - -export const addUserdataInput = (pane: Pane, object: THREE.Object3D) => { - pane.addSeparator() - - const params = { - userData: JSON.stringify(object.userData, undefined, 2), - } - - const lineCount = params.userData.split(/\r\n|\r|\n/u).length - const monitor = pane.addMonitor(params, 'userData', { - interval: 5000, - lineCount, - multiline: true, - }) - - return () => monitor.dispose() -} diff --git a/src_old/lib/controls.ts b/src_old/lib/controls.ts deleted file mode 100644 index 91edaa5..0000000 --- a/src_old/lib/controls.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' -import { createViewHelper } from '../elements/gizmo' -import { refs } from '../refs' -import { save } from 'trzy' - -export type Cameras = THREE.PerspectiveCamera | THREE.OrthographicCamera - -// eslint-disable-next-line no-shadow -export const enum Controls { - NONE, - ORBIT, - // MAP, -} - -let controls: OrbitControls | undefined - -export const setEnabledControls = (type: Controls, camera: Cameras) => { - const { renderer } = refs - - const savePosition = () => { - save('three-inspect.camera', { - position: camera.position.toArray(), - quaternion: camera.quaternion.toArray(), - target: controls?.target.toArray(), - zoom: camera.zoom, - }) - } - - if (controls !== undefined) { - controls.dispose() - window.removeEventListener('pointerup', savePosition) - window.removeEventListener('wheel', savePosition) - } - - if (type === Controls.ORBIT) { - save('three-inspect.controls', Controls.ORBIT) - controls = new OrbitControls(camera, renderer.domElement) - window.addEventListener('pointerup', savePosition, { passive: true }) - window.addEventListener('wheel', savePosition, { passive: true }) - - createViewHelper() - - /** - * No controls - */ - } else { - save('three-inspect.camera', null) - save('controls', null) - } -} diff --git a/src_old/lib/event-dispatcher.ts b/src_old/lib/event-dispatcher.ts deleted file mode 100644 index c522626..0000000 --- a/src_old/lib/event-dispatcher.ts +++ /dev/null @@ -1,64 +0,0 @@ -/** - * https://github.com/mrdoob/eventdispatcher.js/ - */ - -type Listener = (...args: unknown[]) => void - -class EventDispatcher { - listeners: Record = {} - - addEventListener (type: string, listener: Listener) { - const { listeners } = this - - listeners[type] ??= [] - - const listenerArray = listeners[type]! - - if (!listenerArray.includes(listener)) { - listenerArray.push(listener) - } - } - - hasEventListener (type: string, listener: Listener) { - return this.listeners[type]?.includes(listener) - } - - removeEventListener (type: string, listener: Listener) { - const { listeners } = this - const listenerArray = listeners[type] - - if (listenerArray === undefined) { - return - } - - const index = listenerArray.indexOf(listener) - - if (index !== -1) { - listenerArray.splice(index, 1) - } - } - - dispatchEvent (event: Record & { type: string }) { - const { listeners } = this - const listenerArray = listeners[event.type] - - if (listenerArray === undefined) { - return - } - - event.target = this - - // Make a copy, in case listeners are removed while iterating. - const array = [...listenerArray] - - for (let i = 0, l = array.length; i < l; i += 1) { - array[i].call(this, event) - } - - event.target = undefined - } -} - -export { EventDispatcher } - -export const dispatcher = new EventDispatcher() diff --git a/src_old/lib/image.ts b/src_old/lib/image.ts deleted file mode 100644 index ec17e51..0000000 --- a/src_old/lib/image.ts +++ /dev/null @@ -1,18 +0,0 @@ -export const createSinglePixelImage = () => { - const canvas = document.createElement('canvas') - canvas.width = 1 - canvas.height = 1 - - const ctx = canvas.getContext('2d') - - if (ctx !== null) { - ctx.fillStyle = 'rgba(0,0,0,0)' - ctx.fillRect(0, 0, 1, 1) - } - - const img = document.createElement('img') - img.src = canvas.toDataURL('image/png') - return img -} - -export const singlePixelImage = createSinglePixelImage() diff --git a/src_old/lib/raycast.ts b/src_old/lib/raycast.ts deleted file mode 100644 index 61c4986..0000000 --- a/src_old/lib/raycast.ts +++ /dev/null @@ -1,37 +0,0 @@ -import * as THREE from 'three' -import { dispatcher } from './event-dispatcher' -import { refs } from '../refs' - -export const mouseRaycaster = (onSelect: (intersects: THREE.Intersection[]) => void) => { - const { renderer } = refs - const canvas = renderer.domElement - const raycaster = new THREE.Raycaster() - const pointer = new THREE.Vector2() - - const onPointerDown = (event: MouseEvent) => { - const { scene, camera } = refs - /* - * Calculate pointer position in normalized device coordinates - * (-1 to +1) for both components - */ - pointer.x = ((event.clientX / canvas.clientWidth) * 2) - 1 - pointer.y = -((event.clientY / canvas.clientHeight) * 2) + 1 - - // Update the picking ray with the camera and pointer position - raycaster.setFromCamera(pointer, camera) - - const intersections = raycaster.intersectObjects(scene.children).filter((intersection) => { - return intersection.object.userData.THREE_INSPECT_OMIT !== true - }) - - onSelect(intersections) - } - - dispatcher.addEventListener('enable-select', (event) => { - if ((event as { enabled: boolean }).enabled) { - canvas.addEventListener('pointerdown', onPointerDown, { passive: true }) - } else { - canvas.removeEventListener('pointerdown', onPointerDown) - } - }) -} diff --git a/src_old/lib/rectarealight.ts b/src_old/lib/rectarealight.ts deleted file mode 100644 index 463eeed..0000000 --- a/src_old/lib/rectarealight.ts +++ /dev/null @@ -1,92 +0,0 @@ -import * as THREE from 'three' - -const positions = [ - +1, +1, 0, - -1, +1, 0, - -1, -1, 0, - +1, -1, 0, - +1, +1, 0, -] - -const positions2 = [ - +1, +1, 0, - -1, +1, 0, - -1, -1, 0, - +1, +1, 0, - -1, -1, 0, - +1, -1, 0, -] - -export const createRectAreaLightHelper = (light: THREE.RectAreaLight, color?: THREE.Color) => { - const geometry = new THREE.BufferGeometry() - geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)) - geometry.computeBoundingSphere() - - const material = new THREE.LineBasicMaterial({ fog: false }) - const line = new THREE.Line() - - // @ts-expect-error This is ok :P - line.type = 'RectAreaLightHelper' - - const geometry2 = new THREE.BufferGeometry() - geometry2.setAttribute('position', new THREE.Float32BufferAttribute(positions2, 3)) - geometry2.computeBoundingSphere() - - line.add(new THREE.Mesh(geometry2, new THREE.MeshBasicMaterial({ - fog: false, - side: THREE.BackSide, - }))) - - line.updateMatrixWorld = () => { - line.scale.set(0.5 * light.width, 0.5 * light.height, 1) - - if (color === undefined) { - material.color.copy(light.color).multiplyScalar(light.intensity) - - // Prevent hue shift - const { color: matColor } = material - const max = Math.max(matColor.r, matColor.g, matColor.b) - if (max > 1) { - matColor.multiplyScalar(1 / max) - } - - const child = line.children[0] as THREE.Mesh - const mat = child.material as THREE.MeshBasicMaterial - mat.color.copy(matColor) - } else { - material.color.set(color) - - const child = line.children[0] as THREE.Mesh - const mat = child.material as THREE.MeshBasicMaterial - mat.color.set(color) - } - - // Ignore world scale on light - line.matrixWorld.extractRotation(light.matrixWorld).scale(line.scale) - .copyPosition(light.matrixWorld) - - line.children[0].matrixWorld.copy(line.matrixWorld) - } - - const lineAlias = line as unknown as { dispose: () => void } - - lineAlias.dispose = () => { - line.geometry.dispose() - - { - const lineMaterial = line.material as THREE.MeshBasicMaterial - lineMaterial.dispose() - } - - const child = line.children[0] as THREE.Mesh - - child.geometry.dispose() - - { - const childMaterial = child.material as THREE.MeshBasicMaterial - childMaterial.dispose() - } - } - - return line -} diff --git a/src_old/lib/resizable.ts b/src_old/lib/resizable.ts deleted file mode 100644 index c302e03..0000000 --- a/src_old/lib/resizable.ts +++ /dev/null @@ -1,119 +0,0 @@ -type Sides = 'top' | 'right' | 'bottom' | 'left' - -const RESIZE_HANDLE_SIZE = 3 - -interface Args { - element: HTMLElement - side: Sides - min?: number - max?: number - height?: number - width?: number -} - -const getPosition = (side: Sides) => { - switch (side) { - case 'left': { return 'left: 0;' } - case 'right': { return 'left: calc(100% - 3px);' } - case 'top': { return 'top: 0;' } - case 'bottom': { return 'bottom: 0;' } - default: { return '' } - } -} - -export const resizable = (args: Args) => { - const { - element, - side, - min = 100, - max = 300, - } = args - - let x = 0 - let y = 0 - let width = 0 - let height = 0 - - const horizontal = (side === 'right' || side === 'left') - const dom = document.createElement('div') - const handle = document.createElement('div') - handle.style.cssText = ` - position: absolute; - z-index: 1000; - opacity: 0.5; - background-color: var(--color-resize-handle, #888); - cursor: ${horizontal ? 'ew' : 'ns'}-resize; - ${horizontal ? 'width' : 'height'}: 3px; - ${horizontal ? 'height' : 'width'}: 100%; - ${horizontal ? 'top: 0; bottom: 0;' : 'left: 0; right: 0;'} - ${getPosition(side)} - ` - - const onResizeMove = (event: MouseEvent) => { - event.preventDefault() - event.stopPropagation() - - if (horizontal) { - let offsetX = x - event.clientX - - if (side === 'right') { - offsetX = -offsetX - } - - const w = RESIZE_HANDLE_SIZE + Math.max(min, Math.min(max, (width + offsetX))) - dom.style.width = `${w}px` - } else { - let offsetY = y - event.clientY - - if (side === 'bottom') { - offsetY = -offsetY - } - - const h = Math.max(min, Math.min(max, (height + offsetY))) - dom.style.height = `${h}px` - } - } - - const onResizeEnd = (evt: MouseEvent) => { - evt.preventDefault() - evt.stopPropagation() - - window.removeEventListener('mousemove', onResizeMove) - window.removeEventListener('mouseup', onResizeEnd) - - handle.style.opacity = '0.5' - } - - const onResizeStart = (event: MouseEvent) => { - event.preventDefault() - event.stopPropagation() - - x = event.clientX - y = event.clientY - width = dom.clientWidth - height = dom.clientHeight - - window.addEventListener('mousemove', onResizeMove) - window.addEventListener('mouseup', onResizeEnd) - - handle.style.opacity = '1' - } - - handle.addEventListener('mousedown', onResizeStart) - - dom.style.position = 'relative' - dom.style.overflow = 'hidden' - - dom.append(element) - dom.append(handle) - - if (args.height) { - dom.style.height = `${args.height}px` - } - - if (args.width) { - dom.style.width = `${args.width}px` - } - - return dom -} diff --git a/src_old/main.css b/src_old/main.css deleted file mode 100644 index 10d5525..0000000 --- a/src_old/main.css +++ /dev/null @@ -1,43 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -* { - --bs-br: 0px !important; - scrollbar-width: none; -} - -*::-webkit-scrollbar { - display: none; -} - -.tp-grlv_g { - height: 30px !important -} - -.tp-imgv { - height: 20px !important; - transition: 200ms !important; -} - -.tp-imgv:hover { - height: 80px !important; -} - -.tp-rotv_c { - height: 0 !important; - padding: 0 !important; - margin-top: 5px; - width: 100% !important; -} - -.stats .tp-rotv_c { - height: auto !important -} - -.orbit-controls-gizmo { - position: absolute; - top: 10px; - left: -90px; - z-index: 10; -} \ No newline at end of file diff --git a/src_old/main.ts b/src_old/main.ts deleted file mode 100644 index 23dc5dd..0000000 --- a/src_old/main.ts +++ /dev/null @@ -1,108 +0,0 @@ -import './patch/folders' -import { Controls, setEnabledControls } from './lib/controls' -import { pause, run } from './update' -import type { EffectComposer } from 'postprocessing' -import type { Pane } from './pane' -import css from './main.css?inline' -import { initElements } from './elements' -import { initSceneHelpers } from './folders/scene' -import { load } from 'trzy' -import { refs } from './refs' - -const style = document.createElement('style') -style.textContent = css -document.head.append(style) - -// eslint-disable-next-line no-use-before-define -type Plugin = (inspector: Inspector) => Disposer - -export default class Inspector { - disposers: Disposer[] = [] - - /** - * Adds a new pane and navigation menu item. - * - * @param title This will be shown as a navigation menu item. - * - * @returns a Tweakpane.Pane instance. - */ - addPane: (title: string) => Pane - - /** - * Instantiates the Three.js inspector tools. - * - * @param args Arguments required by three-inspect - * @param args.scene The scene to inspect. - * @param args.camera The current camera. - * @param args.renderer The rendering instance. - * @param args.composer An optional pmndrs/postprocessing EffectComposer instance. - * @param args.options Optional setup and rendering options. - * @param args.options.location The location of the inspector. Defaults to 'right'. Options are 'right', 'overlay'. - * - * @returns A cleanup function to unmount and dispose the inspector. - */ - constructor ({ - scene, - camera, - renderer, - composer, - options = {}, - }: { - scene: THREE.Scene, - camera: THREE.PerspectiveCamera | THREE.OrthographicCamera, - renderer: THREE.WebGLRenderer, - composer?: EffectComposer, - options?: { - location?: 'right' | 'overlay' - } - }) { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (!scene) { - const msg = 'three-inspect constructor arguments have changed. Consult docs for new args: https://www.npmjs.com/package/three-inspect' - throw new Error(msg) - } - - refs.scene = scene - refs.camera = camera - refs.renderer = renderer - refs.composer = composer ?? undefined - - const { disposers, addPane } = initElements({ - location: 'right', - ...options, - }) - - this.addPane = addPane - this.disposers.push(...disposers, initSceneHelpers()) - - const controls = load('three-inspect.controls') - - if (controls !== null) { - setEnabledControls(controls, camera) - } - - run() - } - - /** - * Registers a plugin. - * - * @param plugin A function that passes the inspector as a param and returns a disposer. - */ - registerPlugin (plugin: Plugin) { - this.disposers.push(plugin(this)) - } - - /** - * Disposes the inspector. - */ - dispose = () => { - pause() - - for (let i = this.disposers.length - 1; i > -1; i -= 1) { - this.disposers[i]() - } - - this.disposers.slice(0, this.disposers.length) - } -} diff --git a/src_old/objects.ts b/src_old/objects.ts deleted file mode 100644 index bf8ae0a..0000000 --- a/src_old/objects.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { TreeViewItem } from 'flexible-tree' - -const objectToTreeItem = new WeakMap() -const treeItemToObject = new WeakMap() - -const getObjectType = (object3D: THREE.Object3D) => { - if ('isInstancedMesh' in object3D) { - return 'InstancedMesh' - } - - // @ts-expect-error Need to type meshline - if ((object3D).geometry?.isMeshLine) { - return 'MeshLine' - } - - return object3D.type -} - -export const objectFromTreeItem = (item: TreeViewItem) => { - return treeItemToObject.get(item) -} - -export const treeItemFromObject = (object: THREE.Object3D) => { - return objectToTreeItem.get(object) -} - -export const deregister = (object3D: THREE.Object3D) => { - if (object3D.userData.threeInspectHide === true) { - return - } - - object3D.traverse((child) => object3D !== child && deregister(child)) - - const item = objectToTreeItem.get(object3D) - objectToTreeItem.delete(object3D) - - // @TODO investigate - if (item !== undefined) { - treeItemToObject.delete(item) - item.destroy() - } -} - -const orphaned = new Map() - -export const register = (treeroot: TreeViewItem, object3D: THREE.Object3D, parent: THREE.Object3D) => { - if (object3D.userData.threeInspectHide === true) { - return - } - - const name = object3D.name - const parentItem = 'isScene' in parent ? treeroot : objectToTreeItem.get(parent) - const text = `${name ? `${name} ` : ''}(${getObjectType(object3D)})` - const item = new TreeViewItem({ text }) - item.open = true - objectToTreeItem.set(object3D, item) - treeItemToObject.set(item, object3D) - - if (parentItem) { - parentItem.append(item) - } else if (object3D.parent) { - orphaned.set(object3D.parent.uuid, item) - } - - const orphan = orphaned.get(object3D.uuid) - if (orphan) { - item.append(orphan) - orphaned.delete(object3D.uuid) - } - - { - const { children } = object3D - - for (let i = 0, l = children.length; i < l; i += 1) { - register(treeroot, children[i], object3D) - } - } -} diff --git a/src_old/pane/index.ts b/src_old/pane/index.ts deleted file mode 100644 index 63e2e5b..0000000 --- a/src_old/pane/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -import * as EssentialsPlugin from '@tweakpane/plugin-essentials' -import * as ImagePlugin from 'tweakpane-image-plugin' -import * as RotationPlugin from '@0b5vr/tweakpane-plugin-rotation' -import * as TextareaPlugin from '@pangenerator/tweakpane-textarea-plugin' -import * as Tweakpane from 'tweakpane' - -export type Pane = Tweakpane.Pane | Tweakpane.FolderApi - -export let pane: Pane - -export const createPane = (container?: HTMLElement) => { - const nextPane = new Tweakpane.Pane({ container }) - nextPane.registerPlugin(EssentialsPlugin) - nextPane.registerPlugin(ImagePlugin) - nextPane.registerPlugin(RotationPlugin) - nextPane.registerPlugin(TextareaPlugin) - return nextPane -} diff --git a/src_old/patch/folders.ts b/src_old/patch/folders.ts deleted file mode 100644 index fc6bc32..0000000 --- a/src_old/patch/folders.ts +++ /dev/null @@ -1,38 +0,0 @@ -import * as Tweakpane from 'tweakpane' -import { load, save } from 'trzy' - -type Pane = Tweakpane.Pane | Tweakpane.FolderApi - -const folders: Pane[] = [] - -const addFolder = Tweakpane.FolderApi.prototype.addFolder -const dispose = Tweakpane.FolderApi.prototype.dispose - -Tweakpane.FolderApi.prototype.addFolder = function (params: Tweakpane.FolderParams) { - const id = `${String(params.index ?? -1)}.${params.title}` - - const folder = addFolder.call(this, { - expanded: load(`pane.${id}`) !== null, - ...params, - }) - folders.push(folder) - - folder.element.id = id - - folder.on('fold', (event) => { - const key = `pane.${id}` - - if (event.expanded) { - save(key, true) - } else { - save(key, null) - } - }) - - return folder -} - -Tweakpane.FolderApi.prototype.dispose = function () { - dispose.call(this) - folders.splice(folders.indexOf(this), 1) -} diff --git a/src_old/patch/object3d.ts b/src_old/patch/object3d.ts deleted file mode 100644 index 1c7ade0..0000000 --- a/src_old/patch/object3d.ts +++ /dev/null @@ -1,47 +0,0 @@ -import * as THREE from 'three' -import { deregister, register } from '../objects' -import type { TreeViewItem } from 'flexible-tree' - -export const patchObject3d = (treeroot: TreeViewItem) => { - const add = THREE.Object3D.prototype.add - const remove = THREE.Object3D.prototype.remove - const clear = THREE.Object3D.prototype.clear - - THREE.Object3D.prototype.add = function (...object: THREE.Object3D[]) { - add.call(this, ...object) - - for (let i = 0, l = object.length; i < l; i += 1) { - register(treeroot, object[i], this) - } - - return this - } - - THREE.Object3D.prototype.remove = function (...object: THREE.Object3D[]) { - remove.call(this, ...object) - - for (let i = 0, l = object.length; i < l; i += 1) { - deregister(object[i]) - } - - return this - } - - THREE.Object3D.prototype.clear = function () { - const { children } = this - - clear.call(this) - - for (let i = 0, l = children.length; i < l; i += 1) { - deregister(children[i]) - } - - return this - } - - return () => { - THREE.Object3D.prototype.add = add - THREE.Object3D.prototype.remove = remove - THREE.Object3D.prototype.clear = clear - } -} diff --git a/src_old/refs.ts b/src_old/refs.ts deleted file mode 100644 index 1517801..0000000 --- a/src_old/refs.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type * as THREE from 'three' -import type { EffectComposer } from 'postprocessing' - -interface Refs { - camera: THREE.Camera - composer: EffectComposer | undefined - renderer: THREE.WebGLRenderer - scene: THREE.Scene - root: HTMLElement - debugRoot: HTMLElement -} - -export const refs: Refs = { - camera: undefined!, - composer: undefined, - debugRoot: undefined!, - renderer: undefined!, - root: undefined!, - scene: undefined!, -} diff --git a/src_old/scene.ts b/src_old/scene.ts deleted file mode 100644 index e786e18..0000000 --- a/src_old/scene.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { type Cameras, addCameraInputs } from './inputs/camera' -import type { TreeView, TreeViewItem } from 'flexible-tree' -import { deregister, objectFromTreeItem, register, treeItemFromObject } from './objects' -import { addLightInputs } from './inputs/lights' -import { addObjectInputs } from './inputs/object3d' -import { addSceneInputs } from './folders/scene' -import { createPane } from './pane' -import { mouseRaycaster } from './lib/raycast' -import { patchObject3d } from './patch/object3d' -import { refs } from './refs' -import { save } from 'trzy' - -type Disposer = () => void - -const handleSelectItem = (root: HTMLElement, object3D: THREE.Object3D) => { - if (object3D.name) { - save('three-inspect.selected', object3D.name) - } - - const pane = createPane(root) - - let disposers: Disposer[] - - if ('isPerspectiveCamera' in object3D || 'isOrthographicCamera' in object3D) { - disposers = addCameraInputs(pane, object3D as Cameras) - } else if ('isScene' in object3D) { - disposers = addSceneInputs(pane) - } else if ('isLight' in object3D) { - disposers = addLightInputs(pane, object3D as THREE.Light) - } else { - disposers = addObjectInputs(pane, object3D) - } - - return () => { - disposers.forEach((disposer) => disposer()) - pane.dispose() - } -} - -export const initScene = ( - tree: TreeView, - treeroot: TreeViewItem, - root: HTMLElement -) => { - const { scene } = refs - const disposePatcher = patchObject3d(treeroot) - - let selected: TreeViewItem | undefined - - mouseRaycaster((intersects) => { - if (intersects.length < 1) { - return - } - - let treeItem: TreeViewItem | undefined - - - while (treeItem === undefined) { - const intersect = intersects.shift() - - if (intersect === undefined) { - break - } - - treeItem = treeItemFromObject(intersect.object) - } - - if (treeItem !== undefined) { - if (selected !== undefined) { - selected.selected = false - } - treeItem.selected = true - treeItem.dom.scrollIntoView() - } - }) - - let disposer: null | (() => void) = null - - tree.on('deselect', () => { - disposer?.() - disposer = null - selected = undefined - }) - - tree.on('select', (item: TreeViewItem) => { - disposer?.() - disposer = null - selected = item - - const object3D = item.text === 'Scene' ? scene : objectFromTreeItem(item) - - if (object3D !== undefined) { - disposer = handleSelectItem(root, object3D) - } - }) - - tree.on('reparent', (items: { item: TreeViewItem, newParent: TreeViewItem }[]) => { - for (let i = 0, l = items.length; i < l; i += 1) { - const { item, newParent } = items[i] - const child = objectFromTreeItem(item) - const parent = newParent.text === 'Scene' ? scene : objectFromTreeItem(newParent) - - if (parent !== undefined && child !== undefined) { - parent.attach(child) - } - } - }) - - { - const { children } = scene - for (let i = 0, l = children.length; i < l; i += 1) { - register(treeroot, children[i], scene) - } - } - - const deregisterAll = () => { - const { children } = scene - - for (let i = 0, l = children.length; i < l; i += 1) { - deregister(children[i]) - } - } - - return () => { - disposePatcher() - tree.clearTreeItems() - deregisterAll() - } -} diff --git a/src_old/update.ts b/src_old/update.ts deleted file mode 100644 index 4916820..0000000 --- a/src_old/update.ts +++ /dev/null @@ -1,39 +0,0 @@ -type Callback = () => void - -let handle = -1 - -const callbacks: Callback[] = [] - -const loop = () => { - for (let i = 0, l = callbacks.length; i < l; i += 1) { - callbacks[i]() - } - - handle = requestAnimationFrame(loop) -} - -/** - * Starts the animation loop. - */ -export const run = () => { - handle = requestAnimationFrame(loop) -} - -/** - * Pauses the animation looop. - */ -export const pause = () => { - cancelAnimationFrame(handle) -} - -/** - * Registers a callback that will be executed on each frame. - * @param callback The callback to execute on each frame. - */ -export const update = (callback: Callback) => { - callbacks.push(callback) -} - -export const removeUpdate = (callback: Callback) => { - callbacks.splice(callbacks.indexOf(callback), 1) -}