@tonybfox/threejs-tools 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/asset-loader/index.cjs +64 -2
- package/dist/asset-loader/index.d.mts +6 -1
- package/dist/asset-loader/index.d.ts +6 -1
- package/dist/asset-loader/index.mjs +1 -1
- package/dist/{chunk-27WUVRGX.mjs → chunk-LUE7VHLK.mjs} +64 -2
- package/dist/index.cjs +470 -69
- package/dist/index.d.mts +169 -1
- package/dist/index.d.ts +169 -1
- package/dist/index.mjs +339 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -3,11 +3,179 @@ export { CameraMode, DualCameraControls, DualCameraControlsOptions, ExternalCame
|
|
|
3
3
|
export { CompassOverlay, CompassOverlayEvent, CompassOverlayOptions } from './compass/index.mjs';
|
|
4
4
|
export { InfiniteGrid } from './grid/index.mjs';
|
|
5
5
|
export { Measurement, MeasurementData, MeasurementPoint, MeasurementPointData, MeasurementTool, MeasurementToolEvents, MeasurementToolOptions, SnapMode, SnapResult } from './measurements/index.mjs';
|
|
6
|
+
import * as THREE from 'three';
|
|
6
7
|
export { SunLightState, SunLightTool, SunLightToolEvents, SunLightToolOptions, SunLightWeather } from './sunlight/index.mjs';
|
|
7
8
|
export { ElevationPoint, GeoCoordinates, TerrainData, TerrainDimensions, TerrainTool, TerrainToolEvents, TerrainToolOptions } from './terrain/index.mjs';
|
|
8
9
|
export { TransformControls, TransformControlsGizmo, TransformControlsPlane, calculateBoundingBoxCenter } from './transform-controls/index.mjs';
|
|
9
10
|
export { ViewHelper, ViewHelperCameraController, ViewHelperEvent, ViewHelperOptions } from './view-helper/index.mjs';
|
|
10
|
-
import 'three';
|
|
11
11
|
import 'camera-controls';
|
|
12
12
|
import 'three/examples/jsm/renderers/CSS2DRenderer';
|
|
13
13
|
import 'three/examples/jsm/renderers/CSS2DRenderer.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Configuration options for the OutlineTool
|
|
17
|
+
*/
|
|
18
|
+
interface OutlineOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Color of the outline (hex)
|
|
21
|
+
* @default 0xff0000
|
|
22
|
+
*/
|
|
23
|
+
outlineColor?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Thickness of edge lines in pixels (for both modes)
|
|
26
|
+
* @default 2
|
|
27
|
+
*/
|
|
28
|
+
edgeLineWidth?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Color of edge lines (hex) - only for 'mesh' mode
|
|
31
|
+
* @default 0xff0000
|
|
32
|
+
*/
|
|
33
|
+
edgeLineColor?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Angle threshold for edge detection (degrees) - only for 'mesh' mode
|
|
36
|
+
* Higher values = fewer edges detected
|
|
37
|
+
* @default 30
|
|
38
|
+
*/
|
|
39
|
+
edgeThreshold?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Scale multiplier for silhouette outline - only for 'mesh' mode
|
|
42
|
+
* @default 1.02
|
|
43
|
+
*/
|
|
44
|
+
outlineScale?: number;
|
|
45
|
+
/**
|
|
46
|
+
* Enable silhouette outline (inverted hull) - only for 'mesh' mode
|
|
47
|
+
* @default true
|
|
48
|
+
*/
|
|
49
|
+
enableSilhouette?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Enable edge lines - only for 'mesh' mode
|
|
52
|
+
* @default true
|
|
53
|
+
*/
|
|
54
|
+
enableEdgeLines?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Edge strength for postprocess mode (0-1)
|
|
57
|
+
* @default 1.0
|
|
58
|
+
*/
|
|
59
|
+
edgeStrength?: number;
|
|
60
|
+
/**
|
|
61
|
+
* Custom exclusion function to filter objects
|
|
62
|
+
* Return true to exclude an object from outlining
|
|
63
|
+
*/
|
|
64
|
+
excludeFilter?: (object: THREE.Object3D) => boolean;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Internal data structure for tracking outlined objects
|
|
68
|
+
*/
|
|
69
|
+
interface OutlineData {
|
|
70
|
+
originalObject: THREE.Object3D;
|
|
71
|
+
silhouetteMesh?: THREE.Mesh;
|
|
72
|
+
edgeLines?: any;
|
|
73
|
+
parent: THREE.Object3D;
|
|
74
|
+
idColor?: THREE.Color;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* OutlineTool - Add outlines and edge lines to Three.js objects
|
|
79
|
+
*
|
|
80
|
+
* Features:
|
|
81
|
+
* - Two rendering modes: mesh-based and post-processing
|
|
82
|
+
* - Silhouette outlines using inverted hull technique
|
|
83
|
+
* - Edge lines for geometry visualization
|
|
84
|
+
* - Automatic updates when objects move/animate
|
|
85
|
+
* - Exclusion filters for specific object types
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* const outlineTool = new OutlineTool(renderer, {
|
|
90
|
+
* outlineColor: 0xff0000,
|
|
91
|
+
* edgeLineWidth: 2,
|
|
92
|
+
* })
|
|
93
|
+
*
|
|
94
|
+
* outlineTool.addObjects([mesh1, mesh2, mesh3])
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
declare class OutlineTool {
|
|
98
|
+
private options;
|
|
99
|
+
private outlineData;
|
|
100
|
+
private lineMaterial;
|
|
101
|
+
private renderer;
|
|
102
|
+
private composer;
|
|
103
|
+
private idRenderTarget;
|
|
104
|
+
private idMaterial;
|
|
105
|
+
/**
|
|
106
|
+
* Default exclusion filter
|
|
107
|
+
* Excludes Line2, LineSegments2, helpers, and gizmos
|
|
108
|
+
*/
|
|
109
|
+
private static defaultExcludeFilter;
|
|
110
|
+
constructor(renderer: THREE.WebGLRenderer, options?: OutlineOptions);
|
|
111
|
+
private handleResize;
|
|
112
|
+
/**
|
|
113
|
+
* Add objects to be outlined
|
|
114
|
+
* @param objects - Array of Three.js objects to outline
|
|
115
|
+
*/
|
|
116
|
+
addObjects(objects: THREE.Object3D[]): void;
|
|
117
|
+
/**
|
|
118
|
+
* Add a single object to be outlined
|
|
119
|
+
* @param object - Three.js object to outline
|
|
120
|
+
*/
|
|
121
|
+
addObject(object: THREE.Object3D): void;
|
|
122
|
+
/**
|
|
123
|
+
* Remove objects from outlining
|
|
124
|
+
* @param objects - Array of objects to remove outlines from
|
|
125
|
+
*/
|
|
126
|
+
removeObjects(objects: THREE.Object3D[]): void;
|
|
127
|
+
/**
|
|
128
|
+
* Remove a single object's outlines
|
|
129
|
+
* @param object - Object to remove outlines from
|
|
130
|
+
*/
|
|
131
|
+
removeObject(object: THREE.Object3D): void;
|
|
132
|
+
/**
|
|
133
|
+
* Clear all outlines
|
|
134
|
+
*/
|
|
135
|
+
clearAll(): void;
|
|
136
|
+
/**
|
|
137
|
+
* Update outlines to match current object transforms
|
|
138
|
+
* Call this in your animation loop (for mesh mode only)
|
|
139
|
+
*/
|
|
140
|
+
update(): void;
|
|
141
|
+
/**
|
|
142
|
+
* Render with outlines (for postprocess mode)
|
|
143
|
+
* Call this instead of renderer.render() when using postprocess mode
|
|
144
|
+
*/
|
|
145
|
+
render(scene: THREE.Scene, camera: THREE.Camera): void;
|
|
146
|
+
/**
|
|
147
|
+
* Render the ID buffer for edge detection
|
|
148
|
+
*/
|
|
149
|
+
private renderIdBuffer;
|
|
150
|
+
/**
|
|
151
|
+
* Update outline options
|
|
152
|
+
* @param options - Partial options to update
|
|
153
|
+
*/
|
|
154
|
+
setOptions(options: Partial<OutlineOptions>): void;
|
|
155
|
+
/**
|
|
156
|
+
* Create silhouette outline mesh
|
|
157
|
+
*/
|
|
158
|
+
private createSilhouette;
|
|
159
|
+
/**
|
|
160
|
+
* Create edge lines
|
|
161
|
+
*/
|
|
162
|
+
private createEdgeLines;
|
|
163
|
+
/**
|
|
164
|
+
* Type guard for THREE.Mesh
|
|
165
|
+
*/
|
|
166
|
+
private isMesh;
|
|
167
|
+
/**
|
|
168
|
+
* Dispose mesh and its resources
|
|
169
|
+
*/
|
|
170
|
+
private disposeMesh;
|
|
171
|
+
/**
|
|
172
|
+
* Dispose LineSegments2 and its resources
|
|
173
|
+
*/
|
|
174
|
+
private disposeLineSegments;
|
|
175
|
+
/**
|
|
176
|
+
* Cleanup and dispose resources
|
|
177
|
+
*/
|
|
178
|
+
dispose(): void;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export { type OutlineData, type OutlineOptions, OutlineTool };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,11 +3,179 @@ export { CameraMode, DualCameraControls, DualCameraControlsOptions, ExternalCame
|
|
|
3
3
|
export { CompassOverlay, CompassOverlayEvent, CompassOverlayOptions } from './compass/index.js';
|
|
4
4
|
export { InfiniteGrid } from './grid/index.js';
|
|
5
5
|
export { Measurement, MeasurementData, MeasurementPoint, MeasurementPointData, MeasurementTool, MeasurementToolEvents, MeasurementToolOptions, SnapMode, SnapResult } from './measurements/index.js';
|
|
6
|
+
import * as THREE from 'three';
|
|
6
7
|
export { SunLightState, SunLightTool, SunLightToolEvents, SunLightToolOptions, SunLightWeather } from './sunlight/index.js';
|
|
7
8
|
export { ElevationPoint, GeoCoordinates, TerrainData, TerrainDimensions, TerrainTool, TerrainToolEvents, TerrainToolOptions } from './terrain/index.js';
|
|
8
9
|
export { TransformControls, TransformControlsGizmo, TransformControlsPlane, calculateBoundingBoxCenter } from './transform-controls/index.js';
|
|
9
10
|
export { ViewHelper, ViewHelperCameraController, ViewHelperEvent, ViewHelperOptions } from './view-helper/index.js';
|
|
10
|
-
import 'three';
|
|
11
11
|
import 'camera-controls';
|
|
12
12
|
import 'three/examples/jsm/renderers/CSS2DRenderer';
|
|
13
13
|
import 'three/examples/jsm/renderers/CSS2DRenderer.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Configuration options for the OutlineTool
|
|
17
|
+
*/
|
|
18
|
+
interface OutlineOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Color of the outline (hex)
|
|
21
|
+
* @default 0xff0000
|
|
22
|
+
*/
|
|
23
|
+
outlineColor?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Thickness of edge lines in pixels (for both modes)
|
|
26
|
+
* @default 2
|
|
27
|
+
*/
|
|
28
|
+
edgeLineWidth?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Color of edge lines (hex) - only for 'mesh' mode
|
|
31
|
+
* @default 0xff0000
|
|
32
|
+
*/
|
|
33
|
+
edgeLineColor?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Angle threshold for edge detection (degrees) - only for 'mesh' mode
|
|
36
|
+
* Higher values = fewer edges detected
|
|
37
|
+
* @default 30
|
|
38
|
+
*/
|
|
39
|
+
edgeThreshold?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Scale multiplier for silhouette outline - only for 'mesh' mode
|
|
42
|
+
* @default 1.02
|
|
43
|
+
*/
|
|
44
|
+
outlineScale?: number;
|
|
45
|
+
/**
|
|
46
|
+
* Enable silhouette outline (inverted hull) - only for 'mesh' mode
|
|
47
|
+
* @default true
|
|
48
|
+
*/
|
|
49
|
+
enableSilhouette?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Enable edge lines - only for 'mesh' mode
|
|
52
|
+
* @default true
|
|
53
|
+
*/
|
|
54
|
+
enableEdgeLines?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Edge strength for postprocess mode (0-1)
|
|
57
|
+
* @default 1.0
|
|
58
|
+
*/
|
|
59
|
+
edgeStrength?: number;
|
|
60
|
+
/**
|
|
61
|
+
* Custom exclusion function to filter objects
|
|
62
|
+
* Return true to exclude an object from outlining
|
|
63
|
+
*/
|
|
64
|
+
excludeFilter?: (object: THREE.Object3D) => boolean;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Internal data structure for tracking outlined objects
|
|
68
|
+
*/
|
|
69
|
+
interface OutlineData {
|
|
70
|
+
originalObject: THREE.Object3D;
|
|
71
|
+
silhouetteMesh?: THREE.Mesh;
|
|
72
|
+
edgeLines?: any;
|
|
73
|
+
parent: THREE.Object3D;
|
|
74
|
+
idColor?: THREE.Color;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* OutlineTool - Add outlines and edge lines to Three.js objects
|
|
79
|
+
*
|
|
80
|
+
* Features:
|
|
81
|
+
* - Two rendering modes: mesh-based and post-processing
|
|
82
|
+
* - Silhouette outlines using inverted hull technique
|
|
83
|
+
* - Edge lines for geometry visualization
|
|
84
|
+
* - Automatic updates when objects move/animate
|
|
85
|
+
* - Exclusion filters for specific object types
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* const outlineTool = new OutlineTool(renderer, {
|
|
90
|
+
* outlineColor: 0xff0000,
|
|
91
|
+
* edgeLineWidth: 2,
|
|
92
|
+
* })
|
|
93
|
+
*
|
|
94
|
+
* outlineTool.addObjects([mesh1, mesh2, mesh3])
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
declare class OutlineTool {
|
|
98
|
+
private options;
|
|
99
|
+
private outlineData;
|
|
100
|
+
private lineMaterial;
|
|
101
|
+
private renderer;
|
|
102
|
+
private composer;
|
|
103
|
+
private idRenderTarget;
|
|
104
|
+
private idMaterial;
|
|
105
|
+
/**
|
|
106
|
+
* Default exclusion filter
|
|
107
|
+
* Excludes Line2, LineSegments2, helpers, and gizmos
|
|
108
|
+
*/
|
|
109
|
+
private static defaultExcludeFilter;
|
|
110
|
+
constructor(renderer: THREE.WebGLRenderer, options?: OutlineOptions);
|
|
111
|
+
private handleResize;
|
|
112
|
+
/**
|
|
113
|
+
* Add objects to be outlined
|
|
114
|
+
* @param objects - Array of Three.js objects to outline
|
|
115
|
+
*/
|
|
116
|
+
addObjects(objects: THREE.Object3D[]): void;
|
|
117
|
+
/**
|
|
118
|
+
* Add a single object to be outlined
|
|
119
|
+
* @param object - Three.js object to outline
|
|
120
|
+
*/
|
|
121
|
+
addObject(object: THREE.Object3D): void;
|
|
122
|
+
/**
|
|
123
|
+
* Remove objects from outlining
|
|
124
|
+
* @param objects - Array of objects to remove outlines from
|
|
125
|
+
*/
|
|
126
|
+
removeObjects(objects: THREE.Object3D[]): void;
|
|
127
|
+
/**
|
|
128
|
+
* Remove a single object's outlines
|
|
129
|
+
* @param object - Object to remove outlines from
|
|
130
|
+
*/
|
|
131
|
+
removeObject(object: THREE.Object3D): void;
|
|
132
|
+
/**
|
|
133
|
+
* Clear all outlines
|
|
134
|
+
*/
|
|
135
|
+
clearAll(): void;
|
|
136
|
+
/**
|
|
137
|
+
* Update outlines to match current object transforms
|
|
138
|
+
* Call this in your animation loop (for mesh mode only)
|
|
139
|
+
*/
|
|
140
|
+
update(): void;
|
|
141
|
+
/**
|
|
142
|
+
* Render with outlines (for postprocess mode)
|
|
143
|
+
* Call this instead of renderer.render() when using postprocess mode
|
|
144
|
+
*/
|
|
145
|
+
render(scene: THREE.Scene, camera: THREE.Camera): void;
|
|
146
|
+
/**
|
|
147
|
+
* Render the ID buffer for edge detection
|
|
148
|
+
*/
|
|
149
|
+
private renderIdBuffer;
|
|
150
|
+
/**
|
|
151
|
+
* Update outline options
|
|
152
|
+
* @param options - Partial options to update
|
|
153
|
+
*/
|
|
154
|
+
setOptions(options: Partial<OutlineOptions>): void;
|
|
155
|
+
/**
|
|
156
|
+
* Create silhouette outline mesh
|
|
157
|
+
*/
|
|
158
|
+
private createSilhouette;
|
|
159
|
+
/**
|
|
160
|
+
* Create edge lines
|
|
161
|
+
*/
|
|
162
|
+
private createEdgeLines;
|
|
163
|
+
/**
|
|
164
|
+
* Type guard for THREE.Mesh
|
|
165
|
+
*/
|
|
166
|
+
private isMesh;
|
|
167
|
+
/**
|
|
168
|
+
* Dispose mesh and its resources
|
|
169
|
+
*/
|
|
170
|
+
private disposeMesh;
|
|
171
|
+
/**
|
|
172
|
+
* Dispose LineSegments2 and its resources
|
|
173
|
+
*/
|
|
174
|
+
private disposeLineSegments;
|
|
175
|
+
/**
|
|
176
|
+
* Cleanup and dispose resources
|
|
177
|
+
*/
|
|
178
|
+
dispose(): void;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export { type OutlineData, type OutlineOptions, OutlineTool };
|
package/dist/index.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "./chunk-IAZH4OHC.mjs";
|
|
10
10
|
import {
|
|
11
11
|
AssetLoader
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-LUE7VHLK.mjs";
|
|
13
13
|
import {
|
|
14
14
|
DualCameraControls
|
|
15
15
|
} from "./chunk-XA7OKYSM.mjs";
|
|
@@ -29,12 +29,350 @@ import {
|
|
|
29
29
|
import {
|
|
30
30
|
TerrainTool
|
|
31
31
|
} from "./chunk-FBTT6MU6.mjs";
|
|
32
|
+
|
|
33
|
+
// packages/outline/src/OutlineTool.ts
|
|
34
|
+
import * as THREE from "three";
|
|
35
|
+
import { LineSegments2 } from "three/examples/jsm/lines/LineSegments2.js";
|
|
36
|
+
import { LineSegmentsGeometry } from "three/examples/jsm/lines/LineSegmentsGeometry.js";
|
|
37
|
+
import { LineMaterial } from "three/examples/jsm/lines/LineMaterial.js";
|
|
38
|
+
var _OutlineTool = class _OutlineTool {
|
|
39
|
+
constructor(renderer, options = {}) {
|
|
40
|
+
this.outlineData = /* @__PURE__ */ new Map();
|
|
41
|
+
this.lineMaterial = null;
|
|
42
|
+
this.composer = null;
|
|
43
|
+
this.idRenderTarget = null;
|
|
44
|
+
this.idMaterial = null;
|
|
45
|
+
this.handleResize = () => {
|
|
46
|
+
const size = this.renderer.getSize(new THREE.Vector2());
|
|
47
|
+
if (this.lineMaterial) {
|
|
48
|
+
this.lineMaterial.resolution.set(size.width, size.height);
|
|
49
|
+
}
|
|
50
|
+
if (this.idRenderTarget) {
|
|
51
|
+
this.idRenderTarget.setSize(size.width, size.height);
|
|
52
|
+
}
|
|
53
|
+
if (this.composer) {
|
|
54
|
+
this.composer.setSize(size.width, size.height);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
this.renderer = renderer;
|
|
58
|
+
this.options = {
|
|
59
|
+
outlineColor: options.outlineColor ?? 16711680,
|
|
60
|
+
edgeLineWidth: options.edgeLineWidth ?? 2,
|
|
61
|
+
edgeLineColor: options.edgeLineColor ?? 16711680,
|
|
62
|
+
edgeThreshold: options.edgeThreshold ?? 30,
|
|
63
|
+
outlineScale: options.outlineScale ?? 1.02,
|
|
64
|
+
enableSilhouette: options.enableSilhouette ?? true,
|
|
65
|
+
enableEdgeLines: options.enableEdgeLines ?? true,
|
|
66
|
+
edgeStrength: options.edgeStrength ?? 1,
|
|
67
|
+
excludeFilter: options.excludeFilter ?? _OutlineTool.defaultExcludeFilter
|
|
68
|
+
};
|
|
69
|
+
const size = renderer.getSize(new THREE.Vector2());
|
|
70
|
+
this.lineMaterial = new LineMaterial({
|
|
71
|
+
color: this.options.edgeLineColor,
|
|
72
|
+
linewidth: this.options.edgeLineWidth,
|
|
73
|
+
resolution: new THREE.Vector2(size.width, size.height)
|
|
74
|
+
});
|
|
75
|
+
window.addEventListener("resize", this.handleResize);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Add objects to be outlined
|
|
79
|
+
* @param objects - Array of Three.js objects to outline
|
|
80
|
+
*/
|
|
81
|
+
addObjects(objects) {
|
|
82
|
+
objects.forEach((obj) => this.addObject(obj));
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Add a single object to be outlined
|
|
86
|
+
* @param object - Three.js object to outline
|
|
87
|
+
*/
|
|
88
|
+
addObject(object) {
|
|
89
|
+
const uuid = object.uuid;
|
|
90
|
+
if (this.outlineData.has(uuid)) {
|
|
91
|
+
console.warn(`Object ${object.name || uuid} is already outlined`);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const outlines = [];
|
|
95
|
+
object.traverse((child) => {
|
|
96
|
+
if (!this.isMesh(child) || this.options.excludeFilter(child)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const mesh = child;
|
|
100
|
+
const data = {
|
|
101
|
+
originalObject: mesh,
|
|
102
|
+
parent: mesh.parent
|
|
103
|
+
};
|
|
104
|
+
if (this.options.enableSilhouette) {
|
|
105
|
+
data.silhouetteMesh = this.createSilhouette(mesh);
|
|
106
|
+
mesh.parent.add(data.silhouetteMesh);
|
|
107
|
+
}
|
|
108
|
+
if (this.options.enableEdgeLines) {
|
|
109
|
+
data.edgeLines = this.createEdgeLines(mesh);
|
|
110
|
+
mesh.parent.add(data.edgeLines);
|
|
111
|
+
}
|
|
112
|
+
outlines.push(data);
|
|
113
|
+
});
|
|
114
|
+
if (outlines.length > 0) {
|
|
115
|
+
this.outlineData.set(uuid, outlines);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Remove objects from outlining
|
|
120
|
+
* @param objects - Array of objects to remove outlines from
|
|
121
|
+
*/
|
|
122
|
+
removeObjects(objects) {
|
|
123
|
+
objects.forEach((obj) => this.removeObject(obj));
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Remove a single object's outlines
|
|
127
|
+
* @param object - Object to remove outlines from
|
|
128
|
+
*/
|
|
129
|
+
removeObject(object) {
|
|
130
|
+
const uuid = object.uuid;
|
|
131
|
+
const outlines = this.outlineData.get(uuid);
|
|
132
|
+
if (!outlines) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
outlines.forEach((data) => {
|
|
136
|
+
if (data.silhouetteMesh) {
|
|
137
|
+
data.parent.remove(data.silhouetteMesh);
|
|
138
|
+
this.disposeMesh(data.silhouetteMesh);
|
|
139
|
+
}
|
|
140
|
+
if (data.edgeLines) {
|
|
141
|
+
data.parent.remove(data.edgeLines);
|
|
142
|
+
this.disposeLineSegments(data.edgeLines);
|
|
143
|
+
}
|
|
144
|
+
if (data.originalObject.userData.outlineIdColor) {
|
|
145
|
+
delete data.originalObject.userData.outlineIdColor;
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
this.outlineData.delete(uuid);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Clear all outlines
|
|
152
|
+
*/
|
|
153
|
+
clearAll() {
|
|
154
|
+
const objects = Array.from(this.outlineData.keys());
|
|
155
|
+
objects.forEach((uuid) => {
|
|
156
|
+
const outlines = this.outlineData.get(uuid);
|
|
157
|
+
if (outlines && outlines.length > 0) {
|
|
158
|
+
this.removeObject(outlines[0].originalObject.parent);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Update outlines to match current object transforms
|
|
164
|
+
* Call this in your animation loop (for mesh mode only)
|
|
165
|
+
*/
|
|
166
|
+
update() {
|
|
167
|
+
this.outlineData.forEach((outlines) => {
|
|
168
|
+
outlines.forEach((data) => {
|
|
169
|
+
const mesh = data.originalObject;
|
|
170
|
+
if (data.silhouetteMesh) {
|
|
171
|
+
data.silhouetteMesh.position.copy(mesh.position);
|
|
172
|
+
data.silhouetteMesh.rotation.copy(mesh.rotation);
|
|
173
|
+
data.silhouetteMesh.quaternion.copy(mesh.quaternion);
|
|
174
|
+
data.silhouetteMesh.scale.copy(mesh.scale);
|
|
175
|
+
data.silhouetteMesh.scale.multiplyScalar(this.options.outlineScale);
|
|
176
|
+
}
|
|
177
|
+
if (data.edgeLines) {
|
|
178
|
+
data.edgeLines.position.copy(mesh.position);
|
|
179
|
+
data.edgeLines.rotation.copy(mesh.rotation);
|
|
180
|
+
data.edgeLines.quaternion.copy(mesh.quaternion);
|
|
181
|
+
data.edgeLines.scale.copy(mesh.scale);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Render with outlines (for postprocess mode)
|
|
188
|
+
* Call this instead of renderer.render() when using postprocess mode
|
|
189
|
+
*/
|
|
190
|
+
render(scene, camera) {
|
|
191
|
+
this.renderIdBuffer(scene, camera);
|
|
192
|
+
this.composer.render();
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Render the ID buffer for edge detection
|
|
196
|
+
*/
|
|
197
|
+
renderIdBuffer(scene, camera) {
|
|
198
|
+
if (!this.idRenderTarget || !this.idMaterial) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const oldRT = this.renderer.getRenderTarget();
|
|
202
|
+
const oldOverride = scene.overrideMaterial;
|
|
203
|
+
const visibilityMap = /* @__PURE__ */ new Map();
|
|
204
|
+
scene.traverse((obj) => {
|
|
205
|
+
visibilityMap.set(obj, obj.visible);
|
|
206
|
+
if (this.isMesh(obj) && !obj.userData.outlineIdColor) {
|
|
207
|
+
obj.visible = false;
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
scene.overrideMaterial = this.idMaterial;
|
|
211
|
+
scene.traverse((obj) => {
|
|
212
|
+
if (!this.isMesh(obj)) return;
|
|
213
|
+
const mesh = obj;
|
|
214
|
+
mesh.onBeforeRender = () => {
|
|
215
|
+
const idColor = mesh.userData.outlineIdColor;
|
|
216
|
+
if (idColor) {
|
|
217
|
+
this.idMaterial.color.copy(idColor);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
});
|
|
221
|
+
this.renderer.setRenderTarget(this.idRenderTarget);
|
|
222
|
+
this.renderer.clear();
|
|
223
|
+
this.renderer.render(scene, camera);
|
|
224
|
+
scene.traverse((obj) => {
|
|
225
|
+
if (!this.isMesh(obj)) return;
|
|
226
|
+
obj.onBeforeRender = () => {
|
|
227
|
+
};
|
|
228
|
+
const originalVisibility = visibilityMap.get(obj);
|
|
229
|
+
if (originalVisibility !== void 0) {
|
|
230
|
+
obj.visible = originalVisibility;
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
scene.overrideMaterial = oldOverride;
|
|
234
|
+
this.renderer.setRenderTarget(oldRT);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Update outline options
|
|
238
|
+
* @param options - Partial options to update
|
|
239
|
+
*/
|
|
240
|
+
setOptions(options) {
|
|
241
|
+
const needsRecreate = options.outlineColor !== void 0 || options.edgeLineColor !== void 0 || options.edgeThreshold !== void 0 || options.enableSilhouette !== void 0 || options.enableEdgeLines !== void 0;
|
|
242
|
+
Object.assign(this.options, options);
|
|
243
|
+
if (options.edgeLineWidth !== void 0 && this.lineMaterial) {
|
|
244
|
+
this.lineMaterial.linewidth = options.edgeLineWidth;
|
|
245
|
+
}
|
|
246
|
+
if (options.edgeLineColor !== void 0 && this.lineMaterial) {
|
|
247
|
+
this.lineMaterial.color.setHex(options.edgeLineColor);
|
|
248
|
+
}
|
|
249
|
+
if (needsRecreate) {
|
|
250
|
+
const objects = [];
|
|
251
|
+
this.outlineData.forEach((outlines) => {
|
|
252
|
+
if (outlines.length > 0) {
|
|
253
|
+
let root = outlines[0].originalObject;
|
|
254
|
+
while (root.parent && !this.outlineData.has(root.parent.uuid)) {
|
|
255
|
+
root = root.parent;
|
|
256
|
+
}
|
|
257
|
+
objects.push(root);
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
this.clearAll();
|
|
261
|
+
this.addObjects(objects);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Create silhouette outline mesh
|
|
266
|
+
*/
|
|
267
|
+
createSilhouette(mesh) {
|
|
268
|
+
const outlineMesh = mesh.clone();
|
|
269
|
+
outlineMesh.material = new THREE.MeshBasicMaterial({
|
|
270
|
+
color: this.options.outlineColor,
|
|
271
|
+
side: THREE.BackSide
|
|
272
|
+
});
|
|
273
|
+
outlineMesh.renderOrder = -1;
|
|
274
|
+
outlineMesh.scale.multiplyScalar(this.options.outlineScale);
|
|
275
|
+
outlineMesh.userData.excludeOutline = true;
|
|
276
|
+
return outlineMesh;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Create edge lines
|
|
280
|
+
*/
|
|
281
|
+
createEdgeLines(mesh) {
|
|
282
|
+
if (!this.lineMaterial) {
|
|
283
|
+
throw new Error("Line material not initialized");
|
|
284
|
+
}
|
|
285
|
+
const edges = new THREE.EdgesGeometry(
|
|
286
|
+
mesh.geometry,
|
|
287
|
+
this.options.edgeThreshold
|
|
288
|
+
);
|
|
289
|
+
const lineGeometry = new LineSegmentsGeometry();
|
|
290
|
+
const positions = edges.attributes.position.array;
|
|
291
|
+
lineGeometry.setPositions(positions);
|
|
292
|
+
const edgeLines = new LineSegments2(lineGeometry, this.lineMaterial);
|
|
293
|
+
edgeLines.computeLineDistances();
|
|
294
|
+
edgeLines.scale.copy(mesh.scale);
|
|
295
|
+
edgeLines.rotation.copy(mesh.rotation);
|
|
296
|
+
edgeLines.position.copy(mesh.position);
|
|
297
|
+
edgeLines.userData.excludeOutline = true;
|
|
298
|
+
edges.dispose();
|
|
299
|
+
return edgeLines;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Type guard for THREE.Mesh
|
|
303
|
+
*/
|
|
304
|
+
isMesh(object) {
|
|
305
|
+
return object.isMesh === true;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Dispose mesh and its resources
|
|
309
|
+
*/
|
|
310
|
+
disposeMesh(mesh) {
|
|
311
|
+
if (mesh.geometry) {
|
|
312
|
+
mesh.geometry.dispose();
|
|
313
|
+
}
|
|
314
|
+
if (Array.isArray(mesh.material)) {
|
|
315
|
+
mesh.material.forEach((mat) => mat.dispose());
|
|
316
|
+
} else if (mesh.material) {
|
|
317
|
+
mesh.material.dispose();
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Dispose LineSegments2 and its resources
|
|
322
|
+
*/
|
|
323
|
+
disposeLineSegments(line) {
|
|
324
|
+
if (line.geometry) {
|
|
325
|
+
line.geometry.dispose();
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Cleanup and dispose resources
|
|
330
|
+
*/
|
|
331
|
+
dispose() {
|
|
332
|
+
this.clearAll();
|
|
333
|
+
if (this.lineMaterial) {
|
|
334
|
+
this.lineMaterial.dispose();
|
|
335
|
+
}
|
|
336
|
+
if (this.idRenderTarget) {
|
|
337
|
+
this.idRenderTarget.dispose();
|
|
338
|
+
}
|
|
339
|
+
if (this.idMaterial) {
|
|
340
|
+
this.idMaterial.dispose();
|
|
341
|
+
}
|
|
342
|
+
if (this.composer) {
|
|
343
|
+
this.composer = null;
|
|
344
|
+
}
|
|
345
|
+
window.removeEventListener("resize", this.handleResize);
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
/**
|
|
349
|
+
* Default exclusion filter
|
|
350
|
+
* Excludes Line2, LineSegments2, helpers, and gizmos
|
|
351
|
+
*/
|
|
352
|
+
_OutlineTool.defaultExcludeFilter = (object) => {
|
|
353
|
+
if (object.type === "Line2" || object.type === "LineSegments2") {
|
|
354
|
+
return true;
|
|
355
|
+
}
|
|
356
|
+
if (object.type.includes("Helper")) {
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
if (object.userData.excludeOutline) {
|
|
360
|
+
return true;
|
|
361
|
+
}
|
|
362
|
+
const name = object.name.toLowerCase();
|
|
363
|
+
if (name.includes("arrow") || name.includes("gizmo") || name.includes("control")) {
|
|
364
|
+
return true;
|
|
365
|
+
}
|
|
366
|
+
return false;
|
|
367
|
+
};
|
|
368
|
+
var OutlineTool = _OutlineTool;
|
|
32
369
|
export {
|
|
33
370
|
AssetLoader,
|
|
34
371
|
CompassOverlay,
|
|
35
372
|
DualCameraControls,
|
|
36
373
|
InfiniteGrid,
|
|
37
374
|
MeasurementTool,
|
|
375
|
+
OutlineTool,
|
|
38
376
|
SnapMode,
|
|
39
377
|
SunLightTool,
|
|
40
378
|
TerrainTool,
|