diff --git a/examples/jsm/inspector/tabs/Parameters.js b/examples/jsm/inspector/tabs/Parameters.js index 6f26f875cb6fcd..f0e9d34a716194 100644 --- a/examples/jsm/inspector/tabs/Parameters.js +++ b/examples/jsm/inspector/tabs/Parameters.js @@ -2,7 +2,7 @@ import { Tab } from '../ui/Tab.js'; import { List } from '../ui/List.js'; import { Item } from '../ui/Item.js'; import { createValueSpan } from '../ui/utils.js'; -import { ValueNumber, ValueSlider, ValueSelect, ValueCheckbox, ValueColor, ValueButton } from '../ui/Values.js'; +import { ValueString, ValueNumber, ValueSlider, ValueSelect, ValueCheckbox, ValueColor, ValueButton } from '../ui/Values.js'; class ParametersGroup { @@ -52,6 +52,10 @@ class ParametersGroup { item = this.addBoolean( object, property ); + } else if ( type === 'string' ) { + + item = this.addString( object, property ); + } else if ( type === 'function' ) { item = this.addButton( object, property, ...params ); @@ -106,6 +110,34 @@ class ParametersGroup { } + addString( object, property ) { + + const value = object[ property ]; + + const editor = new ValueString( { value } ); + editor.addEventListener( 'change', ( { value } ) => { + + object[ property ] = value; + + } ); + + const description = createValueSpan(); + description.textContent = property; + + const subItem = new Item( description, editor.domElement ); + this.paramList.add( subItem ); + + const itemRow = subItem.domElement.firstChild; + itemRow.classList.add( 'actionable' ); + + // extend object property + + this._addParameter( object, property, editor, subItem ); + + return editor; + + } + addFolder( name ) { const group = new ParametersGroup( this.parameters, name ); diff --git a/examples/jsm/inspector/ui/Style.js b/examples/jsm/inspector/ui/Style.js index 5243ec91c390ec..07ec9bfff63340 100644 --- a/examples/jsm/inspector/ui/Style.js +++ b/examples/jsm/inspector/ui/Style.js @@ -1200,6 +1200,11 @@ export class Style { box-sizing: border-box; } +.param-control input:focus { + outline: none; + border-color: var(--accent-color); +} + .param-control select { padding-top: 3px; padding-bottom: 1px; diff --git a/examples/jsm/inspector/ui/Values.js b/examples/jsm/inspector/ui/Values.js index 3e576cb67902bd..61d74b43e62f8d 100644 --- a/examples/jsm/inspector/ui/Values.js +++ b/examples/jsm/inspector/ui/Values.js @@ -436,4 +436,41 @@ class ValueButton extends Value { } -export { Value, ValueNumber, ValueCheckbox, ValueSlider, ValueSelect, ValueColor, ValueButton }; +class ValueString extends Value { + + constructor( { value = '' } ) { + + super(); + + const input = document.createElement( 'input' ); + input.type = 'text'; + input.value = value; + this.input = input; + + input.addEventListener( 'input', () => { + + this.dispatchChange(); + + } ); + + this.domElement.appendChild( input ); + + } + + setValue( val ) { + + this.input.value = val; + + return super.setValue( val ); + + } + + getValue() { + + return this.input.value; + + } + +} + +export { Value, ValueNumber, ValueString, ValueCheckbox, ValueSlider, ValueSelect, ValueColor, ValueButton }; diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index 797950ed9a7a75..c8c83b67485b10 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -3241,6 +3241,8 @@ class WebGLRenderer { } + state.activeTexture( _gl.TEXTURE0 ); // see #33153 + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY ); _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha ); _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment ); diff --git a/src/renderers/common/Animation.js b/src/renderers/common/Animation.js index 9fc359f4edc022..2a0a0ed3476414 100644 --- a/src/renderers/common/Animation.js +++ b/src/renderers/common/Animation.js @@ -95,7 +95,7 @@ class Animation { */ stop() { - this._context.cancelAnimationFrame( this._requestId ); + if ( this._context !== null ) this._context.cancelAnimationFrame( this._requestId ); this._requestId = null; diff --git a/src/renderers/common/Renderer.js b/src/renderers/common/Renderer.js index 6372c866f6872c..1520dacce7cd3f 100644 --- a/src/renderers/common/Renderer.js +++ b/src/renderers/common/Renderer.js @@ -1340,9 +1340,10 @@ class Renderer { const { width, height } = this.getDrawingBufferSize( _drawingBufferSize ); const { depth, stencil } = this; - const canvasTarget = this._canvasTarget; + // TODO: Unify CanvasTarget and OutputRenderTarget + const target = this._outputRenderTarget || this._canvasTarget; - let frameBufferTarget = this._frameBufferTargets.get( canvasTarget ); + let frameBufferTarget = this._frameBufferTargets.get( target ); if ( frameBufferTarget === undefined ) { @@ -1362,17 +1363,17 @@ class Renderer { const dispose = () => { - canvasTarget.removeEventListener( 'dispose', dispose ); + target.removeEventListener( 'dispose', dispose ); frameBufferTarget.dispose(); - this._frameBufferTargets.delete( canvasTarget ); + this._frameBufferTargets.delete( target ); }; - canvasTarget.addEventListener( 'dispose', dispose ); + target.addEventListener( 'dispose', dispose ); - this._frameBufferTargets.set( canvasTarget, frameBufferTarget ); + this._frameBufferTargets.set( target, frameBufferTarget ); } @@ -1380,6 +1381,7 @@ class Renderer { frameBufferTarget.depthBuffer = depth; frameBufferTarget.stencilBuffer = stencil; + if ( outputRenderTarget !== null ) { frameBufferTarget.setSize( outputRenderTarget.width, outputRenderTarget.height, outputRenderTarget.depth ); @@ -1390,11 +1392,18 @@ class Renderer { } - frameBufferTarget.viewport.copy( canvasTarget._viewport ); - frameBufferTarget.scissor.copy( canvasTarget._scissor ); - frameBufferTarget.viewport.multiplyScalar( canvasTarget._pixelRatio ); - frameBufferTarget.scissor.multiplyScalar( canvasTarget._pixelRatio ); - frameBufferTarget.scissorTest = canvasTarget._scissorTest; + // RenderTarget || CanvasTarget + + const viewport = this._outputRenderTarget ? this._outputRenderTarget.viewport : target._viewport; + const scissor = this._outputRenderTarget ? this._outputRenderTarget.scissor : target._scissor; + const pixelRatio = this._outputRenderTarget ? 1 : target._pixelRatio; + const scissorTest = this._outputRenderTarget ? this._outputRenderTarget.scissorTest : target._scissorTest; + + frameBufferTarget.viewport.copy( viewport ); + frameBufferTarget.scissor.copy( scissor ); + frameBufferTarget.viewport.multiplyScalar( pixelRatio ); + frameBufferTarget.scissor.multiplyScalar( pixelRatio ); + frameBufferTarget.scissorTest = scissorTest; frameBufferTarget.multiview = outputRenderTarget !== null ? outputRenderTarget.multiview : false; frameBufferTarget.resolveDepthBuffer = outputRenderTarget !== null ? outputRenderTarget.resolveDepthBuffer : true; frameBufferTarget._autoAllocateDepthBuffer = outputRenderTarget !== null ? outputRenderTarget._autoAllocateDepthBuffer : false; diff --git a/src/renderers/common/XRManager.js b/src/renderers/common/XRManager.js index a31d2f70f9d922..13c50cfb9fe919 100644 --- a/src/renderers/common/XRManager.js +++ b/src/renderers/common/XRManager.js @@ -11,16 +11,17 @@ import { AddEquation, BackSide, CustomBlending, DepthFormat, DepthStencilFormat, import { DepthTexture } from '../../textures/DepthTexture.js'; import { XRRenderTarget } from './XRRenderTarget.js'; import { CylinderGeometry } from '../../geometries/CylinderGeometry.js'; -import QuadMesh from './QuadMesh.js'; -import NodeMaterial from '../../materials/nodes/NodeMaterial.js'; import { PlaneGeometry } from '../../geometries/PlaneGeometry.js'; import { MeshBasicMaterial } from '../../materials/MeshBasicMaterial.js'; import { Mesh } from '../../objects/Mesh.js'; import { warn } from '../../utils.js'; +import { renderOutput } from '../../nodes/display/RenderOutputNode.js'; const _cameraLPos = /*@__PURE__*/ new Vector3(); const _cameraRPos = /*@__PURE__*/ new Vector3(); +const _contextNodeLib = /*@__PURE__*/ new WeakMap(); + /** * The XR manager is built on top of the WebXR Device API to * manage XR sessions with `WebGPURenderer`. @@ -182,8 +183,6 @@ class XRManager extends EventDispatcher { */ this._supportsGlBinding = typeof XRWebGLBinding !== 'undefined'; - this._frameBufferTargets = null; - /** * Helper function to create native WebXR Layer. * @@ -830,19 +829,23 @@ class XRManager extends EventDispatcher { const renderer = this._renderer; const wasPresenting = this.isPresenting; - const rendererOutputTarget = renderer.getOutputRenderTarget(); - const rendererFramebufferTarget = renderer._frameBufferTarget; + this.isPresenting = false; const rendererSize = new Vector2(); renderer.getSize( rendererSize ); - const rendererQuad = renderer._quad; + + const currentRenderTarget = renderer.getRenderTarget(); for ( const layer of this._layers ) { layer.renderTarget.isXRRenderTarget = this._session !== null; layer.renderTarget._hasExternalTextures = layer.renderTarget.isXRRenderTarget; + const currentContextNode = renderer.contextNode; + + let contextNode; + if ( layer.renderTarget.isXRRenderTarget && this._sessionUsesLayers ) { layer.xrlayer.transform = new XRRigidTransform( layer.plane.getWorldPosition( translationObject ), layer.plane.getWorldQuaternion( quaternionObject ) ); @@ -854,42 +857,46 @@ class XRManager extends EventDispatcher { undefined ); renderer._setXRLayerSize( layer.renderTarget.width, layer.renderTarget.height ); - renderer.setOutputRenderTarget( layer.renderTarget ); - renderer.setRenderTarget( null ); - renderer._frameBufferTarget = null; - this._frameBufferTargets || ( this._frameBufferTargets = new WeakMap() ); - const { frameBufferTarget, quad } = this._frameBufferTargets.get( layer.renderTarget ) || { frameBufferTarget: null, quad: null }; - if ( ! frameBufferTarget ) { + contextNode = _contextNodeLib.get( currentContextNode ); - renderer._quad = new QuadMesh( new NodeMaterial() ); - this._frameBufferTargets.set( layer.renderTarget, { frameBufferTarget: renderer._getFrameBufferTarget(), quad: renderer._quad } ); + if ( contextNode === undefined ) { - } else { + // Apply ToneMapping and OutputColorSpace directly in the material shader - renderer._frameBufferTarget = frameBufferTarget; - renderer._quad = quad; + contextNode = currentContextNode.context( { - } + getOutput: ( outputNode ) => { - layer.rendercall(); + return renderOutput( outputNode, renderer.toneMapping, renderer.outputColorSpace ); - renderer._frameBufferTarget = null; + } + + } ); + + _contextNodeLib.set( currentContextNode, contextNode ); + + } } else { - renderer.setRenderTarget( layer.renderTarget ); - layer.rendercall(); + contextNode = currentContextNode; } + renderer.contextNode = contextNode; + + renderer.setRenderTarget( layer.renderTarget ); + + layer.rendercall(); + + renderer.contextNode = currentContextNode; + } - renderer.setRenderTarget( null ); - renderer.setOutputRenderTarget( rendererOutputTarget ); - renderer._frameBufferTarget = rendererFramebufferTarget; + renderer.setRenderTarget( currentRenderTarget ); renderer._setXRLayerSize( rendererSize.x, rendererSize.y ); - renderer._quad = rendererQuad; + this.isPresenting = wasPresenting; } diff --git a/src/renderers/common/nodes/NodeManager.js b/src/renderers/common/nodes/NodeManager.js index 43e1885665f229..0881e2621075cc 100644 --- a/src/renderers/common/nodes/NodeManager.js +++ b/src/renderers/common/nodes/NodeManager.js @@ -414,11 +414,16 @@ class NodeManager extends DataMap { if ( object.isRenderObject ) { const nodeBuilderState = this.get( object ).nodeBuilderState; - nodeBuilderState.usedTimes --; - if ( nodeBuilderState.usedTimes === 0 ) { + if ( nodeBuilderState !== undefined ) { - this.nodeBuilderCache.delete( this.getForRenderCacheKey( object ) ); + nodeBuilderState.usedTimes --; + + if ( nodeBuilderState.usedTimes === 0 ) { + + this.nodeBuilderCache.delete( this.getForRenderCacheKey( object ) ); + + } } diff --git a/src/renderers/webgl/WebGLAnimation.js b/src/renderers/webgl/WebGLAnimation.js index 6965bcf897abdb..385f13e9d0e665 100644 --- a/src/renderers/webgl/WebGLAnimation.js +++ b/src/renderers/webgl/WebGLAnimation.js @@ -19,6 +19,7 @@ function WebGLAnimation() { if ( isAnimating === true ) return; if ( animationLoop === null ) return; + if ( context === null ) return; requestId = context.requestAnimationFrame( onAnimationFrame ); @@ -28,7 +29,7 @@ function WebGLAnimation() { stop: function () { - context.cancelAnimationFrame( requestId ); + if ( context !== null ) context.cancelAnimationFrame( requestId ); isAnimating = false;