From 515000c02d13cbb6b7a69186e9adcd9d8468f5d1 Mon Sep 17 00:00:00 2001 From: Joshua Koo Date: Sat, 29 Jan 2022 22:20:59 -0800 Subject: [PATCH 1/2] Update HTMLMesh to observe DOM mutation and support Canvas elements - enable html2canvas updates to be made automatically based on dom updates - also add Stats.js to VR Sandbox --- examples/jsm/interactive/HTMLMesh.js | 50 ++++++++++++++++++++++++++-- examples/webxr_vr_sandbox.html | 21 ++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/examples/jsm/interactive/HTMLMesh.js b/examples/jsm/interactive/HTMLMesh.js index 27fe7d9f1167dd..5654af08b1979e 100644 --- a/examples/jsm/interactive/HTMLMesh.js +++ b/examples/jsm/interactive/HTMLMesh.js @@ -60,13 +60,31 @@ class HTMLTexture extends CanvasTexture { this.minFilter = LinearFilter; this.magFilter = LinearFilter; + // Create an observer on the DOM, and run html2canvas update in the next loop + const observer = new MutationObserver( () => { + + if ( ! this.scheduleUpdate ) { + + this.scheduleUpdate = requestAnimationFrame( () => this.update() ); + + } + + } ); + + const config = { attributes: true, childList: true, subtree: true, characterData: true }; + observer.observe( dom, config ); + + this.observer = observer; + } dispatchDOMEvent( event ) { - htmlevent( this.dom, event.type, event.data.x, event.data.y ); + if ( event.data ) { + + htmlevent( this.dom, event.type, event.data.x, event.data.y ); - this.update(); + } } @@ -75,10 +93,27 @@ class HTMLTexture extends CanvasTexture { this.image = html2canvas( this.dom ); this.needsUpdate = true; + this.scheduleUpdate = null; + + } + + dispose() { + + if ( this.observer ) { + + this.observer.disconnect(); + + } + + this.scheduleUpdate = cancelAnimationFrame( this.scheduleUpdate ); + + super.dispose(); + } } + // const canvases = new WeakMap(); @@ -202,6 +237,17 @@ function html2canvas( element ) { drawText( style, x, y, element.nodeValue.trim() ); + } else if ( element instanceof HTMLCanvasElement ) { + + // Canvas element + if ( element.style.display === 'none' ) return; + + context.save(); + const dpr = window.devicePixelRatio; + context.scale(1/dpr, 1/dpr); + context.drawImage(element, 0, 0 ); + context.restore(); + } else { if ( element.style.display === 'none' ) return; diff --git a/examples/webxr_vr_sandbox.html b/examples/webxr_vr_sandbox.html index d0c5b17fd69480..84ef55407359e0 100644 --- a/examples/webxr_vr_sandbox.html +++ b/examples/webxr_vr_sandbox.html @@ -33,9 +33,11 @@ import { XRControllerModelFactory } from './jsm/webxr/XRControllerModelFactory.js'; import { GUI } from './jsm/libs/lil-gui.module.min.js'; + import Stats from './jsm/libs/stats.module.js'; let camera, scene, renderer; let reflector; + let stats, statsMesh; const parameters = { radius: 0.6, @@ -193,6 +195,21 @@ mesh.scale.setScalar( 2 ); group.add( mesh ); + + // Add stats.js + stats = new Stats(); + stats.dom.style.width = '80px'; + stats.dom.style.height = '48px'; + document.body.appendChild( stats.dom ); + + statsMesh = new HTMLMesh( stats.dom ); + statsMesh.position.x = - 0.75; + statsMesh.position.y = 1.8; + statsMesh.position.z = - 0.6; + statsMesh.rotation.y = Math.PI / 4; + statsMesh.scale.setScalar( 2.5 ); + group.add( statsMesh ); + } function onWindowResize() { @@ -218,6 +235,10 @@ torus.rotation.y = time * 5; renderer.render( scene, camera ); + stats.update(); + + // Canvas elements doesn't trigger DOM updates, so we have to update the texture + statsMesh.material.map.update(); } From 1d2b98310bc5861ed3ca19ab61fe21f86acc892e Mon Sep 17 00:00:00 2001 From: Joshua Koo Date: Sat, 29 Jan 2022 22:59:41 -0800 Subject: [PATCH 2/2] Switch raf to setTimeout in HTMLMesh, also fix repeat notes in haptics --- examples/jsm/interactive/HTMLMesh.js | 5 +++-- examples/webxr_vr_haptics.html | 2 +- examples/webxr_vr_sandbox.html | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/jsm/interactive/HTMLMesh.js b/examples/jsm/interactive/HTMLMesh.js index 5654af08b1979e..476bc2c2789b54 100644 --- a/examples/jsm/interactive/HTMLMesh.js +++ b/examples/jsm/interactive/HTMLMesh.js @@ -65,7 +65,8 @@ class HTMLTexture extends CanvasTexture { if ( ! this.scheduleUpdate ) { - this.scheduleUpdate = requestAnimationFrame( () => this.update() ); + // ideally should use xr.requestAnimationFrame, here setTimeout to avoid passing the renderer + this.scheduleUpdate = setTimeout( () => this.update(), 16 ); } @@ -105,7 +106,7 @@ class HTMLTexture extends CanvasTexture { } - this.scheduleUpdate = cancelAnimationFrame( this.scheduleUpdate ); + this.scheduleUpdate = clearTimeout( this.scheduleUpdate ); super.dispose(); diff --git a/examples/webxr_vr_haptics.html b/examples/webxr_vr_haptics.html index 57e0a0c6cf4e91..a577a2ce9216f8 100644 --- a/examples/webxr_vr_haptics.html +++ b/examples/webxr_vr_haptics.html @@ -43,7 +43,7 @@ let audioCtx = null; // minor pentatonic scale, so whichever notes is striked would be more pleasant - const musicScale = [ 0, 3, 5, 7, 10, 12 ]; + const musicScale = [ 0, 3, 5, 7, 10 ]; init(); animate(); diff --git a/examples/webxr_vr_sandbox.html b/examples/webxr_vr_sandbox.html index 84ef55407359e0..02dd54d78678d1 100644 --- a/examples/webxr_vr_sandbox.html +++ b/examples/webxr_vr_sandbox.html @@ -204,7 +204,7 @@ statsMesh = new HTMLMesh( stats.dom ); statsMesh.position.x = - 0.75; - statsMesh.position.y = 1.8; + statsMesh.position.y = 2; statsMesh.position.z = - 0.6; statsMesh.rotation.y = Math.PI / 4; statsMesh.scale.setScalar( 2.5 );