diff options
| author | victor | 2026-10-24 15:57:01 +0200 |
|---|---|---|
| committer | victor | 2026-10-24 15:57:01 +0200 |
| commit | 4533910bce394e7a0ee6debfc05ca1221ee51899 (patch) | |
| tree | 73aaa5b2c7a48dbf226e6b81d499ba1a8ecc33a1 /src/scene/primitives.ts | |
| parent | Tilføj dansk (diff) | |
| download | 3D-Electrophysics-4533910bce394e7a0ee6debfc05ca1221ee51899.tar.gz 3D-Electrophysics-4533910bce394e7a0ee6debfc05ca1221ee51899.zip | |
Astra!ny-start
Diffstat (limited to 'src/scene/primitives.ts')
| -rw-r--r-- | src/scene/primitives.ts | 107 |
1 files changed, 0 insertions, 107 deletions
diff --git a/src/scene/primitives.ts b/src/scene/primitives.ts deleted file mode 100644 index 384ea1d..0000000 --- a/src/scene/primitives.ts +++ /dev/null @@ -1,107 +0,0 @@ -import * as THREE from 'three'; -import { CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js'; -import { renderProse } from '../math'; -import type { Point } from '../physics/electricField'; - -export const colours = { positive: '#ff967b', negative: '#73d7ff', field: '#91e2cb', gold: '#f5d58b', muted: '#8294a8' }; -export const vector = (p: Point) => new THREE.Vector3(p.x, p.y, p.z); -export function sphere(group: THREE.Group, position: Point, radius: number, colour: string): THREE.Mesh { - const mesh = new THREE.Mesh(new THREE.SphereGeometry(radius, 18, 12), new THREE.MeshStandardMaterial({ color: colour, roughness: 0.3, emissive: colour, emissiveIntensity: 0.12 })); - mesh.position.copy(vector(position)); - group.add(mesh); - return mesh; -} -export function box(group: THREE.Group, position: Point, dimensions: Point, colour: string, opacity = 1): THREE.Mesh { - const mesh = new THREE.Mesh(new THREE.BoxGeometry(dimensions.x, dimensions.y, dimensions.z), new THREE.MeshStandardMaterial({ color: colour, transparent: opacity < 1, opacity, depthWrite: opacity === 1, side: THREE.DoubleSide, roughness: 0.45 })); - mesh.position.copy(vector(position)); - group.add(mesh); - return mesh; -} -export function line(group: THREE.Group, points: Point[], colour: string, opacity = 1): THREE.Line { - const mesh = new THREE.Line(new THREE.BufferGeometry().setFromPoints(points.map(vector)), new THREE.LineBasicMaterial({ color: colour, transparent: opacity < 1, opacity })); - group.add(mesh); - return mesh; -} -export function arrow(group: THREE.Group, origin: Point, direction: Point, length: number, colour = colours.field): void { - const dir = vector(direction); - if (dir.lengthSq() < 1e-24) return; - group.add(new THREE.ArrowHelper(dir.normalize(), vector(origin), length, colour, Math.min(0.16, length * 0.3), Math.min(0.1, length * 0.2))); -} -export function label(group: THREE.Group, text: string, position: Point, colour: string = '#dbe7f0', width = 2, minViewportWidth = 0): THREE.Sprite | CSS2DObject { - if (text.includes('$')) { - const element = document.createElement('div'); - element.className = 'scene-math-label'; - element.style.color = colour; - renderProse(element, text); - const annotation = new CSS2DObject(element); - annotation.position.copy(vector(position)); - annotation.onBeforeRender = () => { - element.style.visibility = (element.parentElement?.clientWidth ?? Infinity) < minViewportWidth ? 'hidden' : 'visible'; - }; - group.add(annotation); - return annotation; - } - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d')!; - context.font = '500 44px system-ui, sans-serif'; - canvas.width = Math.ceil(context.measureText(text).width) + 36; - canvas.height = 80; - context.fillStyle = 'rgba(16, 24, 34, 0.85)'; - context.fillRect(0, 0, canvas.width, canvas.height); - context.font = '500 44px system-ui, sans-serif'; - context.fillStyle = colour; - context.textAlign = 'center'; - context.textBaseline = 'middle'; - context.fillText(text, canvas.width / 2, 40); - const texture = new THREE.CanvasTexture(canvas); - texture.colorSpace = THREE.SRGBColorSpace; - const sprite = new THREE.Sprite(new THREE.SpriteMaterial({ map: texture, depthTest: false })); - sprite.position.copy(vector(position)); - const aspect = canvas.width / canvas.height; - const screenHeight = 23 + Math.min(2, Math.max(-1, width - 2)) * 2; - const viewportSize = new THREE.Vector2(); - const cameraPosition = new THREE.Vector3(); - // Keep labels legible when the camera or viewport changes. Width hints - // affect text size slightly; the actual texture fits the text content. - sprite.onBeforeRender = (renderer, _scene, camera) => { - if (!(camera instanceof THREE.PerspectiveCamera)) return; - sprite.getWorldPosition(cameraPosition).applyMatrix4(camera.matrixWorldInverse); - renderer.getSize(viewportSize); - sprite.material.opacity = viewportSize.x < minViewportWidth ? 0 : 1; - const responsiveHeight = viewportSize.x < 600 ? screenHeight * 0.78 : screenHeight; - const worldHeight = 2 * Math.abs(cameraPosition.z) * Math.tan(THREE.MathUtils.degToRad(camera.getEffectiveFOV()) / 2) * responsiveHeight / Math.max(1, viewportSize.y); - sprite.scale.set(worldHeight * aspect, worldHeight, 1); - sprite.updateMatrixWorld(); - }; - group.add(sprite); - return sprite; -} -export function grid(group: THREE.Group, y = -0.25) { - const helper = new THREE.GridHelper(12, 12, 0x375066, 0x22313f); - helper.position.y = y; - group.add(helper); -} - -/** Dispose shared geometries/materials once per scene replacement, including - * textures owned by generated labels. No GPU resources survive a lesson. */ -export function disposeGroup(group: THREE.Group) { - const geometries = new Set<THREE.BufferGeometry>(); - const materials = new Set<THREE.Material>(); - const textures = new Set<THREE.Texture>(); - group.traverse(object => { - const mesh = object as THREE.Mesh; - if (mesh.geometry) geometries.add(mesh.geometry); - if (mesh.material) { - const list = Array.isArray(mesh.material) ? mesh.material : [mesh.material]; - for (const material of list) { - materials.add(material); - const map = (material as THREE.MeshBasicMaterial).map; - if (map) textures.add(map); - } - } - }); - geometries.forEach(geometry => geometry.dispose()); - materials.forEach(material => material.dispose()); - textures.forEach(texture => texture.dispose()); - group.clear(); -} |