diff --git a/public/js/webgl-book-lab.js b/public/js/webgl-book-lab.js index 0e2d33a..8d06795 100644 --- a/public/js/webgl-book-lab.js +++ b/public/js/webgl-book-lab.js @@ -4317,12 +4317,39 @@ function primeSceneForLoader() { updateTableReflection(); markLoaderTiming('tableReflection:end'); markLoaderTiming('shaderCompile:start'); - renderer.compile(scene, camera); + compileFlipMaterialsForLoader(); markLoaderTiming('shaderCompile:end'); + // Run the full post-processing pipeline now so the SSAO and output passes compile their + // programs and allocate their render targets during the loader, instead of stalling the + // first live frames after the loader fades out. + markLoaderTiming('composerWarmup:start'); + if (composer) { + composer.render(); + composer.render(); + } + markLoaderTiming('composerWarmup:end'); staticSceneBuffersDirty = false; markLoaderTiming('primeSceneForLoader:end'); } +// The flipping page mesh is only created on the first page flip, so its materials are not in +// the scene graph that renderer.compile walks. Compile them now via a throwaway probe mesh so +// the first flip does not stutter while the GPU compiles the flip page program. +function compileFlipMaterialsForLoader() { + const probeGeometry = new THREE.PlaneGeometry(0.001, 0.001); + const probes = [materials.flipPageSurface, materials.flipPageBackSurface, materials.flipPageEdge] + .map((material) => { + const probe = new THREE.Mesh(probeGeometry, material); + probe.position.copy(book.position); + probe.visible = true; + book.add(probe); + return probe; + }); + renderer.compile(scene, camera); + probes.forEach((probe) => book.remove(probe)); + probeGeometry.dispose(); +} + function tintAmbientFromCanvas(canvas) { if (!canvas || !candleBounceLight) return; const ctx = canvas.getContext('2d');