|
1 | 1 | --- |
2 | | -sidebar_position: 2 |
| 2 | +sidebar_position: 3 |
3 | 3 | title: Using Bitbybit with Babylon.js |
4 | 4 | sidebar_label: Babylon.js Integration |
5 | 5 | description: Learn how to set up and use the @bitbybit-dev/babylonjs package with Vite to create 3D CAD applications, and control which geometry kernels (OCCT, JSCAD, Manifold) are initialized. |
@@ -204,7 +204,7 @@ import { |
204 | 204 | HemisphericLight, |
205 | 205 | Color4, // Using Color4 for scene clearColor for alpha |
206 | 206 | } from '@babylonjs/core'; |
207 | | -import { first } from 'rxjs'; |
| 207 | +import { first, firstValueFrom, tap } from 'rxjs'; |
208 | 208 |
|
209 | 209 | // Define an interface for kernel options |
210 | 210 | interface KernelOptions { |
@@ -260,6 +260,7 @@ function initBabylonJS() { |
260 | 260 | stencil: true, |
261 | 261 | }); |
262 | 262 | const scene = new Scene(engine); |
| 263 | + scene.metadata = { shadowGenerators: [] }; // Important for Bitbybit till we have better implementation... |
263 | 264 | scene.clearColor = new Color4(0.1, 0.11, 0.12, 1); // Set background color |
264 | 265 |
|
265 | 266 | const camera = new ArcRotateCamera( |
@@ -289,93 +290,121 @@ function initBabylonJS() { |
289 | 290 |
|
290 | 291 | // --- 5. Bitbybit Kernel Initialization Logic --- |
291 | 292 | async function initWithKernels( |
292 | | - scene: Scene, // Babylon.js Scene |
293 | | - bitbybit: BitByBitBase, |
294 | | - options: KernelOptions |
| 293 | + scene: Scene, |
| 294 | + bitbybit: BitByBitBase, |
| 295 | + options: KernelOptions |
295 | 296 | ): Promise<{ message: string }> { |
296 | | - return new Promise(async (resolve) => { |
297 | 297 | let occtWorkerInstance: Worker | undefined; |
298 | 298 | let jscadWorkerInstance: Worker | undefined; |
299 | 299 | let manifoldWorkerInstance: Worker | undefined; |
300 | 300 |
|
301 | | - // Conditionally create worker instances based on options |
| 301 | + // 1. Conditionally create worker instances |
302 | 302 | if (options.enableOCCT) { |
303 | | - occtWorkerInstance = new Worker( |
| 303 | + occtWorkerInstance = new Worker( |
304 | 304 | new URL('./workers/occt.worker.ts', import.meta.url), |
305 | 305 | { name: 'OCC_WORKER', type: 'module' } |
306 | | - ); |
| 306 | + ); |
307 | 307 | } |
308 | 308 | if (options.enableJSCAD) { |
309 | | - jscadWorkerInstance = new Worker( |
| 309 | + jscadWorkerInstance = new Worker( |
310 | 310 | new URL('./workers/jscad.worker.ts', import.meta.url), |
311 | 311 | { name: 'JSCAD_WORKER', type: 'module' } |
312 | | - ); |
| 312 | + ); |
313 | 313 | } |
314 | 314 | if (options.enableManifold) { |
315 | | - manifoldWorkerInstance = new Worker( |
| 315 | + manifoldWorkerInstance = new Worker( |
316 | 316 | new URL('./workers/manifold.worker.ts', import.meta.url), |
317 | 317 | { name: 'MANIFOLD_WORKER', type: 'module' } |
318 | | - ); |
| 318 | + ); |
319 | 319 | } |
320 | 320 |
|
321 | | - // Initialize Bitbybit with the (potentially undefined) worker instances. |
322 | | - // This passes the Babylon.js 'scene' to Bitbybit for integration. |
323 | | - scene.metadata = { shadowGenerators: [] }; |
| 321 | + // 2. Initialize Bitbybit |
324 | 322 | await bitbybit.init( |
325 | | - scene, |
326 | | - occtWorkerInstance, |
327 | | - jscadWorkerInstance, |
328 | | - manifoldWorkerInstance |
| 323 | + scene, |
| 324 | + occtWorkerInstance, |
| 325 | + jscadWorkerInstance, |
| 326 | + manifoldWorkerInstance |
329 | 327 | ); |
330 | 328 |
|
331 | | - // Logic to wait for selected kernels to be initialized |
332 | | - let nrResolved = 0; |
333 | | - let resolutionsNeeded = 0; |
| 329 | + // 3. Collect promises for kernel initializations |
| 330 | + const initializationPromises: Promise<void>[] = []; |
| 331 | + let anyKernelSelectedForInit = false; |
334 | 332 |
|
335 | | - const checkIfAllInitialized = () => { |
336 | | - if (nrResolved === resolutionsNeeded) { |
337 | | - console.log('Selected kernels initialized:', options); |
338 | | - resolve({ message: 'Selected kernels initialized successfully.' }); |
339 | | - } |
340 | | - }; |
| 333 | + if (options.enableOCCT) { |
| 334 | + anyKernelSelectedForInit = true; |
| 335 | + if (bitbybit.occtWorkerManager) { |
| 336 | + initializationPromises.push( |
| 337 | + firstValueFrom( |
| 338 | + bitbybit.occtWorkerManager.occWorkerState$.pipe( |
| 339 | + first((s) => s.state === OccStateEnum.initialised), |
| 340 | + tap(() => console.log('OCCT Initialized')) |
| 341 | + ) |
| 342 | + ).then(() => {}) // Ensure the promise resolves to void for Promise.all |
| 343 | + ); |
| 344 | + } else { |
| 345 | + console.warn( |
| 346 | + 'OCCT enabled in options, but occtWorkerManager not found after init.' |
| 347 | + ); |
| 348 | + } |
| 349 | + } |
341 | 350 |
|
342 | | - if (options.enableOCCT && bitbybit.occtWorkerManager) { |
343 | | - resolutionsNeeded++; |
344 | | - bitbybit.occtWorkerManager.occWorkerState$ |
345 | | - .pipe(first((s) => s.state === OccStateEnum.initialised)) |
346 | | - .subscribe(() => { |
347 | | - console.log('OCCT Initialized'); |
348 | | - nrResolved++; |
349 | | - checkIfAllInitialized(); |
350 | | - }); |
| 351 | + if (options.enableJSCAD) { |
| 352 | + anyKernelSelectedForInit = true; |
| 353 | + if (bitbybit.jscadWorkerManager) { |
| 354 | + initializationPromises.push( |
| 355 | + firstValueFrom( |
| 356 | + bitbybit.jscadWorkerManager.jscadWorkerState$.pipe( |
| 357 | + first((s) => s.state === JscadStateEnum.initialised), |
| 358 | + tap(() => console.log('JSCAD Initialized')) |
| 359 | + ) |
| 360 | + ).then(() => {}) |
| 361 | + ); |
| 362 | + } else { |
| 363 | + console.warn( |
| 364 | + 'JSCAD enabled in options, but jscadWorkerManager not found after init.' |
| 365 | + ); |
| 366 | + } |
351 | 367 | } |
352 | | - if (options.enableJSCAD && bitbybit.jscadWorkerManager) { |
353 | | - resolutionsNeeded++; |
354 | | - bitbybit.jscadWorkerManager.jscadWorkerState$ |
355 | | - .pipe(first((s) => s.state === JscadStateEnum.initialised)) |
356 | | - .subscribe(() => { |
357 | | - console.log('JSCAD Initialized'); |
358 | | - nrResolved++; |
359 | | - checkIfAllInitialized(); |
360 | | - }); |
| 368 | + |
| 369 | + if (options.enableManifold) { |
| 370 | + anyKernelSelectedForInit = true; |
| 371 | + if (bitbybit.manifoldWorkerManager) { |
| 372 | + initializationPromises.push( |
| 373 | + firstValueFrom( |
| 374 | + bitbybit.manifoldWorkerManager.manifoldWorkerState$.pipe( |
| 375 | + first((s) => s.state === ManifoldStateEnum.initialised), |
| 376 | + tap(() => console.log('Manifold Initialized')) |
| 377 | + ) |
| 378 | + ).then(() => {}) |
| 379 | + ); |
| 380 | + } else { |
| 381 | + console.warn( |
| 382 | + 'Manifold enabled in options, but manifoldWorkerManager not found after init.' |
| 383 | + ); |
| 384 | + } |
361 | 385 | } |
362 | | - if (options.enableManifold && bitbybit.manifoldWorkerManager) { |
363 | | - resolutionsNeeded++; |
364 | | - bitbybit.manifoldWorkerManager.manifoldWorkerState$ |
365 | | - .pipe(first((s) => s.state === ManifoldStateEnum.initialised)) |
366 | | - .subscribe(() => { |
367 | | - console.log('Manifold Initialized'); |
368 | | - nrResolved++; |
369 | | - checkIfAllInitialized(); |
370 | | - }); |
| 386 | + |
| 387 | + // 4. Wait for selected & available kernels or handle no selection/availability |
| 388 | + if (!anyKernelSelectedForInit) { |
| 389 | + console.log('No kernels selected for initialization.'); |
| 390 | + return { message: 'No kernels selected for initialization.' }; |
371 | 391 | } |
372 | 392 |
|
373 | | - // If no kernels were selected to be enabled |
374 | | - if (resolutionsNeeded === 0) { |
375 | | - console.log('No kernels selected for initialization.'); |
376 | | - resolve({ message: 'No kernels selected for initialization.' }); |
| 393 | + if (initializationPromises.length === 0) { |
| 394 | + // Kernels were selected, but none were awaitable (e.g., managers missing for all selected) |
| 395 | + console.log( |
| 396 | + 'Kernels were selected, but none had managers available for awaiting initialization.' |
| 397 | + ); |
| 398 | + return { |
| 399 | + message: 'Selected kernels were not awaitable for initialization state.', |
| 400 | + }; |
377 | 401 | } |
378 | | - }); |
| 402 | + |
| 403 | + await Promise.all(initializationPromises); |
| 404 | + console.log('Selected and awaitable kernels initialized:', options); |
| 405 | + return { |
| 406 | + message: 'Selected and awaitable kernels initialized successfully.', |
| 407 | + }; |
379 | 408 | } |
380 | 409 |
|
381 | 410 | // --- 6. Geometry Creation Functions (Examples) --- |
|
0 commit comments