| /* eslint-disable */ | /* eslint-disable */ | ||||
| import {Camera, Mesh, MOUSE, Object3D, Quaternion, Raycaster, Vector3} from 'three'; | |||||
| import { | |||||
| Camera, | |||||
| LineBasicMaterial, | |||||
| Mesh, | |||||
| MeshBasicMaterial, | |||||
| MOUSE, | |||||
| Object3D, | |||||
| Quaternion, | |||||
| Raycaster, | |||||
| Vector3 | |||||
| } from 'three'; | |||||
| export class TransformControls extends Object3D { | export class TransformControls extends Object3D { | ||||
| constructor(object: Camera, domElement?: HTMLElement); | constructor(object: Camera, domElement?: HTMLElement); | ||||
| setSpace(space: 'world' | 'local'): void; | setSpace(space: 'world' | 'local'): void; | ||||
| reset(): void; | reset(): void; | ||||
| dispose(): void; | dispose(): void; | ||||
| static ObjectConstructors: { | |||||
| MeshBasicMaterial: typeof MeshBasicMaterial; | |||||
| LineBasicMaterial: typeof LineBasicMaterial; | |||||
| } | |||||
| } | } | ||||
| export class TransformControlsGizmo extends Object3D { | export class TransformControlsGizmo extends Object3D { |
| } | } | ||||
| TransformControls.ObjectConstructors = { | |||||
| 'MeshBasicMaterial': MeshBasicMaterial, | |||||
| 'LineBasicMaterial': LineBasicMaterial, | |||||
| }; | |||||
| // mouse / touch event handlers | // mouse / touch event handlers | ||||
| function getPointer( event ) { | function getPointer( event ) { | ||||
| // shared materials | // shared materials | ||||
| const gizmoMaterial = new MeshBasicMaterial( { | |||||
| const gizmoMaterial = new TransformControls.ObjectConstructors.MeshBasicMaterial( { | |||||
| depthTest: false, | depthTest: false, | ||||
| depthWrite: false, | depthWrite: false, | ||||
| fog: false, | fog: false, | ||||
| transparent: true | transparent: true | ||||
| } ); | } ); | ||||
| const gizmoLineMaterial = new LineBasicMaterial( { | |||||
| const gizmoLineMaterial = new TransformControls.ObjectConstructors.LineBasicMaterial( { | |||||
| depthTest: false, | depthTest: false, | ||||
| depthWrite: false, | depthWrite: false, | ||||
| fog: false, | fog: false, | ||||
| super( | super( | ||||
| new PlaneGeometry( 100000, 100000, 2, 2 ), | new PlaneGeometry( 100000, 100000, 2, 2 ), | ||||
| new MeshBasicMaterial( { visible: false, wireframe: true, side: DoubleSide, transparent: true, opacity: 0.1, toneMapped: false } ) | |||||
| new TransformControls.ObjectConstructors.MeshBasicMaterial( { visible: false, wireframe: true, side: DoubleSide, transparent: true, opacity: 0.1, toneMapped: false } ) | |||||
| ); | ); | ||||
| this.isTransformControlsPlane = true; | this.isTransformControlsPlane = true; |
| import {TransformControls} from './TransformControls.js' | import {TransformControls} from './TransformControls.js' | ||||
| import {MathUtils} from 'three' | import {MathUtils} from 'three' | ||||
| import {ICamera, IObject3D, iObjectCommons, ISceneEvent, IWidget} from '../../core' | |||||
| import type {ICamera, IObject3D, ISceneEvent, IWidget} from '../../core' | |||||
| import {iObjectCommons} from '../../core' | |||||
| import {uiDropdown, uiNumber, uiPanelContainer, uiToggle} from 'uiconfig.js' | import {uiDropdown, uiNumber, uiPanelContainer, uiToggle} from 'uiconfig.js' | ||||
| @uiPanelContainer('Transform Controls') | @uiPanelContainer('Transform Controls') |
| export {OrbitControls3, type TOrbitControlsEvents} from './controls/OrbitControls3' | export {OrbitControls3, type TOrbitControlsEvents} from './controls/OrbitControls3' | ||||
| export {TransformControls2} from './controls/TransformControls2' | |||||
| export {TransformControls, TransformControlsGizmo, TransformControlsPlane} from './controls/TransformControls' | |||||
| export {Box3B} from './math/Box3B' | export {Box3B} from './math/Box3B' | ||||
| export * from './utils/index' | export * from './utils/index' | ||||
| export * from './widgets/index' |
| export {getTextureDataType, textureToCanvas, textureDataToImageData, textureToDataUrl, textureToBlob, texImageToCanvas} from './texture' | export {getTextureDataType, textureToCanvas, textureDataToImageData, textureToDataUrl, textureToBlob, texImageToCanvas} from './texture' | ||||
| export {threeConstMappings} from './const-mappings' | export {threeConstMappings} from './const-mappings' | ||||
| export {ObjectPicker} from './ObjectPicker' | export {ObjectPicker} from './ObjectPicker' | ||||
| export {SelectionWidget, BoxSelectionWidget} from './SelectionWidget' | |||||
| export {autoGPUInstanceMeshes} from './gpu-instancing' | export {autoGPUInstanceMeshes} from './gpu-instancing' | ||||
| export {ViewHelper2, type GizmoOrientation, type DomPlacement} from './ViewHelper2' | export {ViewHelper2, type GizmoOrientation, type DomPlacement} from './ViewHelper2' | ||||
| export {TransformControls2} from './TransformControls2' | |||||
| export {TransformControls, TransformControlsGizmo, TransformControlsPlane} from './TransformControls' | |||||
| // export {} from './constants' | // export {} from './constants' |
| import {Camera} from 'three' | |||||
| import {IUiConfigContainer} from 'uiconfig.js' | |||||
| import {AHelperWidget} from './AHelperWidget' | |||||
| export abstract class ACameraHelperWidget extends AHelperWidget { | |||||
| camera: (Camera & IUiConfigContainer) | undefined | |||||
| protected constructor(object: Camera & IUiConfigContainer) { | |||||
| super(object) | |||||
| this.camera = object | |||||
| this.traverse(o => { | |||||
| o.userData.__keepShadowDef = true | |||||
| o.castShadow = false | |||||
| o.receiveShadow = false | |||||
| }) | |||||
| } | |||||
| } |
| import {Object3D, PerspectiveCamera} from 'three' | |||||
| import {generateUiFolder, IUiConfigContainer, uiToggle} from 'uiconfig.js' | |||||
| import {iObjectCommons, IWidget} from '../../core' | |||||
| import {onChange2} from 'ts-browser-helpers' | |||||
| export abstract class AHelperWidget extends Object3D implements IWidget { | |||||
| modelObject = this | |||||
| isWidget = true as const | |||||
| assetType = 'widget' | |||||
| object: (Object3D & IUiConfigContainer) | undefined | |||||
| @uiToggle() | |||||
| @onChange2(AHelperWidget.prototype.update) | |||||
| visible = true | |||||
| protected constructor(object: Object3D & IUiConfigContainer) { | |||||
| super() | |||||
| this.object = object | |||||
| this.object.updateMatrixWorld() | |||||
| if ((this.object as PerspectiveCamera).updateProjectionMatrix) | |||||
| (this.object as PerspectiveCamera).updateProjectionMatrix() | |||||
| this.matrix = object.matrixWorld | |||||
| this.matrixAutoUpdate = false | |||||
| this._objectUpdate = this._objectUpdate.bind(this) | |||||
| this.attach(object) | |||||
| this.traverse(o => { | |||||
| o.userData.__keepShadowDef = true | |||||
| o.castShadow = false | |||||
| o.receiveShadow = false | |||||
| }) | |||||
| } | |||||
| dispose() { | |||||
| this.detach() | |||||
| } | |||||
| update() { | |||||
| iObjectCommons.setDirty.call(this) | |||||
| } | |||||
| private _objectUpdate() { | |||||
| if (this.object) this.update() | |||||
| } | |||||
| attach(object: Object3D): this { | |||||
| if (this.object) this.detach() | |||||
| this.object = object | |||||
| if (this.object) { | |||||
| this.update() | |||||
| this.object.addEventListener('objectUpdate', this._objectUpdate) | |||||
| this.object.addEventListener('dispose', this.dispose) | |||||
| this.uiConfig && this.object.uiConfig?.children?.push(this.uiConfig) | |||||
| this.visible = true | |||||
| } | |||||
| return this | |||||
| } | |||||
| detach(): this { | |||||
| if (this.object) { | |||||
| this.object.removeEventListener('objectUpdate', this._objectUpdate) | |||||
| this.object.removeEventListener('dispose', this.dispose) | |||||
| if (this.uiConfig) { | |||||
| const i = this.object.uiConfig?.children?.indexOf(this.uiConfig) | |||||
| if (i !== undefined && i >= 0) | |||||
| this.object.uiConfig?.children?.splice(i, 1) | |||||
| } | |||||
| this.object = undefined | |||||
| this.visible = false | |||||
| } | |||||
| return this | |||||
| } | |||||
| uiConfig = generateUiFolder('Widget', this) | |||||
| } | |||||
| import {Light} from 'three' | |||||
| import {IUiConfigContainer} from 'uiconfig.js' | |||||
| import {AHelperWidget} from './AHelperWidget' | |||||
| export abstract class ALightHelperWidget extends AHelperWidget { | |||||
| light: (Light & IUiConfigContainer)|undefined | |||||
| protected constructor(object: Light & IUiConfigContainer) { | |||||
| super(object) | |||||
| this.light = object | |||||
| this.traverse(o => { | |||||
| o.userData.__keepShadowDef = true | |||||
| o.castShadow = false | |||||
| o.receiveShadow = false | |||||
| }) | |||||
| } | |||||
| } |
| import {LineMaterial2} from '../../core/material/LineMaterial2' | |||||
| import {Vector2} from 'three' | |||||
| import {LineSegmentsGeometry} from 'three/examples/jsm/lines/LineSegmentsGeometry.js' | |||||
| import {LineSegments2} from 'three/examples/jsm/lines/LineSegments2.js' | |||||
| import {Box3B} from '../math/Box3B' | |||||
| import {SelectionWidget} from './SelectionWidget' | |||||
| export class BoxSelectionWidget extends SelectionWidget { | |||||
| constructor() { | |||||
| super() | |||||
| const matLine = new LineMaterial2({ | |||||
| color: '#ff2222' as any, transparent: true, opacity: 0.9, | |||||
| linewidth: 5, // in pixels | |||||
| resolution: new Vector2(1024, 1024), // to be set by renderer, eventually | |||||
| dashed: false, | |||||
| toneMapped: false, | |||||
| }) | |||||
| this.lineMaterial = matLine | |||||
| const ls = new LineSegmentsGeometry() | |||||
| ls.setPositions([1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1].map(v => v - 0.5)) | |||||
| const wireframe = new LineSegments2(ls, matLine as any) | |||||
| wireframe.computeLineDistances() | |||||
| wireframe.scale.set(1, 1, 1) | |||||
| wireframe.visible = true | |||||
| this.add(wireframe) | |||||
| } | |||||
| protected _updater() { | |||||
| super._updater() | |||||
| const selected = this.object | |||||
| if (selected) { | |||||
| const bbox = new Box3B().expandByObject(selected, false) | |||||
| // const scale = bbox.getBoundingSphere(new Sphere()).radius | |||||
| bbox.getSize(this.scale).multiplyScalar(this.boundingScaleMultiplier).clampScalar(0.1, 100) | |||||
| this.setVisible(true) | |||||
| } | |||||
| } | |||||
| } |
| import {Camera, Color, Object3D, OrthographicCamera, PerspectiveCamera, Vector3} from 'three' | |||||
| import {ACameraHelperWidget} from './ACameraHelperWidget' | |||||
| import {LineSegments2} from 'three/examples/jsm/lines/LineSegments2.js' | |||||
| import {LineSegmentsGeometry} from 'three/examples/jsm/lines/LineSegmentsGeometry.js' | |||||
| import {InterleavedBufferAttribute} from 'three/src/core/InterleavedBufferAttribute' | |||||
| import {LineMaterial2} from '../../core' | |||||
| /** | |||||
| * Fork of CameraHelper from three.js | |||||
| * - shows frustum, line of sight and up of the camera | |||||
| * - suitable for fast updates | |||||
| * - based on frustum visualization in lightgl.js shadowmap example | |||||
| * https://github.com/evanw/lightgl.js/blob/master/tests/shadowmap.html | |||||
| */ | |||||
| export class CameraHelper2 extends ACameraHelperWidget { | |||||
| protected _vector = new Vector3() | |||||
| // @ts-expect-error update three-ts-types remove abstract | |||||
| protected _camera = new Camera() | |||||
| line: LineSegments2 | |||||
| pointMap: Record<string, number[]> | |||||
| constructor(camera: PerspectiveCamera|OrthographicCamera) { | |||||
| super(camera) | |||||
| const geometry = new LineSegmentsGeometry() | |||||
| const material = new LineMaterial2({ | |||||
| color: 0xffffff, | |||||
| linewidth: 0.005, // in world units with size attenuation, pixels otherwise | |||||
| vertexColors: true, | |||||
| dashed: false, | |||||
| alphaToCoverage: true, | |||||
| toneMapped: false, | |||||
| transparent: true, | |||||
| depthTest: false, | |||||
| depthWrite: false, | |||||
| }) | |||||
| const {vertices, colors, pointMap} = generateVertices() | |||||
| geometry.setPositions(vertices) | |||||
| geometry.setColors(colors) | |||||
| // @ts-expect-error update three-ts-types | |||||
| this.line = new LineSegments2(geometry, material) | |||||
| this.line.frustumCulled = false | |||||
| this.add(this.line) | |||||
| this.pointMap = pointMap | |||||
| this.update() | |||||
| // colors | |||||
| const colorFrustum = new Color(0xffaa00) | |||||
| const colorCone = new Color(0xff0000) | |||||
| const colorUp = new Color(0x00aaff) | |||||
| const colorTarget = new Color(0xffffff) | |||||
| const colorCross = new Color(0x333333) | |||||
| this.setColors(colorFrustum, colorCone, colorUp, colorTarget, colorCross) | |||||
| } | |||||
| setColors(frustum: Color, cone: Color, up: Color, target: Color, cross: Color) { | |||||
| const geometry = this.line.geometry | |||||
| const colorAttribute = geometry.getAttribute('instanceColorStart') | |||||
| const colorAttribute2 = geometry.getAttribute('instanceColorEnd') | |||||
| function setXYZ(i: number, color: Color) { | |||||
| colorAttribute.setXYZ(i / 2, color.r, color.g, color.b) | |||||
| colorAttribute2.setXYZ(i / 2, color.r, color.g, color.b) | |||||
| } | |||||
| // near | |||||
| setXYZ(0, frustum) // n1, n2 | |||||
| setXYZ(2, frustum) // n2, n4 | |||||
| setXYZ(4, frustum) // n4, n3 | |||||
| setXYZ(6, frustum) // n3, n1 | |||||
| // far | |||||
| setXYZ(8, frustum) // f1, f2 | |||||
| setXYZ(10, frustum) // f2, f4 | |||||
| setXYZ(12, frustum) // f4, f3 | |||||
| setXYZ(14, frustum) // f3, f1 | |||||
| // sides | |||||
| setXYZ(16, frustum) // n1, f1 | |||||
| setXYZ(18, frustum) // n2, f2 | |||||
| setXYZ(20, frustum) // n3, f3 | |||||
| setXYZ(22, frustum) // n4, f4 | |||||
| // cone | |||||
| setXYZ(24, cone) // p, n1 | |||||
| setXYZ(26, cone) // p, n2 | |||||
| setXYZ(28, cone) // p, n3 | |||||
| setXYZ(30, cone) // p, n4 | |||||
| // up | |||||
| setXYZ(32, up) // u1, u2 | |||||
| setXYZ(34, up) // u2, u3 | |||||
| setXYZ(36, up) // u3, u1 | |||||
| // target | |||||
| setXYZ(38, target) // c, t | |||||
| setXYZ(40, cross) // p, c | |||||
| // cross | |||||
| setXYZ(42, cross) // cn1, cn2 | |||||
| setXYZ(44, cross) // cn3, cn4 | |||||
| setXYZ(46, cross) // cf1, cf2 | |||||
| setXYZ(48, cross) // cf3, cf4 | |||||
| colorAttribute.needsUpdate = true | |||||
| colorAttribute2.needsUpdate = true | |||||
| } | |||||
| update() { | |||||
| if (!this.camera) return | |||||
| const geometry = this.line.geometry | |||||
| const pointMap = this.pointMap | |||||
| const w = 1, h = 1 | |||||
| // we need just camera projection matrix inverse | |||||
| // world matrix must be identity | |||||
| // eslint-disable-next-line @typescript-eslint/naming-convention | |||||
| const {_camera, _vector} = this | |||||
| _camera.projectionMatrixInverse.copy(this.camera.projectionMatrixInverse) | |||||
| // center / target | |||||
| setPoint('c', pointMap, geometry, _camera, 0, 0, -1, _vector) | |||||
| setPoint('t', pointMap, geometry, _camera, 0, 0, 1, _vector) | |||||
| // near | |||||
| setPoint('n1', pointMap, geometry, _camera, -w, -h, -1, _vector) | |||||
| setPoint('n2', pointMap, geometry, _camera, w, -h, -1, _vector) | |||||
| setPoint('n3', pointMap, geometry, _camera, -w, h, -1, _vector) | |||||
| setPoint('n4', pointMap, geometry, _camera, w, h, -1, _vector) | |||||
| // far | |||||
| setPoint('f1', pointMap, geometry, _camera, -w, -h, 1, _vector) | |||||
| setPoint('f2', pointMap, geometry, _camera, w, -h, 1, _vector) | |||||
| setPoint('f3', pointMap, geometry, _camera, -w, h, 1, _vector) | |||||
| setPoint('f4', pointMap, geometry, _camera, w, h, 1, _vector) | |||||
| // up | |||||
| setPoint('u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, -1, _vector) | |||||
| setPoint('u2', pointMap, geometry, _camera, -w * 0.7, h * 1.1, -1, _vector) | |||||
| setPoint('u3', pointMap, geometry, _camera, 0, h * 2, -1, _vector) | |||||
| // cross | |||||
| setPoint('cf1', pointMap, geometry, _camera, -w, 0, 1, _vector) | |||||
| setPoint('cf2', pointMap, geometry, _camera, w, 0, 1, _vector) | |||||
| setPoint('cf3', pointMap, geometry, _camera, 0, -h, 1, _vector) | |||||
| setPoint('cf4', pointMap, geometry, _camera, 0, h, 1, _vector) | |||||
| setPoint('cn1', pointMap, geometry, _camera, -w, 0, -1, _vector) | |||||
| setPoint('cn2', pointMap, geometry, _camera, w, 0, -1, _vector) | |||||
| setPoint('cn3', pointMap, geometry, _camera, 0, -h, -1, _vector) | |||||
| setPoint('cn4', pointMap, geometry, _camera, 0, h, -1, _vector) | |||||
| geometry.getAttribute('instanceStart').needsUpdate = true | |||||
| geometry.getAttribute('instanceEnd').needsUpdate = true | |||||
| geometry.computeBoundingBox() | |||||
| geometry.computeBoundingSphere() | |||||
| super.update() | |||||
| } | |||||
| dispose() { | |||||
| this.line.geometry.dispose() | |||||
| this.line.material.dispose() | |||||
| super.dispose() | |||||
| } | |||||
| static Check(camera: Object3D) { | |||||
| return (camera as any).isCamera | |||||
| } | |||||
| static Create(camera: Object3D) { | |||||
| return new CameraHelper2(camera as any) | |||||
| } | |||||
| } | |||||
| function setPoint(point: string, pointMap: Record<string, number[]>, geometry: LineSegmentsGeometry, camera: Camera, x: number, y: number, z: number, _vector: Vector3) { | |||||
| _vector.set(x, y, z).unproject(camera) | |||||
| const points = pointMap[ point ] | |||||
| if (points !== undefined) { | |||||
| const position1 = geometry.getAttribute('instanceStart') as InterleavedBufferAttribute | |||||
| const position2 = geometry.getAttribute('instanceEnd') as InterleavedBufferAttribute | |||||
| for (let i = 0, l = points.length; i < l; i++) { | |||||
| const j = Math.floor(points[ i ] / 2.) | |||||
| ;(points[ i ] % 2 === 0 ? position1 : position2).setXYZ(j, _vector.x, _vector.y, _vector.z) | |||||
| // (i % 2 === 0 ? position1 : position2).setXYZ(points[ i ], _vector.x, _vector.y, _vector.z) | |||||
| } | |||||
| } | |||||
| } | |||||
| function generateVertices() { | |||||
| const vertices: number[] = [] | |||||
| const colors: number[] = [] | |||||
| const pointMap: any = {} | |||||
| // near | |||||
| addLine('n1', 'n2') | |||||
| addLine('n2', 'n4') | |||||
| addLine('n4', 'n3') | |||||
| addLine('n3', 'n1') | |||||
| // far | |||||
| addLine('f1', 'f2') | |||||
| addLine('f2', 'f4') | |||||
| addLine('f4', 'f3') | |||||
| addLine('f3', 'f1') | |||||
| // sides | |||||
| addLine('n1', 'f1') | |||||
| addLine('n2', 'f2') | |||||
| addLine('n3', 'f3') | |||||
| addLine('n4', 'f4') | |||||
| // cone | |||||
| addLine('p', 'n1') | |||||
| addLine('p', 'n2') | |||||
| addLine('p', 'n3') | |||||
| addLine('p', 'n4') | |||||
| // up | |||||
| addLine('u1', 'u2') | |||||
| addLine('u2', 'u3') | |||||
| addLine('u3', 'u1') | |||||
| // target | |||||
| addLine('c', 't') | |||||
| addLine('p', 'c') | |||||
| // cross | |||||
| addLine('cn1', 'cn2') | |||||
| addLine('cn3', 'cn4') | |||||
| addLine('cf1', 'cf2') | |||||
| addLine('cf3', 'cf4') | |||||
| function addLine(a: string, b: string) { | |||||
| addPoint(a) | |||||
| addPoint(b) | |||||
| } | |||||
| function addPoint(id: string) { | |||||
| vertices.push(0, 0, 0) | |||||
| colors.push(0, 0, 0) | |||||
| if (pointMap[id] === undefined) { | |||||
| pointMap[id] = [] | |||||
| } | |||||
| pointMap[id].push(vertices.length / 3 - 1) | |||||
| } | |||||
| return {vertices, colors, pointMap} | |||||
| } |
| import {ColorRepresentation, DirectionalLight, Object3D, Vector3} from 'three' | |||||
| import {Line2} from 'three/examples/jsm/lines/Line2.js' | |||||
| import {LineGeometry} from 'three/examples/jsm/lines/LineGeometry.js' | |||||
| import {onChange} from 'ts-browser-helpers' | |||||
| import {ALightHelperWidget} from './ALightHelperWidget' | |||||
| import {IUiConfigContainer, uiSlider} from 'uiconfig.js' | |||||
| import {LineMaterial2} from '../../core' | |||||
| export class DirectionalLightHelper2 extends ALightHelperWidget { | |||||
| color: ColorRepresentation|undefined | |||||
| lightPlane: Line2 | |||||
| targetLine: Line2 | |||||
| light: (DirectionalLight&IUiConfigContainer)|undefined | |||||
| @onChange(DirectionalLightHelper2.prototype.update) | |||||
| material: LineMaterial2 | |||||
| @onChange(DirectionalLightHelper2.prototype.update) | |||||
| @uiSlider(undefined, [0.1, 20], 0.01) | |||||
| lineWidth = 5 | |||||
| @onChange(DirectionalLightHelper2.prototype.update) | |||||
| @uiSlider(undefined, [0.01, 10], 0.01) | |||||
| size = 0.5 | |||||
| constructor(light: DirectionalLight, size?: number, color?: ColorRepresentation) { | |||||
| super(light) | |||||
| this.color = color | |||||
| if (size !== undefined) this.size = size | |||||
| let geometry = new LineGeometry() | |||||
| this.material = new LineMaterial2({ | |||||
| color: 0xff0000, | |||||
| linewidth: 0.005, // in world units with size attenuation, pixels otherwise | |||||
| vertexColors: false, | |||||
| dashed: false, | |||||
| alphaToCoverage: true, | |||||
| toneMapped: false, | |||||
| transparent: true, | |||||
| depthTest: false, | |||||
| depthWrite: false, | |||||
| }) | |||||
| // @ts-expect-error update three-ts-types | |||||
| this.lightPlane = new Line2(geometry, this.material) | |||||
| this.add(this.lightPlane) | |||||
| geometry = new LineGeometry() | |||||
| geometry.setPositions([0, 0, 0, 0, 0, 1]) | |||||
| // @ts-expect-error update three-ts-types | |||||
| this.targetLine = new Line2(geometry, this.material) | |||||
| this.add(this.targetLine) | |||||
| this.update() | |||||
| this.traverse(o=>{ | |||||
| o.userData.__keepShadowDef = true | |||||
| o.castShadow = false | |||||
| o.receiveShadow = false | |||||
| }) | |||||
| } | |||||
| dispose() { | |||||
| this.lightPlane.geometry.dispose() | |||||
| this.lightPlane.material.dispose() | |||||
| this.targetLine.geometry.dispose() | |||||
| this.targetLine.material.dispose() | |||||
| super.dispose() | |||||
| } | |||||
| private _v1 = new Vector3() | |||||
| private _v2 = new Vector3() | |||||
| private _v3 = new Vector3() | |||||
| update() { | |||||
| if (!this.light || !this.lightPlane) return | |||||
| this._v1.setFromMatrixPosition(this.light.matrixWorld) | |||||
| this._v2.setFromMatrixPosition(this.light.target.matrixWorld) | |||||
| this._v3.subVectors(this._v2, this._v1) | |||||
| this.lightPlane.geometry.setPositions([ | |||||
| -this.size, this.size, 0, | |||||
| this.size, this.size, 0, | |||||
| this.size, -this.size, 0, | |||||
| -this.size, -this.size, 0, | |||||
| -this.size, this.size, 0, | |||||
| ]) | |||||
| this.lightPlane.lookAt(this._v2) | |||||
| // @ts-expect-error update three-ts-types | |||||
| this.lightPlane.material = this.material | |||||
| // @ts-expect-error update three-ts-types | |||||
| this.targetLine.material = this.material | |||||
| this.material.color.set(this.color ?? this.light.color) | |||||
| this.material.linewidth = this.lineWidth * 0.001 | |||||
| this.targetLine.lookAt(this._v2) | |||||
| this.targetLine.scale.z = this.light.intensity / 3. | |||||
| super.update() | |||||
| } | |||||
| static Check(light: Object3D) { | |||||
| return (light as DirectionalLight).isDirectionalLight | |||||
| } | |||||
| static Create(light: Object3D) { | |||||
| return new DirectionalLightHelper2(light as DirectionalLight) | |||||
| } | |||||
| } | |||||
| import {ColorRepresentation, Object3D, PointLight, SphereGeometry} from 'three' | |||||
| import {WireframeGeometry2} from 'three/examples/jsm/lines/WireframeGeometry2.js' | |||||
| import {Wireframe} from 'three/examples/jsm/lines/Wireframe.js' | |||||
| import {onChange} from 'ts-browser-helpers' | |||||
| import {ALightHelperWidget} from './ALightHelperWidget' | |||||
| import {IUiConfigContainer, uiSlider} from 'uiconfig.js' | |||||
| import {LineMaterial2} from '../../core' | |||||
| export class PointLightHelper2 extends ALightHelperWidget { | |||||
| color: ColorRepresentation | undefined | |||||
| lightSphere: Wireframe | |||||
| light: (PointLight & IUiConfigContainer) | undefined | |||||
| @onChange(PointLightHelper2.prototype.update) | |||||
| material: LineMaterial2 | |||||
| @onChange(PointLightHelper2.prototype.update) | |||||
| @uiSlider(undefined, [0.1, 20], 0.01) | |||||
| lineWidth = 5 | |||||
| @onChange(PointLightHelper2.prototype.update) | |||||
| @uiSlider(undefined, [0.01, 10], 0.01) | |||||
| size = 0.5 | |||||
| constructor(light: PointLight, size?: number, color?: ColorRepresentation) { | |||||
| super(light) | |||||
| this.color = color | |||||
| if (size !== undefined) this.size = size | |||||
| const geometry = new WireframeGeometry2(new SphereGeometry(0.5, 4, 2)) | |||||
| this.material = new LineMaterial2({ | |||||
| color: 0xff0000, | |||||
| linewidth: 0.005, // in world units with size attenuation, pixels otherwise | |||||
| vertexColors: false, | |||||
| dashed: false, | |||||
| alphaToCoverage: true, | |||||
| toneMapped: false, | |||||
| transparent: true, | |||||
| depthTest: false, | |||||
| depthWrite: false, | |||||
| }) | |||||
| // @ts-expect-error update three-ts-types | |||||
| this.lightSphere = new Wireframe(geometry, this.material) | |||||
| this.lightSphere.computeLineDistances() | |||||
| this.add(this.lightSphere) | |||||
| this.update() | |||||
| this.traverse(o => { | |||||
| o.userData.__keepShadowDef = true | |||||
| o.castShadow = false | |||||
| o.receiveShadow = false | |||||
| }) | |||||
| } | |||||
| dispose() { | |||||
| this.lightSphere.geometry.dispose() | |||||
| ;(this.lightSphere.material as any).dispose() | |||||
| super.dispose() | |||||
| } | |||||
| update() { | |||||
| if (!this.light || !this.lightSphere) return | |||||
| this.material.color.set(this.color ?? this.light.color) | |||||
| this.material.linewidth = this.lineWidth * 0.001 | |||||
| this.lightSphere.scale.setScalar(this.size) | |||||
| super.update() | |||||
| } | |||||
| static Check(light: Object3D) { | |||||
| return (light as PointLight).isPointLight | |||||
| } | |||||
| static Create(light: Object3D) { | |||||
| return new PointLightHelper2(light as PointLight) | |||||
| } | |||||
| } |
| import {Group, Sphere, Vector2} from 'three' | |||||
| import {Group, Sphere} from 'three' | |||||
| import {AnyOptions} from 'ts-browser-helpers' | import {AnyOptions} from 'ts-browser-helpers' | ||||
| import {Box3B} from '../math/Box3B' | import {Box3B} from '../math/Box3B' | ||||
| import {IMaterial, IObject3D, IWidget, LineMaterial2} from '../../core' | |||||
| import {LineSegments2} from 'three/examples/jsm/lines/LineSegments2.js' | |||||
| import {LineSegmentsGeometry} from 'three/examples/jsm/lines/LineSegmentsGeometry.js' | |||||
| import {IMaterial, IObject3D, IWidget} from '../../core' | |||||
| export class SelectionWidget extends Group implements IWidget { | export class SelectionWidget extends Group implements IWidget { | ||||
| isWidget = true as const | isWidget = true as const | ||||
| } | } | ||||
| export class BoxSelectionWidget extends SelectionWidget { | |||||
| constructor() { | |||||
| super() | |||||
| const matLine = new LineMaterial2({ | |||||
| color: '#ff2222' as any, transparent: true, opacity: 0.9, | |||||
| linewidth: 5, // in pixels | |||||
| resolution: new Vector2(1024, 1024), // to be set by renderer, eventually | |||||
| dashed: false, | |||||
| toneMapped: false, | |||||
| }) | |||||
| this.lineMaterial = matLine | |||||
| const ls = new LineSegmentsGeometry() | |||||
| ls.setPositions([1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1].map(v=>v - 0.5)) | |||||
| const wireframe = new LineSegments2(ls, matLine as any) | |||||
| wireframe.computeLineDistances() | |||||
| wireframe.scale.set(1, 1, 1) | |||||
| wireframe.visible = true | |||||
| this.add(wireframe) | |||||
| } | |||||
| protected _updater() { | |||||
| super._updater() | |||||
| const selected = this.object | |||||
| if (selected) { | |||||
| const bbox = new Box3B().expandByObject(selected, false) | |||||
| // const scale = bbox.getBoundingSphere(new Sphere()).radius | |||||
| bbox.getSize(this.scale).multiplyScalar(this.boundingScaleMultiplier).clampScalar(0.1, 100) | |||||
| this.setVisible(true) | |||||
| } | |||||
| } | |||||
| } |
| import {ColorRepresentation, Object3D, SpotLight, Vector3} from 'three' | |||||
| import {LineGeometry} from 'three/examples/jsm/lines/LineGeometry.js' | |||||
| import {LineSegments2} from 'three/examples/jsm/lines/LineSegments2.js' | |||||
| import {LineSegmentsGeometry} from 'three/examples/jsm/lines/LineSegmentsGeometry.js' | |||||
| import {onChange} from 'ts-browser-helpers' | |||||
| import {ALightHelperWidget} from './ALightHelperWidget' | |||||
| import {IUiConfigContainer, uiSlider} from 'uiconfig.js' | |||||
| import {LineMaterial2} from '../../core' | |||||
| export class SpotLightHelper2 extends ALightHelperWidget { | |||||
| color: ColorRepresentation | undefined | |||||
| cone: LineSegments2 | |||||
| light: (SpotLight & IUiConfigContainer) | undefined | |||||
| @onChange(SpotLightHelper2.prototype.update) | |||||
| material: LineMaterial2 | |||||
| @onChange(SpotLightHelper2.prototype.update) | |||||
| @uiSlider(undefined, [0.1, 20], 0.01) | |||||
| lineWidth = 5 | |||||
| constructor(light: SpotLight, size?: number, color?: ColorRepresentation) { | |||||
| super(light) | |||||
| this.color = color | |||||
| if (size === undefined) size = 0.5 | |||||
| let geometry = new LineSegmentsGeometry() | |||||
| const positions = [ | |||||
| 0, 0, 0, 0, 0, 1, | |||||
| 0, 0, 0, 1, 0, 1, | |||||
| 0, 0, 0, -1, 0, 1, | |||||
| 0, 0, 0, 0, 1, 1, | |||||
| 0, 0, 0, 0, -1, 1, | |||||
| ] | |||||
| for (let i = 0, j = 1, l = 32; i < l; i++, j++) { | |||||
| const p1 = i / l * Math.PI * 2 | |||||
| const p2 = j / l * Math.PI * 2 | |||||
| positions.push( | |||||
| Math.cos(p1), Math.sin(p1), 1, | |||||
| Math.cos(p2), Math.sin(p2), 1 | |||||
| ) | |||||
| } | |||||
| geometry.setPositions(positions) | |||||
| this.material = new LineMaterial2({ | |||||
| color: 0xff0000, | |||||
| linewidth: 0.005, // in world units with size attenuation, pixels otherwise | |||||
| vertexColors: false, | |||||
| dashed: false, | |||||
| alphaToCoverage: true, | |||||
| toneMapped: false, | |||||
| transparent: true, | |||||
| depthTest: false, | |||||
| depthWrite: false, | |||||
| }) | |||||
| // @ts-expect-error update three-ts-types | |||||
| this.cone = new LineSegments2(geometry, this.material) | |||||
| this.add(this.cone) | |||||
| geometry = new LineGeometry() | |||||
| geometry.setPositions([0, 0, 0, 0, 0, 1]) | |||||
| this.update() | |||||
| this.traverse(o => { | |||||
| o.userData.__keepShadowDef = true | |||||
| o.castShadow = false | |||||
| o.receiveShadow = false | |||||
| }) | |||||
| } | |||||
| dispose() { | |||||
| this.cone.geometry.dispose() | |||||
| this.cone.material.dispose() | |||||
| super.dispose() | |||||
| } | |||||
| private _v1 = new Vector3() | |||||
| update() { | |||||
| if (!this.light || !this.cone) return | |||||
| this.light.updateWorldMatrix(true, false) | |||||
| this.light.target.updateWorldMatrix(true, false) | |||||
| const coneLength = this.light.distance ? this.light.distance : 1000 | |||||
| const coneWidth = coneLength * Math.tan(this.light.angle) | |||||
| this.cone.scale.set(coneWidth, coneWidth, coneLength) | |||||
| this._v1.setFromMatrixPosition(this.light.target.matrixWorld) | |||||
| this.cone.lookAt(this._v1) | |||||
| this.material.color.set(this.color ?? this.light.color) | |||||
| this.material.linewidth = this.lineWidth * 0.001 | |||||
| super.update() | |||||
| } | |||||
| static Check(light: Object3D) { | |||||
| return (light as SpotLight).isSpotLight | |||||
| } | |||||
| static Create(light: Object3D) { | |||||
| return new SpotLightHelper2(light as SpotLight) | |||||
| } | |||||
| } |
| export {SelectionWidget} from './SelectionWidget' | |||||
| export {ACameraHelperWidget} from './ACameraHelperWidget' | |||||
| export {AHelperWidget} from './AHelperWidget' | |||||
| export {ALightHelperWidget} from './ALightHelperWidget' | |||||
| export {BoxSelectionWidget} from './BoxSelectionWidget' | |||||
| export {CameraHelper2} from './CameraHelper2' | |||||
| export {DirectionalLightHelper2} from './DirectionalLightHelper2' | |||||
| export {PointLightHelper2} from './PointLightHelper2' | |||||
| export {SpotLightHelper2} from './SpotLightHelper2' |