remesh-threejs 0.2.0
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/LICENSE +21 -0
- package/README.md +271 -0
- package/dist/index.d.ts +2505 -0
- package/dist/remesh-threejs.cjs +2 -0
- package/dist/remesh-threejs.cjs.map +1 -0
- package/dist/remesh-threejs.js +4338 -0
- package/dist/remesh-threejs.js.map +1 -0
- package/package.json +103 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 RossGraeber
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# remesh-threejs
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/remesh-threejs)
|
|
4
|
+
[](https://www.npmjs.com/package/remesh-threejs)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://github.com/RossGraeber/remesh-threejs/actions)
|
|
7
|
+
|
|
8
|
+
TypeScript library for adaptive remeshing of non-manifold surfaces using Three.js.
|
|
9
|
+
|
|
10
|
+
Based on the EUROGRAPHICS 2008 paper ["Adaptive Remeshing of Non-Manifold Surfaces"](https://doi.org/10.1111/j.1467-8659.2008.01285.x) by Zilske, Lamecker, and Zachow.
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- **Non-manifold mesh support**: Extended halfedge data structure supporting edges with more than 2 incident faces
|
|
15
|
+
- **Feature skeleton**: Unified treatment of non-manifold edges, feature lines, and boundary edges
|
|
16
|
+
- **Adaptive remeshing**: Edge splitting, contraction, flipping, and vertex smoothing
|
|
17
|
+
- **Analysis tools**: Detect and classify non-manifold vertices and edges
|
|
18
|
+
- **Spatial acceleration**: SpatialHash and BVH for efficient queries on large meshes (500K+ triangles)
|
|
19
|
+
- **Three.js integration**: Import/export BufferGeometry with visualization helpers
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install remesh-threejs three
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
### Basic Remeshing
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { BufferGeometry } from 'three';
|
|
33
|
+
import { remesh } from 'remesh-threejs';
|
|
34
|
+
|
|
35
|
+
// Remesh a geometry with default options
|
|
36
|
+
const result = remesh(inputGeometry, {
|
|
37
|
+
targetEdgeLength: 0.1,
|
|
38
|
+
iterations: 5,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
console.log(`Remeshed in ${result.stats.iterations} iterations`);
|
|
42
|
+
const outputGeometry = result.geometry;
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Analyze Mesh for Non-Manifold Issues
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { analyzeManifold, isManifold } from 'remesh-threejs';
|
|
49
|
+
|
|
50
|
+
// Quick check
|
|
51
|
+
if (!isManifold(geometry)) {
|
|
52
|
+
console.log('Mesh has non-manifold edges');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Detailed analysis
|
|
56
|
+
const analysis = analyzeManifold(geometry);
|
|
57
|
+
console.log(`Non-manifold edges: ${analysis.nonManifoldEdgeCount}`);
|
|
58
|
+
console.log(`Non-manifold vertices: ${analysis.nonManifoldVertexCount}`);
|
|
59
|
+
console.log(`Boundary edges: ${analysis.boundaryEdgeCount}`);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Advanced Usage with Full Control
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import {
|
|
66
|
+
NonManifoldMesh,
|
|
67
|
+
AdaptiveRemesher,
|
|
68
|
+
classifyAllVertices,
|
|
69
|
+
validateTopology,
|
|
70
|
+
exportBufferGeometry,
|
|
71
|
+
} from 'remesh-threejs';
|
|
72
|
+
|
|
73
|
+
// Create mesh from geometry
|
|
74
|
+
const mesh = NonManifoldMesh.fromBufferGeometry(inputGeometry);
|
|
75
|
+
|
|
76
|
+
// Classify vertices (required for skeleton-aware smoothing)
|
|
77
|
+
classifyAllVertices(mesh);
|
|
78
|
+
|
|
79
|
+
// Create remesher with options
|
|
80
|
+
const remesher = new AdaptiveRemesher(mesh, {
|
|
81
|
+
targetEdgeLength: 0.1,
|
|
82
|
+
minEdgeLength: 0.05,
|
|
83
|
+
maxEdgeLength: 0.2,
|
|
84
|
+
qualityThreshold: 0.3,
|
|
85
|
+
iterations: 10,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Run remeshing
|
|
89
|
+
const stats = remesher.run();
|
|
90
|
+
|
|
91
|
+
// Validate result
|
|
92
|
+
const validation = validateTopology(mesh);
|
|
93
|
+
if (!validation.isValid) {
|
|
94
|
+
console.error('Topology errors:', validation.errors);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Export result
|
|
98
|
+
const outputGeometry = exportBufferGeometry(mesh);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## API Reference
|
|
102
|
+
|
|
103
|
+
### Main Functions
|
|
104
|
+
|
|
105
|
+
| Function | Description |
|
|
106
|
+
|----------|-------------|
|
|
107
|
+
| `remesh(geometry, options?)` | One-shot remeshing of a BufferGeometry |
|
|
108
|
+
| `analyzeManifold(geometry)` | Analyze mesh for non-manifold features |
|
|
109
|
+
| `isManifold(geometry)` | Quick check if mesh is manifold |
|
|
110
|
+
| `validateTopology(mesh)` | Validate mesh topology integrity |
|
|
111
|
+
|
|
112
|
+
### Core Classes
|
|
113
|
+
|
|
114
|
+
| Class | Description |
|
|
115
|
+
|-------|-------------|
|
|
116
|
+
| `NonManifoldMesh` | Main mesh data structure with halfedge connectivity |
|
|
117
|
+
| `AdaptiveRemesher` | Iterative remeshing algorithm |
|
|
118
|
+
| `ManifoldAnalyzer` | Analysis with caching support |
|
|
119
|
+
| `VertexClassifier` | Classify vertices by skeleton topology |
|
|
120
|
+
| `TopologyValidator` | Validate mesh topology invariants |
|
|
121
|
+
|
|
122
|
+
### Mesh Operations
|
|
123
|
+
|
|
124
|
+
| Function | Description |
|
|
125
|
+
|----------|-------------|
|
|
126
|
+
| `splitEdge(mesh, edge, t?)` | Split an edge at parameter t |
|
|
127
|
+
| `splitLongEdges(mesh, maxLength)` | Split all edges exceeding length |
|
|
128
|
+
| `contractEdge(mesh, edge)` | Contract an edge to a single vertex |
|
|
129
|
+
| `contractShortEdges(mesh, minLength)` | Contract all edges below length |
|
|
130
|
+
| `flipEdge(mesh, edge)` | Flip a manifold edge |
|
|
131
|
+
| `makeDelaunay(mesh)` | Flip edges to achieve Delaunay triangulation |
|
|
132
|
+
| `smoothAllVertices(mesh, skeleton?, lambda?)` | Tangential smoothing |
|
|
133
|
+
|
|
134
|
+
### Vertex Classification
|
|
135
|
+
|
|
136
|
+
Vertices are classified based on their relationship to the feature skeleton:
|
|
137
|
+
|
|
138
|
+
| Type | Description | Constraint |
|
|
139
|
+
|------|-------------|------------|
|
|
140
|
+
| `Manifold` | Standard interior vertex | Free movement in 3D |
|
|
141
|
+
| `OpenBook` | On exactly 2 skeleton edges | Constrained to skeleton |
|
|
142
|
+
| `SkeletonBranching` | On 1 or >2 skeleton edges | Position fixed |
|
|
143
|
+
| `NonManifoldOther` | Other non-manifold config | Position fixed |
|
|
144
|
+
|
|
145
|
+
### Edge Classification
|
|
146
|
+
|
|
147
|
+
| Type | Description |
|
|
148
|
+
|------|-------------|
|
|
149
|
+
| `Manifold` | Exactly 2 incident faces |
|
|
150
|
+
| `NonManifold` | More than 2 incident faces |
|
|
151
|
+
| `Feature` | User-marked feature edge |
|
|
152
|
+
| `Boundary` | Only 1 incident face |
|
|
153
|
+
|
|
154
|
+
### Spatial Structures
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
import { SpatialHash, BVH, createBVHFromMesh } from 'remesh-threejs';
|
|
158
|
+
|
|
159
|
+
// Fast neighbor queries
|
|
160
|
+
const hash = new SpatialHash<Vertex>(cellSize);
|
|
161
|
+
hash.insert(vertex, vertex.position);
|
|
162
|
+
const neighbors = hash.queryRadius(position, radius);
|
|
163
|
+
|
|
164
|
+
// Closest point queries
|
|
165
|
+
const bvh = createBVHFromMesh(mesh);
|
|
166
|
+
const result = bvh.closestPoint(queryPoint);
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Visualization Helpers
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
import {
|
|
173
|
+
exportSkeletonGeometry,
|
|
174
|
+
exportClassificationGeometry,
|
|
175
|
+
exportQualityGeometry,
|
|
176
|
+
} from 'remesh-threejs';
|
|
177
|
+
|
|
178
|
+
// Visualize the feature skeleton as line segments
|
|
179
|
+
const skeletonLines = exportSkeletonGeometry(mesh);
|
|
180
|
+
|
|
181
|
+
// Color vertices by classification type
|
|
182
|
+
const classifiedMesh = exportClassificationGeometry(mesh);
|
|
183
|
+
|
|
184
|
+
// Color faces by triangle quality (red=poor, green=good)
|
|
185
|
+
const qualityMesh = exportQualityGeometry(mesh);
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Options
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
interface RemeshOptions {
|
|
192
|
+
// Target edge length (default: auto-computed)
|
|
193
|
+
targetEdgeLength?: number;
|
|
194
|
+
|
|
195
|
+
// Edge length bounds (default: 0.5x and 2x target)
|
|
196
|
+
minEdgeLength?: number;
|
|
197
|
+
maxEdgeLength?: number;
|
|
198
|
+
|
|
199
|
+
// Minimum triangle quality threshold (default: 0.3)
|
|
200
|
+
qualityThreshold?: number;
|
|
201
|
+
|
|
202
|
+
// Maximum iterations (default: 10)
|
|
203
|
+
iterations?: number;
|
|
204
|
+
|
|
205
|
+
// Smoothing strength (default: 0.5)
|
|
206
|
+
smoothingLambda?: number;
|
|
207
|
+
|
|
208
|
+
// Preserve non-manifold features (default: true)
|
|
209
|
+
preserveFeatures?: boolean;
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Development
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
# Install dependencies
|
|
217
|
+
npm install
|
|
218
|
+
|
|
219
|
+
# Run tests
|
|
220
|
+
npm test
|
|
221
|
+
|
|
222
|
+
# Run tests with coverage
|
|
223
|
+
npm run test:coverage
|
|
224
|
+
|
|
225
|
+
# Build library
|
|
226
|
+
npm run build
|
|
227
|
+
|
|
228
|
+
# Lint and format
|
|
229
|
+
npm run quality:fix
|
|
230
|
+
|
|
231
|
+
# Full validation (lint + test + build)
|
|
232
|
+
npm run validate
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Test Coverage
|
|
236
|
+
|
|
237
|
+
The library includes comprehensive tests covering:
|
|
238
|
+
|
|
239
|
+
- Type system and branded IDs
|
|
240
|
+
- Core data structures (Vertex, Edge, Face, Halfedge)
|
|
241
|
+
- Geometric utilities (40+ functions)
|
|
242
|
+
- Spatial acceleration (SpatialHash, BVH)
|
|
243
|
+
- Analysis tools (manifold detection, classification, validation)
|
|
244
|
+
- Full remeshing pipeline integration
|
|
245
|
+
|
|
246
|
+
Run `npm run test:coverage` to see the detailed coverage report.
|
|
247
|
+
|
|
248
|
+
## Publishing
|
|
249
|
+
|
|
250
|
+
See [PUBLISHING.md](PUBLISHING.md) for detailed instructions on publishing new versions to npm.
|
|
251
|
+
|
|
252
|
+
### Quick Publish Steps
|
|
253
|
+
|
|
254
|
+
1. Update version: `npm version patch|minor|major`
|
|
255
|
+
2. Push: `git push && git push --tags`
|
|
256
|
+
3. Create GitHub release
|
|
257
|
+
4. Automated CI/CD publishes to npm
|
|
258
|
+
|
|
259
|
+
## Contributing
|
|
260
|
+
|
|
261
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
262
|
+
|
|
263
|
+
1. Fork the repository
|
|
264
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
265
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
266
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
267
|
+
5. Open a Pull Request
|
|
268
|
+
|
|
269
|
+
## License
|
|
270
|
+
|
|
271
|
+
MIT
|