Browse Source

Inspector: Add overdraw render mode. (#33870)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mrdoob 2 weeks ago
parent
commit
97096f71c0

+ 65 - 1
examples/jsm/inspector/RendererInspector.js

@@ -1,5 +1,6 @@
 
-import { InspectorBase, TimestampQuery, warnOnce } from 'three/webgpu';
+import { InspectorBase, TimestampQuery, warnOnce, RendererUtils, MeshBasicNodeMaterial, AdditiveBlending, NoToneMapping, LinearSRGBColorSpace } from 'three/webgpu';
+import { vec3 } from 'three/tsl';
 
 class ObjectStats {
 
@@ -84,6 +85,9 @@ export class RendererInspector extends InspectorBase {
 		this._lastFinishTime = 0;
 		this._resolveTimestampPromise = null;
 
+		this.overdraw = false;
+		this._overdrawMaterial = null;
+
 		this.isRendererInspector = true;
 
 	}
@@ -122,6 +126,66 @@ export class RendererInspector extends InspectorBase {
 
 		this._lastFinishTime = now;
 
+		if ( this.overdraw === true ) {
+
+			this._renderOverdraw( frame );
+
+		}
+
+	}
+
+	_renderOverdraw( frame ) {
+
+		const renderer = this.getRenderer();
+
+		if ( renderer === null ) return;
+
+		// first scene render of the frame; nested shadow / RTT passes come after
+
+		let primary = null;
+
+		for ( const render of frame.renders ) {
+
+			if ( render.scene.isScene === true ) {
+
+				primary = render;
+				break;
+
+			}
+
+		}
+
+		if ( primary === null ) return;
+
+		if ( this._overdrawMaterial === null ) {
+
+			// additive constant, so each pixel sums the depth-passing fragments it shaded
+
+			this._overdrawMaterial = new MeshBasicNodeMaterial( {
+				colorNode: vec3( 0.25 ),
+				blending: AdditiveBlending,
+				depthTest: true,
+				depthWrite: true,
+				toneMapped: false
+			} );
+
+		}
+
+		const { scene, camera } = primary;
+
+		// raw render against black with no tone mapping, so the count stays linear
+
+		const state = RendererUtils.resetRendererAndSceneState( renderer, scene );
+
+		renderer.toneMapping = NoToneMapping;
+		renderer.outputColorSpace = LinearSRGBColorSpace;
+
+		scene.overrideMaterial = this._overdrawMaterial;
+
+		renderer.render( scene, camera );
+
+		RendererUtils.restoreRendererAndSceneState( renderer, scene, state );
+
 	}
 
 	_getFPS() {

+ 10 - 0
examples/jsm/inspector/tabs/Settings.js

@@ -115,6 +115,16 @@ class Settings extends Parameters {
 
 		} );
 
+		// Render Modes
+
+		const modesGroup = this.createGroup( 'Render Modes' );
+
+		modesGroup.add( { overdraw: false }, 'overdraw' ).name( 'Overdraw' ).onChange( ( enable ) => {
+
+			this.inspector.overdraw = enable;
+
+		} ).info( 'Shows how many times each pixel is shaded.' );
+
 	}
 
 	init() {

+ 8 - 1
examples/jsm/inspector/ui/utils.js

@@ -101,8 +101,15 @@ export function info( parentNode, text ) {
 		tooltip.innerHTML = html;
 
 		const rect = infoIcon.getBoundingClientRect();
+		const tooltipWidth = tooltip.getBoundingClientRect().width;
 
-		tooltip.style.left = ( rect.left + rect.width / 2 ) + 'px';
+		// keep the centered tooltip within the viewport so it isn't clipped near an edge
+
+		const margin = 8;
+		const half = tooltipWidth / 2;
+		const center = Math.max( margin + half, Math.min( window.innerWidth - margin - half, rect.left + rect.width / 2 ) );
+
+		tooltip.style.left = center + 'px';
 		tooltip.style.top = ( rect.top - 8 ) + 'px';
 
 		tooltip.style.opacity = '1';

粤ICP备19079148号