Sorry, the diff of this file is not supported yet
| This Font Software is licensed under the SIL Open Font License, Version 1.1. | ||
| This license is copied below, and is also available with a FAQ at: | ||
| https://openfontlicense.org | ||
| ----------------------------------------------------------- | ||
| SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 | ||
| ----------------------------------------------------------- | ||
| PREAMBLE | ||
| The goals of the Open Font License (OFL) are to stimulate worldwide | ||
| development of collaborative font projects, to support the font creation | ||
| efforts of academic and linguistic communities, and to provide a free and | ||
| open framework in which fonts may be shared and improved in partnership | ||
| with others. | ||
| The OFL allows the licensed fonts to be used, studied, modified and | ||
| redistributed freely as long as they are not sold by themselves. The | ||
| fonts, including any derivative works, can be bundled, embedded, | ||
| redistributed and/or sold with any software provided that any reserved | ||
| names are not used by derivative works. The fonts and derivatives, | ||
| however, cannot be released under any other type of license. The | ||
| requirement for fonts to remain under this license does not apply | ||
| to any document created using the fonts or their derivatives. | ||
| DEFINITIONS | ||
| "Font Software" refers to the set of files released by the Copyright | ||
| Holder(s) under this license and clearly marked as such. This may | ||
| include source files, build scripts and documentation. | ||
| "Reserved Font Name" refers to any names specified as such after the | ||
| copyright statement(s). | ||
| "Original Version" refers to the collection of Font Software components as | ||
| distributed by the Copyright Holder(s). | ||
| "Modified Version" refers to any derivative made by adding to, deleting, | ||
| or substituting -- in part or in whole -- any of the components of the | ||
| Original Version, by changing formats or by porting the Font Software to a | ||
| new environment. | ||
| "Author" refers to any designer, engineer, programmer, technical | ||
| writer or other person who contributed to the Font Software. | ||
| PERMISSION & CONDITIONS | ||
| Permission is hereby granted, free of charge, to any person obtaining | ||
| a copy of the Font Software, to use, study, copy, merge, embed, modify, | ||
| redistribute, and sell modified and unmodified copies of the Font | ||
| Software, subject to the following conditions: | ||
| 1) Neither the Font Software nor any of its individual components, | ||
| in Original or Modified Versions, may be sold by itself. | ||
| 2) Original or Modified Versions of the Font Software may be bundled, | ||
| redistributed and/or sold with any software, provided that each copy | ||
| contains the above copyright notice and this license. These can be | ||
| included either as stand-alone text files, human-readable headers or | ||
| in the appropriate machine-readable metadata fields within text or | ||
| binary files as long as those fields can be easily viewed by the user. | ||
| 3) No Modified Version of the Font Software may use the Reserved Font | ||
| Name(s) unless explicit written permission is granted by the corresponding | ||
| Copyright Holder. This restriction only applies to the primary font name as | ||
| presented to the users. | ||
| 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font | ||
| Software shall not be used to promote, endorse or advertise any | ||
| Modified Version, except to acknowledge the contribution(s) of the | ||
| Copyright Holder(s) and the Author(s) or with their explicit written | ||
| permission. | ||
| 5) The Font Software, modified or unmodified, in part or in whole, | ||
| must be distributed entirely under this license, and must not be | ||
| distributed under any other license. The requirement for fonts to | ||
| remain under this license does not apply to any document created | ||
| using the Font Software. | ||
| TERMINATION | ||
| This license becomes null and void if any of the above conditions are | ||
| not met. | ||
| DISCLAIMER | ||
| THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF | ||
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT | ||
| OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE | ||
| COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
| INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL | ||
| DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM | ||
| OTHER DEALINGS IN THE FONT SOFTWARE. |
| import { Fn, uvec2, If, instancedArray, instanceIndex, invocationLocalIndex, Loop, workgroupArray, workgroupBarrier, workgroupId, uint, select, min, max } from 'three/tsl'; | ||
| const StepType = { | ||
| NONE: 0, | ||
| // Swap all values within the local range of workgroupSize * 2 | ||
| SWAP_LOCAL: 1, | ||
| DISPERSE_LOCAL: 2, | ||
| // Swap values within global data buffer. | ||
| FLIP_GLOBAL: 3, | ||
| DISPERSE_GLOBAL: 4, | ||
| }; | ||
| /** | ||
| * Returns the indices that will be compared in a bitonic flip operation. | ||
| * | ||
| * @tsl | ||
| * @private | ||
| * @param {Node<uint>} index - The compute thread's invocation id. | ||
| * @param {Node<uint>} blockHeight - The height of the block within which elements are being swapped. | ||
| * @returns {Node<uvec2>} The indices of the elements in the data buffer being compared. | ||
| */ | ||
| export const getBitonicFlipIndices = /*@__PURE__*/ Fn( ( [ index, blockHeight ] ) => { | ||
| const blockOffset = ( index.mul( 2 ).div( blockHeight ) ).mul( blockHeight ); | ||
| const halfHeight = blockHeight.div( 2 ); | ||
| const idx = uvec2( | ||
| index.mod( halfHeight ), | ||
| blockHeight.sub( index.mod( halfHeight ) ).sub( 1 ) | ||
| ); | ||
| idx.x.addAssign( blockOffset ); | ||
| idx.y.addAssign( blockOffset ); | ||
| return idx; | ||
| } ).setLayout( { | ||
| name: 'getBitonicFlipIndices', | ||
| type: 'uvec2', | ||
| inputs: [ | ||
| { name: 'index', type: 'uint' }, | ||
| { name: 'blockHeight', type: 'uint' } | ||
| ] | ||
| } ); | ||
| /** | ||
| * Returns the indices that will be compared in a bitonic sort's disperse operation. | ||
| * | ||
| * @tsl | ||
| * @private | ||
| * @param {Node<uint>} index - The compute thread's invocation id. | ||
| * @param {Node<uint>} swapSpan - The maximum span over which elements are being swapped. | ||
| * @returns {Node<uvec2>} The indices of the elements in the data buffer being compared. | ||
| */ | ||
| export const getBitonicDisperseIndices = /*@__PURE__*/ Fn( ( [ index, swapSpan ] ) => { | ||
| const blockOffset = ( ( index.mul( 2 ) ).div( swapSpan ) ).mul( swapSpan ); | ||
| const halfHeight = swapSpan.div( 2 ); | ||
| const idx = uvec2( | ||
| index.mod( halfHeight ), | ||
| ( index.mod( halfHeight ) ).add( halfHeight ) | ||
| ); | ||
| idx.x.addAssign( blockOffset ); | ||
| idx.y.addAssign( blockOffset ); | ||
| return idx; | ||
| } ).setLayout( { | ||
| name: 'getBitonicDisperseIndices', | ||
| type: 'uvec2', | ||
| inputs: [ | ||
| { name: 'index', type: 'uint' }, | ||
| { name: 'blockHeight', type: 'uint' } | ||
| ] | ||
| } ); | ||
| export class BitonicSort { | ||
| /** | ||
| * Constructs a new light probe helper. | ||
| * | ||
| * @param {Renderer} renderer - The current scene's renderer. | ||
| * @param {StorageBufferNode} dataBuffer - The data buffer to sort. | ||
| * @param {Object} [options={}] - Options that modify the bitonic sort. | ||
| */ | ||
| constructor( renderer, dataBuffer, options = {} ) { | ||
| /** | ||
| * A reference to the renderer. | ||
| * | ||
| * @type {Renderer} | ||
| */ | ||
| this.renderer = renderer; | ||
| /** | ||
| * A reference to the StorageBufferNode holding the data that will be sorted . | ||
| * | ||
| * @type {StorageBufferNode} | ||
| */ | ||
| this.dataBuffer = dataBuffer; | ||
| /** | ||
| * The size of the data. | ||
| * | ||
| * @type {StorageBufferNode} | ||
| */ | ||
| this.count = dataBuffer.value.count; | ||
| /** | ||
| * | ||
| * The size of each compute dispatch. | ||
| * @type {number} | ||
| */ | ||
| this.dispatchSize = this.count / 2; | ||
| /** | ||
| * The workgroup size of the compute shaders executed during the sort. | ||
| * | ||
| * @type {StorageBufferNode} | ||
| */ | ||
| this.workgroupSize = options.workgroupSize ? Math.min( this.dispatchSize, options.workgroupSize ) : Math.min( this.dispatchSize, 64 ); | ||
| /** | ||
| * A node representing a workgroup scoped buffer that holds locally sorted elements. | ||
| * | ||
| * @type {WorkgroupInfoNode} | ||
| */ | ||
| this.localStorage = workgroupArray( dataBuffer.nodeType, this.workgroupSize * 2 ); | ||
| this._tempArray = new Uint32Array( this.count ); | ||
| for ( let i = 0; i < this.count; i ++ ) { | ||
| this._tempArray[ i ] = 0; | ||
| } | ||
| /** | ||
| * A node representing a storage buffer used for transferring the result of the global sort back to the original data buffer. | ||
| * | ||
| * @type {StorageBufferNode} | ||
| */ | ||
| this.tempBuffer = instancedArray( this.count, dataBuffer.nodeType ).setName( 'TempStorage' ); | ||
| /** | ||
| * A node containing the current algorithm type, the current swap span, and the highest swap span. | ||
| * | ||
| * @type {StorageBufferNode} | ||
| */ | ||
| this.infoStorage = instancedArray( new Uint32Array( [ 1, 2, 2 ] ), 'uint' ).setName( 'BitonicSortInfo' ); | ||
| /** | ||
| * The number of distinct swap operations ('flips' and 'disperses') executed in an in-place | ||
| * bitonic sort of the current data buffer. | ||
| * | ||
| * @type {number} | ||
| */ | ||
| this.swapOpCount = this._getSwapOpCount(); | ||
| /** | ||
| * The number of steps (i.e prepping and/or executing a swap) needed to fully execute an in-place bitonic sort of the current data buffer. | ||
| * | ||
| * @type {number} | ||
| */ | ||
| this.stepCount = this._getStepCount(); | ||
| /** | ||
| * The number of the buffer being read from. | ||
| * | ||
| * @type {string} | ||
| */ | ||
| this.readBufferName = 'Data'; | ||
| /** | ||
| * An object containing compute shaders that execute a 'flip' swap within a global address space on elements in the data buffer. | ||
| * | ||
| * @type {Object<string, ComputeNode>} | ||
| */ | ||
| this.flipGlobalNodes = { | ||
| 'Data': this._getFlipGlobal( this.dataBuffer, this.tempBuffer ), | ||
| 'Temp': this._getFlipGlobal( this.tempBuffer, this.dataBuffer ) | ||
| }; | ||
| /** | ||
| * An object containing compute shaders that execute a 'disperse' swap within a global address space on elements in the data buffer. | ||
| * | ||
| * @type {Object<string, ComputeNode>} | ||
| */ | ||
| this.disperseGlobalNodes = { | ||
| 'Data': this._getDisperseGlobal( this.dataBuffer, this.tempBuffer ), | ||
| 'Temp': this._getDisperseGlobal( this.tempBuffer, this.dataBuffer ) | ||
| }; | ||
| /** | ||
| * A compute shader that executes a sequence of flip and disperse swaps within a local address space on elements in the data buffer. | ||
| * | ||
| * @type {ComputeNode} | ||
| */ | ||
| this.swapLocalFn = this._getSwapLocal(); | ||
| /** | ||
| * A compute shader that executes a sequence of disperse swaps within a local address space on elements in the data buffer. | ||
| * | ||
| * @type {Object<string, ComputeNode>} | ||
| */ | ||
| this.disperseLocalNodes = { | ||
| 'Data': this._getDisperseLocal( this.dataBuffer ), | ||
| 'Temp': this._getDisperseLocal( this.tempBuffer ), | ||
| }; | ||
| // Utility functions | ||
| /** | ||
| * A compute shader that sets up the algorithm and the swap span for the next swap operation. | ||
| * | ||
| * @type {ComputeNode} | ||
| */ | ||
| this.setAlgoFn = this._getSetAlgoFn(); | ||
| /** | ||
| * A compute shader that aligns the result of the global swap operation with the current buffer. | ||
| * | ||
| * @type {ComputeNode} | ||
| */ | ||
| this.alignFn = this._getAlignFn(); | ||
| /** | ||
| * A compute shader that resets the algorithm and swap span information. | ||
| * | ||
| * @type {ComputeNode} | ||
| */ | ||
| this.resetFn = this._getResetFn(); | ||
| /** | ||
| * The current compute shader dispatch within the list of dispatches needed to complete the sort. | ||
| * | ||
| * @type {number} | ||
| */ | ||
| this.currentDispatch = 0; | ||
| /** | ||
| * The number of global swap operations that must be executed before the sort | ||
| * can swap in local address space. | ||
| * | ||
| * @type {number} | ||
| */ | ||
| this.globalOpsRemaining = 0; | ||
| /** | ||
| * The total number of global operations needed to sort elements within the current swap span. | ||
| * | ||
| * @type {number} | ||
| */ | ||
| this.globalOpsInSpan = 0; | ||
| } | ||
| /** | ||
| * Get total number of distinct swaps that occur in a bitonic sort. | ||
| * | ||
| * @private | ||
| * @returns {number} - The total number of distinct swaps in a bitonic sort | ||
| */ | ||
| _getSwapOpCount() { | ||
| const n = Math.log2( this.count ); | ||
| return ( n * ( n + 1 ) ) / 2; | ||
| } | ||
| /** | ||
| * Get the number of steps it takes to execute a complete bitonic sort. | ||
| * | ||
| * @private | ||
| * @returns {number} The number of steps it takes to execute a complete bitonic sort. | ||
| */ | ||
| _getStepCount() { | ||
| const logElements = Math.log2( this.count ); | ||
| const logSwapSpan = Math.log2( this.workgroupSize * 2 ); | ||
| const numGlobalFlips = logElements - logSwapSpan; | ||
| // Start with 1 for initial sort over all local elements | ||
| let numSteps = 1; | ||
| let numGlobalDisperses = 0; | ||
| for ( let i = 1; i <= numGlobalFlips; i ++ ) { | ||
| // Increment by the global flip that starts each global block | ||
| numSteps += 1; | ||
| // Increment by number of global disperses following the global flip | ||
| numSteps += numGlobalDisperses; | ||
| // Increment by local disperse that occurs after all global swaps are finished | ||
| numSteps += 1; | ||
| // Number of global disperse increases as swapSpan increases by factor of 2 | ||
| numGlobalDisperses += 1; | ||
| } | ||
| return numSteps; | ||
| } | ||
| /** | ||
| * Compares and swaps two data points in the data buffer within the global address space. | ||
| * @param {Node<uint>} idxBefore - The index of the first data element in the data buffer. | ||
| * @param {Node<uint>} idxAfter - The index of the second data element in the data buffer. | ||
| * @param {StorageBufferNode} dataBuffer - The buffer of data to read from. | ||
| * @param {StorageBufferNode} tempBuffer - The buffer of data to write to. | ||
| * @private | ||
| * | ||
| */ | ||
| _globalCompareAndSwapTSL( idxBefore, idxAfter, dataBuffer, tempBuffer ) { | ||
| const data1 = dataBuffer.element( idxBefore ); | ||
| const data2 = dataBuffer.element( idxAfter ); | ||
| tempBuffer.element( idxBefore ).assign( min( data1, data2 ) ); | ||
| tempBuffer.element( idxAfter ).assign( max( data1, data2 ) ); | ||
| } | ||
| /** | ||
| * Compares and swaps two data points in the data buffer within the local address space. | ||
| * | ||
| * @private | ||
| * @param {Node<uint>} idxBefore - The index of the first data element in the data buffer. | ||
| * @param {Node<uint>} idxAfter - The index of the second data element in the data buffer | ||
| */ | ||
| _localCompareAndSwapTSL( idxBefore, idxAfter ) { | ||
| const { localStorage } = this; | ||
| const data1 = localStorage.element( idxBefore ).toVar(); | ||
| const data2 = localStorage.element( idxAfter ).toVar(); | ||
| localStorage.element( idxBefore ).assign( min( data1, data2 ) ); | ||
| localStorage.element( idxAfter ).assign( max( data1, data2 ) ); | ||
| } | ||
| /** | ||
| * Create the compute shader that performs a global disperse swap on the data buffer. | ||
| * | ||
| * @private | ||
| * @param {StorageBufferNode} readBuffer - The data buffer to read from. | ||
| * @param {StorageBufferNode} writeBuffer - The data buffer to read from. | ||
| * @returns {ComputeNode} - A compute shader that performs a global disperse swap on the data buffer. | ||
| */ | ||
| _getDisperseGlobal( readBuffer, writeBuffer ) { | ||
| const { infoStorage } = this; | ||
| const currentSwapSpan = infoStorage.element( 1 ); | ||
| const fnDef = Fn( () => { | ||
| const idx = getBitonicDisperseIndices( instanceIndex, currentSwapSpan ); | ||
| this._globalCompareAndSwapTSL( idx.x, idx.y, readBuffer, writeBuffer ); | ||
| } )().compute( this.dispatchSize, [ this.workgroupSize ] ); | ||
| return fnDef; | ||
| } | ||
| /** | ||
| * Create the compute shader that performs a global flip swap on the data buffer. | ||
| * | ||
| * @private | ||
| * @param {StorageBufferNode} readBuffer - The data buffer to read from. | ||
| * @param {StorageBufferNode} writeBuffer - The data buffer to read from. | ||
| * @returns {ComputeNode} - A compute shader that executes a global flip swap. | ||
| */ | ||
| _getFlipGlobal( readBuffer, writeBuffer ) { | ||
| const { infoStorage } = this; | ||
| const currentSwapSpan = infoStorage.element( 1 ); | ||
| const fnDef = Fn( () => { | ||
| const idx = getBitonicFlipIndices( instanceIndex, currentSwapSpan ); | ||
| this._globalCompareAndSwapTSL( idx.x, idx.y, readBuffer, writeBuffer ); | ||
| } )().compute( this.dispatchSize, [ this.workgroupSize ] ); | ||
| return fnDef; | ||
| } | ||
| /** | ||
| * Create the compute shader that performs a complete local swap on the data buffer. | ||
| * | ||
| * @private | ||
| * @returns {ComputeNode} - A compute shader that executes a full local swap. | ||
| */ | ||
| _getSwapLocal() { | ||
| const { localStorage, dataBuffer, workgroupSize } = this; | ||
| const fnDef = Fn( () => { | ||
| // Get ids of indices needed to populate workgroup local buffer. | ||
| // Use .toVar() to prevent these values from being recalculated multiple times. | ||
| const localOffset = uint( workgroupSize ).mul( 2 ).mul( workgroupId.x ).toVar(); | ||
| const localID1 = invocationLocalIndex.mul( 2 ); | ||
| const localID2 = invocationLocalIndex.mul( 2 ).add( 1 ); | ||
| localStorage.element( localID1 ).assign( dataBuffer.element( localOffset.add( localID1 ) ) ); | ||
| localStorage.element( localID2 ).assign( dataBuffer.element( localOffset.add( localID2 ) ) ); | ||
| // Ensure that all local data has been populated | ||
| workgroupBarrier(); | ||
| // Perform a chunk of the sort in a single pass that operates entirely in workgroup local space | ||
| // SWAP_LOCAL will always be first pass, so we start with known block height of 2 | ||
| const flipBlockHeight = uint( 2 ); | ||
| Loop( { start: uint( 2 ), end: uint( workgroupSize * 2 ), type: 'uint', condition: '<=', update: '<<= 1' }, () => { | ||
| // Ensure that last dispatch block executed | ||
| workgroupBarrier(); | ||
| const flipIdx = getBitonicFlipIndices( invocationLocalIndex, flipBlockHeight ); | ||
| this._localCompareAndSwapTSL( flipIdx.x, flipIdx.y ); | ||
| const localBlockHeight = flipBlockHeight.div( 2 ); | ||
| Loop( { start: localBlockHeight, end: uint( 1 ), type: 'uint', condition: '>', update: '>>= 1' }, () => { | ||
| // Ensure that last dispatch op executed | ||
| workgroupBarrier(); | ||
| const disperseIdx = getBitonicDisperseIndices( invocationLocalIndex, localBlockHeight ); | ||
| this._localCompareAndSwapTSL( disperseIdx.x, disperseIdx.y ); | ||
| localBlockHeight.divAssign( 2 ); | ||
| } ); | ||
| // flipBlockHeight *= 2; | ||
| flipBlockHeight.shiftLeftAssign( 1 ); | ||
| } ); | ||
| // Ensure that all invocations have swapped their own regions of data | ||
| workgroupBarrier(); | ||
| dataBuffer.element( localOffset.add( localID1 ) ).assign( localStorage.element( localID1 ) ); | ||
| dataBuffer.element( localOffset.add( localID2 ) ).assign( localStorage.element( localID2 ) ); | ||
| } )().compute( this.dispatchSize, [ this.workgroupSize ] ); | ||
| return fnDef; | ||
| } | ||
| /** | ||
| * Create the compute shader that performs a local disperse swap on the data buffer. | ||
| * | ||
| * @private | ||
| * @param {StorageBufferNode} readWriteBuffer - The data buffer to read from and write to. | ||
| * @returns {ComputeNode} - A compute shader that executes a local disperse swap. | ||
| */ | ||
| _getDisperseLocal( readWriteBuffer ) { | ||
| const { localStorage, workgroupSize } = this; | ||
| const fnDef = Fn( () => { | ||
| // Get ids of indices needed to populate workgroup local buffer. | ||
| // Use .toVar() to prevent these values from being recalculated multiple times. | ||
| const localOffset = uint( workgroupSize ).mul( 2 ).mul( workgroupId.x ).toVar(); | ||
| const localID1 = invocationLocalIndex.mul( 2 ); | ||
| const localID2 = invocationLocalIndex.mul( 2 ).add( 1 ); | ||
| localStorage.element( localID1 ).assign( readWriteBuffer.element( localOffset.add( localID1 ) ) ); | ||
| localStorage.element( localID2 ).assign( readWriteBuffer.element( localOffset.add( localID2 ) ) ); | ||
| // Ensure that all local data has been populated | ||
| workgroupBarrier(); | ||
| const localBlockHeight = uint( workgroupSize * 2 ); | ||
| Loop( { start: localBlockHeight, end: uint( 1 ), type: 'uint', condition: '>', update: '>>= 1' }, () => { | ||
| // Ensure that last dispatch op executed | ||
| workgroupBarrier(); | ||
| const disperseIdx = getBitonicDisperseIndices( invocationLocalIndex, localBlockHeight ); | ||
| this._localCompareAndSwapTSL( disperseIdx.x, disperseIdx.y ); | ||
| localBlockHeight.divAssign( 2 ); | ||
| } ); | ||
| // Ensure that all invocations have swapped their own regions of data | ||
| workgroupBarrier(); | ||
| readWriteBuffer.element( localOffset.add( localID1 ) ).assign( localStorage.element( localID1 ) ); | ||
| readWriteBuffer.element( localOffset.add( localID2 ) ).assign( localStorage.element( localID2 ) ); | ||
| } )().compute( this.dispatchSize, [ this.workgroupSize ] ); | ||
| return fnDef; | ||
| } | ||
| /** | ||
| * Create the compute shader that resets the sort's algorithm information. | ||
| * | ||
| * @private | ||
| * @returns {ComputeNode} - A compute shader that resets the bitonic sort's algorithm information. | ||
| */ | ||
| _getResetFn() { | ||
| const fnDef = Fn( () => { | ||
| const { infoStorage } = this; | ||
| const currentAlgo = infoStorage.element( 0 ); | ||
| const currentSwapSpan = infoStorage.element( 1 ); | ||
| const maxSwapSpan = infoStorage.element( 2 ); | ||
| currentAlgo.assign( StepType.SWAP_LOCAL ); | ||
| currentSwapSpan.assign( 2 ); | ||
| maxSwapSpan.assign( 2 ); | ||
| } )().compute( 1 ); | ||
| return fnDef; | ||
| } | ||
| /** | ||
| * Create the compute shader that copies the state of the last global swap to the data buffer. | ||
| * | ||
| * @private | ||
| * @returns {ComputeNode} - A compute shader that copies the state of the last global swap to the data buffer. | ||
| */ | ||
| _getAlignFn() { | ||
| const { dataBuffer, tempBuffer } = this; | ||
| // TODO: Only do this in certain instances by ping-ponging which buffer gets sorted | ||
| // And only aligning if numDispatches % 2 === 1 | ||
| const fnDef = Fn( () => { | ||
| dataBuffer.element( instanceIndex ).assign( tempBuffer.element( instanceIndex ) ); | ||
| } )().compute( this.count, [ this.workgroupSize ] ); | ||
| return fnDef; | ||
| } | ||
| /** | ||
| * Create the compute shader that sets the bitonic sort algorithm's information. | ||
| * | ||
| * @private | ||
| * @returns {ComputeNode} - A compute shader that sets the bitonic sort algorithm's information. | ||
| */ | ||
| _getSetAlgoFn() { | ||
| const fnDef = Fn( () => { | ||
| const { infoStorage, workgroupSize } = this; | ||
| const currentAlgo = infoStorage.element( 0 ); | ||
| const currentSwapSpan = infoStorage.element( 1 ); | ||
| const maxSwapSpan = infoStorage.element( 2 ); | ||
| If( currentAlgo.equal( StepType.SWAP_LOCAL ), () => { | ||
| const nextHighestSwapSpan = uint( workgroupSize * 4 ); | ||
| currentAlgo.assign( StepType.FLIP_GLOBAL ); | ||
| currentSwapSpan.assign( nextHighestSwapSpan ); | ||
| maxSwapSpan.assign( nextHighestSwapSpan ); | ||
| } ).ElseIf( currentAlgo.equal( StepType.DISPERSE_LOCAL ), () => { | ||
| currentAlgo.assign( StepType.FLIP_GLOBAL ); | ||
| const nextHighestSwapSpan = maxSwapSpan.mul( 2 ); | ||
| currentSwapSpan.assign( nextHighestSwapSpan ); | ||
| maxSwapSpan.assign( nextHighestSwapSpan ); | ||
| } ).Else( () => { | ||
| const nextSwapSpan = currentSwapSpan.div( 2 ); | ||
| currentAlgo.assign( | ||
| select( | ||
| nextSwapSpan.lessThanEqual( uint( workgroupSize * 2 ) ), | ||
| StepType.DISPERSE_LOCAL, | ||
| StepType.DISPERSE_GLOBAL | ||
| ).uniformFlow() | ||
| ); | ||
| currentSwapSpan.assign( nextSwapSpan ); | ||
| } ); | ||
| } )().compute( 1 ); | ||
| return fnDef; | ||
| } | ||
| /** | ||
| * Executes a step of the bitonic sort operation. | ||
| * | ||
| * @param {Renderer} renderer - The current scene's renderer. | ||
| */ | ||
| computeStep( renderer ) { | ||
| // Swap local only runs once | ||
| if ( this.currentDispatch === 0 ) { | ||
| renderer.compute( this.swapLocalFn ); | ||
| this.globalOpsRemaining = 1; | ||
| this.globalOpsInSpan = 1; | ||
| } else if ( this.globalOpsRemaining > 0 ) { | ||
| const swapType = this.globalOpsRemaining === this.globalOpsInSpan ? 'Flip' : 'Disperse'; | ||
| renderer.compute( swapType === 'Flip' ? this.flipGlobalNodes[ this.readBufferName ] : this.disperseGlobalNodes[ this.readBufferName ] ); | ||
| if ( this.readBufferName === 'Data' ) { | ||
| this.readBufferName = 'Temp'; | ||
| } else { | ||
| this.readBufferName = 'Data'; | ||
| } | ||
| this.globalOpsRemaining -= 1; | ||
| } else { | ||
| // Then run local disperses when we've finished all global swaps | ||
| renderer.compute( this.disperseLocalNodes[ this.readBufferName ] ); | ||
| const nextSpanGlobalOps = this.globalOpsInSpan + 1; | ||
| this.globalOpsInSpan = nextSpanGlobalOps; | ||
| this.globalOpsRemaining = nextSpanGlobalOps; | ||
| } | ||
| this.currentDispatch += 1; | ||
| if ( this.currentDispatch === this.stepCount ) { | ||
| // If our last swap addressed only addressed the temp buffer, then re-align it with the data buffer | ||
| // to fulfill the requirement of an in-place sort. | ||
| if ( this.readBufferName === 'Temp' ) { | ||
| renderer.compute( this.alignFn ); | ||
| this.readBufferName = 'Data'; | ||
| } | ||
| // Just reset the algorithm information | ||
| renderer.compute( this.resetFn ); | ||
| this.currentDispatch = 0; | ||
| this.globalOpsRemaining = 0; | ||
| this.globalOpsInSpan = 0; | ||
| } else { | ||
| // Otherwise, determine what next swap span is | ||
| renderer.compute( this.setAlgoFn ); | ||
| } | ||
| } | ||
| /** | ||
| * Executes a complete bitonic sort on the data buffer. | ||
| * | ||
| * @param {Renderer} renderer - The current scene's renderer. | ||
| */ | ||
| compute( renderer ) { | ||
| this.globalOpsRemaining = 0; | ||
| this.globalOpsInSpan = 0; | ||
| this.currentDispatch = 0; | ||
| for ( let i = 0; i < this.stepCount; i ++ ) { | ||
| this.computeStep( renderer ); | ||
| } | ||
| } | ||
| } |
| import { RendererInspector } from './RendererInspector.js'; | ||
| import { Profiler } from './ui/Profiler.js'; | ||
| import { Performance } from './tabs/Performance.js'; | ||
| import { Console } from './tabs/Console.js'; | ||
| import { Parameters } from './tabs/Parameters.js'; | ||
| import { Viewer } from './tabs/Viewer.js'; | ||
| import { setText, splitPath, splitCamelCase } from './ui/utils.js'; | ||
| import { QuadMesh, NodeMaterial, CanvasTarget, setConsoleFunction, REVISION, NoToneMapping } from 'three/webgpu'; | ||
| import { renderOutput, vec3, vec4 } from 'three/tsl'; | ||
| class Inspector extends RendererInspector { | ||
| constructor() { | ||
| super(); | ||
| // init profiler | ||
| const profiler = new Profiler(); | ||
| const parameters = new Parameters(); | ||
| parameters.hide(); | ||
| profiler.addTab( parameters ); | ||
| const viewer = new Viewer(); | ||
| viewer.hide(); | ||
| profiler.addTab( viewer ); | ||
| const performance = new Performance(); | ||
| profiler.addTab( performance ); | ||
| const console = new Console(); | ||
| profiler.addTab( console ); | ||
| profiler.setActiveTab( performance.id ); | ||
| // | ||
| this.statsData = new Map(); | ||
| this.canvasNodes = new Map(); | ||
| this.profiler = profiler; | ||
| this.performance = performance; | ||
| this.console = console; | ||
| this.parameters = parameters; | ||
| this.viewer = viewer; | ||
| this.once = {}; | ||
| this.displayCycle = { | ||
| text: { | ||
| needsUpdate: false, | ||
| duration: .25, | ||
| time: 0 | ||
| }, | ||
| graph: { | ||
| needsUpdate: false, | ||
| duration: .02, | ||
| time: 0 | ||
| } | ||
| }; | ||
| } | ||
| get domElement() { | ||
| return this.profiler.domElement; | ||
| } | ||
| resolveConsoleOnce( type, message ) { | ||
| const key = type + message; | ||
| if ( this.once[ key ] !== true ) { | ||
| this.resolveConsole( type, message ); | ||
| this.once[ key ] = true; | ||
| } | ||
| } | ||
| resolveConsole( type, message ) { | ||
| switch ( type ) { | ||
| case 'log': | ||
| this.console.addMessage( 'info', message ); | ||
| console.log( message ); | ||
| break; | ||
| case 'warn': | ||
| this.console.addMessage( 'warn', message ); | ||
| console.warn( message ); | ||
| break; | ||
| case 'error': | ||
| this.console.addMessage( 'error', message ); | ||
| console.error( message ); | ||
| break; | ||
| } | ||
| } | ||
| init() { | ||
| const renderer = this.getRenderer(); | ||
| let sign = `THREE.WebGPURenderer: ${ REVISION } [ "`; | ||
| if ( renderer.backend.isWebGPUBackend ) { | ||
| sign += 'WebGPU'; | ||
| } else if ( renderer.backend.isWebGLBackend ) { | ||
| sign += 'WebGL2'; | ||
| } | ||
| sign += '" ]'; | ||
| this.console.addMessage( 'info', sign ); | ||
| // | ||
| if ( renderer.inspector.domElement.parentElement === null && renderer.domElement.parentElement !== null ) { | ||
| renderer.domElement.parentElement.appendChild( renderer.inspector.domElement ); | ||
| } | ||
| } | ||
| setRenderer( renderer ) { | ||
| super.setRenderer( renderer ); | ||
| if ( renderer !== null ) { | ||
| setConsoleFunction( this.resolveConsole.bind( this ) ); | ||
| if ( this.isAvailable ) { | ||
| renderer.backend.trackTimestamp = true; | ||
| renderer.init().then( () => { | ||
| if ( renderer.hasFeature( 'timestamp-query' ) !== true ) { | ||
| this.console.addMessage( 'error', 'THREE.Inspector: GPU Timestamp Queries not available.' ); | ||
| } | ||
| } ); | ||
| } | ||
| } | ||
| return this; | ||
| } | ||
| createParameters( name ) { | ||
| if ( this.parameters.isVisible === false ) { | ||
| this.parameters.show(); | ||
| this.profiler.setActiveTab( this.parameters.id ); | ||
| } | ||
| return this.parameters.createGroup( name ); | ||
| } | ||
| getStatsData( cid ) { | ||
| let data = this.statsData.get( cid ); | ||
| if ( data === undefined ) { | ||
| data = {}; | ||
| this.statsData.set( cid, data ); | ||
| } | ||
| return data; | ||
| } | ||
| resolveStats( stats ) { | ||
| const data = this.getStatsData( stats.cid ); | ||
| if ( data.initialized !== true ) { | ||
| data.cpu = stats.cpu; | ||
| data.gpu = stats.gpu; | ||
| data.stats = []; | ||
| data.initialized = true; | ||
| } | ||
| // store stats | ||
| if ( data.stats.length > this.maxFrames ) { | ||
| data.stats.shift(); | ||
| } | ||
| data.stats.push( stats ); | ||
| // compute averages | ||
| data.cpu = this.getAverageDeltaTime( data, 'cpu' ); | ||
| data.gpu = this.getAverageDeltaTime( data, 'gpu' ); | ||
| data.total = data.cpu + data.gpu; | ||
| // children | ||
| for ( const child of stats.children ) { | ||
| this.resolveStats( child ); | ||
| const childData = this.getStatsData( child.cid ); | ||
| data.cpu += childData.cpu; | ||
| data.gpu += childData.gpu; | ||
| data.total += childData.total; | ||
| } | ||
| } | ||
| getCanvasDataByNode( node ) { | ||
| let canvasData = this.canvasNodes.get( node ); | ||
| if ( canvasData === undefined ) { | ||
| const renderer = this.getRenderer(); | ||
| const canvas = document.createElement( 'canvas' ); | ||
| const canvasTarget = new CanvasTarget( canvas ); | ||
| canvasTarget.setPixelRatio( window.devicePixelRatio ); | ||
| canvasTarget.setSize( 140, 140 ); | ||
| const id = node.id; | ||
| const { path, name } = splitPath( splitCamelCase( node.getName() || '(unnamed)' ) ); | ||
| let output = vec4( vec3( node ), 1 ); | ||
| output = renderOutput( output, NoToneMapping, renderer.outputColorSpace ); | ||
| output = output.context( { inspector: true } ); | ||
| const material = new NodeMaterial(); | ||
| material.outputNode = output; | ||
| const quad = new QuadMesh( material ); | ||
| quad.name = 'Viewer - ' + name; | ||
| canvasData = { | ||
| id, | ||
| name, | ||
| path, | ||
| node, | ||
| quad, | ||
| canvasTarget, | ||
| material | ||
| }; | ||
| this.canvasNodes.set( node, canvasData ); | ||
| } | ||
| return canvasData; | ||
| } | ||
| resolveViewer() { | ||
| const nodes = this.currentNodes; | ||
| const renderer = this.getRenderer(); | ||
| if ( nodes.length === 0 ) return; | ||
| if ( ! renderer.backend.isWebGPUBackend ) { | ||
| this.resolveConsoleOnce( 'warn', 'Inspector: Viewer is only available with WebGPU.' ); | ||
| return; | ||
| } | ||
| // | ||
| if ( ! this.viewer.isVisible ) { | ||
| this.viewer.show(); | ||
| } | ||
| const canvasDataList = nodes.map( node => this.getCanvasDataByNode( node ) ); | ||
| this.viewer.update( renderer, canvasDataList ); | ||
| } | ||
| getAverageDeltaTime( statsData, property, frames = this.fps ) { | ||
| const statsArray = statsData.stats; | ||
| let sum = 0; | ||
| let count = 0; | ||
| for ( let i = statsArray.length - 1; i >= 0 && count < frames; i -- ) { | ||
| const stats = statsArray[ i ]; | ||
| const value = stats[ property ]; | ||
| if ( value > 0 ) { | ||
| // ignore invalid values | ||
| sum += value; | ||
| count ++; | ||
| } | ||
| } | ||
| return count > 0 ? sum / count : 0; | ||
| } | ||
| resolveFrame( frame ) { | ||
| const nextFrame = this.getFrameById( frame.frameId + 1 ); | ||
| if ( ! nextFrame ) return; | ||
| frame.cpu = 0; | ||
| frame.gpu = 0; | ||
| frame.total = 0; | ||
| for ( const stats of frame.children ) { | ||
| this.resolveStats( stats ); | ||
| const data = this.getStatsData( stats.cid ); | ||
| frame.cpu += data.cpu; | ||
| frame.gpu += data.gpu; | ||
| frame.total += data.total; | ||
| } | ||
| // improve stats using next frame | ||
| frame.deltaTime = nextFrame.startTime - frame.startTime; | ||
| frame.miscellaneous = frame.deltaTime - frame.total; | ||
| if ( frame.miscellaneous < 0 ) { | ||
| // Frame desync, probably due to async GPU timing. | ||
| frame.miscellaneous = 0; | ||
| } | ||
| // | ||
| this.updateCycle( this.displayCycle.text ); | ||
| this.updateCycle( this.displayCycle.graph ); | ||
| if ( this.displayCycle.text.needsUpdate ) { | ||
| setText( 'fps-counter', this.fps.toFixed() ); | ||
| this.performance.updateText( this, frame ); | ||
| } | ||
| if ( this.displayCycle.graph.needsUpdate ) { | ||
| this.performance.updateGraph( this, frame ); | ||
| } | ||
| this.displayCycle.text.needsUpdate = false; | ||
| this.displayCycle.graph.needsUpdate = false; | ||
| } | ||
| updateCycle( cycle ) { | ||
| cycle.time += this.nodeFrame.deltaTime; | ||
| if ( cycle.time >= cycle.duration ) { | ||
| cycle.needsUpdate = true; | ||
| cycle.time = 0; | ||
| } | ||
| } | ||
| } | ||
| export { Inspector }; |
| import { InspectorBase, TimestampQuery } from 'three/webgpu'; | ||
| class ObjectStats { | ||
| constructor( uid, name ) { | ||
| this.uid = uid; | ||
| this.cid = uid.match( /^(.*):f(\d+)$/ )[ 1 ]; // call id | ||
| this.name = name; | ||
| this.timestamp = 0; | ||
| this.cpu = 0; | ||
| this.gpu = 0; | ||
| this.fps = 0; | ||
| this.children = []; | ||
| this.parent = null; | ||
| } | ||
| } | ||
| class RenderStats extends ObjectStats { | ||
| constructor( uid, scene, camera, renderTarget ) { | ||
| let name = scene.name; | ||
| if ( name === '' ) { | ||
| if ( scene.isScene ) { | ||
| name = 'Scene'; | ||
| } else if ( scene.isQuadMesh ) { | ||
| name = 'QuadMesh'; | ||
| } | ||
| } | ||
| super( uid, name ); | ||
| this.scene = scene; | ||
| this.camera = camera; | ||
| this.renderTarget = renderTarget; | ||
| this.isRenderStats = true; | ||
| } | ||
| } | ||
| class ComputeStats extends ObjectStats { | ||
| constructor( uid, computeNode ) { | ||
| super( uid, computeNode.name ); | ||
| this.computeNode = computeNode; | ||
| this.isComputeStats = true; | ||
| } | ||
| } | ||
| export class RendererInspector extends InspectorBase { | ||
| constructor() { | ||
| super(); | ||
| this.currentFrame = null; | ||
| this.currentRender = null; | ||
| this.currentNodes = null; | ||
| this.lastFrame = null; | ||
| this.frames = []; | ||
| this.framesLib = {}; | ||
| this.maxFrames = 512; | ||
| this._lastFinishTime = 0; | ||
| this._resolveTimestampPromise = null; | ||
| this.isRendererInspector = true; | ||
| } | ||
| getParent() { | ||
| return this.currentRender || this.getFrame(); | ||
| } | ||
| begin() { | ||
| this.currentFrame = this._createFrame(); | ||
| this.currentRender = this.currentFrame; | ||
| this.currentNodes = []; | ||
| } | ||
| finish() { | ||
| const now = performance.now(); | ||
| const frame = this.currentFrame; | ||
| frame.finishTime = now; | ||
| frame.deltaTime = now - ( this._lastFinishTime > 0 ? this._lastFinishTime : now ); | ||
| this.addFrame( frame ); | ||
| this.fps = this._getFPS(); | ||
| this.lastFrame = frame; | ||
| this.currentFrame = null; | ||
| this.currentRender = null; | ||
| this.currentNodes = null; | ||
| this._lastFinishTime = now; | ||
| } | ||
| _getFPS() { | ||
| let frameSum = 0; | ||
| let timeSum = 0; | ||
| for ( let i = this.frames.length - 1; i >= 0; i -- ) { | ||
| const frame = this.frames[ i ]; | ||
| frameSum ++; | ||
| timeSum += frame.deltaTime; | ||
| if ( timeSum >= 1000 ) break; | ||
| } | ||
| return ( frameSum * 1000 ) / timeSum; | ||
| } | ||
| _createFrame() { | ||
| return { | ||
| frameId: this.nodeFrame.frameId, | ||
| resolvedCompute: false, | ||
| resolvedRender: false, | ||
| deltaTime: 0, | ||
| startTime: performance.now(), | ||
| finishTime: 0, | ||
| miscellaneous: 0, | ||
| children: [], | ||
| renders: [], | ||
| computes: [] | ||
| }; | ||
| } | ||
| getFrame() { | ||
| return this.currentFrame || this.lastFrame; | ||
| } | ||
| getFrameById( frameId ) { | ||
| return this.framesLib[ frameId ] || null; | ||
| } | ||
| resolveViewer() { } | ||
| resolveFrame( /*frame*/ ) { } | ||
| async resolveTimestamp() { | ||
| if ( this._resolveTimestampPromise !== null ) { | ||
| return this._resolveTimestampPromise; | ||
| } | ||
| this._resolveTimestampPromise = new Promise( ( resolve ) => { | ||
| requestAnimationFrame( async () => { | ||
| const renderer = this.getRenderer(); | ||
| await renderer.resolveTimestampsAsync( TimestampQuery.COMPUTE ); | ||
| await renderer.resolveTimestampsAsync( TimestampQuery.RENDER ); | ||
| const computeFrames = renderer.backend.getTimestampFrames( TimestampQuery.COMPUTE ); | ||
| const renderFrames = renderer.backend.getTimestampFrames( TimestampQuery.RENDER ); | ||
| const frameIds = [ ...new Set( [ ...computeFrames, ...renderFrames ] ) ]; | ||
| for ( const frameId of frameIds ) { | ||
| const frame = this.getFrameById( frameId ); | ||
| if ( frame !== null ) { | ||
| // resolve compute timestamps | ||
| if ( frame.resolvedCompute === false ) { | ||
| if ( frame.computes.length > 0 ) { | ||
| if ( computeFrames.includes( frameId ) ) { | ||
| for ( const stats of frame.computes ) { | ||
| if ( renderer.backend.hasTimestamp( stats.uid ) ) { | ||
| stats.gpu = renderer.backend.getTimestamp( stats.uid ); | ||
| } else { | ||
| stats.gpu = 0; | ||
| stats.gpuNotAvailable = true; | ||
| } | ||
| } | ||
| frame.resolvedCompute = true; | ||
| } | ||
| } else { | ||
| frame.resolvedCompute = true; | ||
| } | ||
| } | ||
| // resolve render timestamps | ||
| if ( frame.resolvedRender === false ) { | ||
| if ( frame.renders.length > 0 ) { | ||
| if ( renderFrames.includes( frameId ) ) { | ||
| for ( const stats of frame.renders ) { | ||
| if ( renderer.backend.hasTimestamp( stats.uid ) ) { | ||
| stats.gpu = renderer.backend.getTimestamp( stats.uid ); | ||
| } else { | ||
| stats.gpu = 0; | ||
| stats.gpuNotAvailable = true; | ||
| } | ||
| } | ||
| frame.resolvedRender = true; | ||
| } | ||
| } else { | ||
| frame.resolvedRender = true; | ||
| } | ||
| } | ||
| if ( frame.resolvedCompute === true && frame.resolvedRender === true ) { | ||
| this.resolveFrame( frame ); | ||
| } | ||
| } | ||
| } | ||
| this._resolveTimestampPromise = null; | ||
| resolve(); | ||
| } ); | ||
| } ); | ||
| return this._resolveTimestampPromise; | ||
| } | ||
| get isAvailable() { | ||
| const renderer = this.getRenderer(); | ||
| return renderer !== null; | ||
| } | ||
| addFrame( frame ) { | ||
| // Limit to max frames. | ||
| if ( this.frames.length >= this.maxFrames ) { | ||
| const removedFrame = this.frames.shift(); | ||
| delete this.framesLib[ removedFrame.frameId ]; | ||
| } | ||
| this.frames.push( frame ); | ||
| this.framesLib[ frame.frameId ] = frame; | ||
| if ( this.isAvailable ) { | ||
| this.resolveViewer(); | ||
| this.resolveTimestamp(); | ||
| } | ||
| } | ||
| inspect( node ) { | ||
| this.currentNodes.push( node ); | ||
| } | ||
| beginCompute( uid, computeNode ) { | ||
| const frame = this.getFrame(); | ||
| if ( ! frame ) return; | ||
| const currentCompute = new ComputeStats( uid, computeNode ); | ||
| currentCompute.timestamp = performance.now(); | ||
| currentCompute.parent = this.currentCompute || this.getParent(); | ||
| frame.computes.push( currentCompute ); | ||
| if ( this.currentRender !== null ) { | ||
| this.currentRender.children.push( currentCompute ); | ||
| } else { | ||
| frame.children.push( currentCompute ); | ||
| } | ||
| this.currentCompute = currentCompute; | ||
| } | ||
| finishCompute() { | ||
| const frame = this.getFrame(); | ||
| if ( ! frame ) return; | ||
| const currentCompute = this.currentCompute; | ||
| currentCompute.cpu = performance.now() - currentCompute.timestamp; | ||
| this.currentCompute = currentCompute.parent.isComputeStats ? currentCompute.parent : null; | ||
| } | ||
| beginRender( uid, scene, camera, renderTarget ) { | ||
| const frame = this.getFrame(); | ||
| if ( ! frame ) return; | ||
| const currentRender = new RenderStats( uid, scene, camera, renderTarget ); | ||
| currentRender.timestamp = performance.now(); | ||
| currentRender.parent = this.getParent(); | ||
| frame.renders.push( currentRender ); | ||
| if ( this.currentRender !== null ) { | ||
| this.currentRender.children.push( currentRender ); | ||
| } else { | ||
| frame.children.push( currentRender ); | ||
| } | ||
| this.currentRender = currentRender; | ||
| } | ||
| finishRender() { | ||
| const frame = this.getFrame(); | ||
| if ( ! frame ) return; | ||
| const currentRender = this.currentRender; | ||
| currentRender.cpu = performance.now() - currentRender.timestamp; | ||
| this.currentRender = currentRender.parent; | ||
| } | ||
| } |
| import { Tab } from '../ui/Tab.js'; | ||
| class Console extends Tab { | ||
| constructor() { | ||
| super( 'Console' ); | ||
| this.filters = { info: true, warn: true, error: true }; | ||
| this.filterText = ''; | ||
| this.buildHeader(); | ||
| this.logContainer = document.createElement( 'div' ); | ||
| this.logContainer.id = 'console-log'; | ||
| this.content.appendChild( this.logContainer ); | ||
| } | ||
| buildHeader() { | ||
| const header = document.createElement( 'div' ); | ||
| header.className = 'console-header'; | ||
| const filterInput = document.createElement( 'input' ); | ||
| filterInput.type = 'text'; | ||
| filterInput.className = 'console-filter-input'; | ||
| filterInput.placeholder = 'Filter...'; | ||
| filterInput.addEventListener( 'input', ( e ) => { | ||
| this.filterText = e.target.value.toLowerCase(); | ||
| this.applyFilters(); | ||
| } ); | ||
| const filtersGroup = document.createElement( 'div' ); | ||
| filtersGroup.className = 'console-filters-group'; | ||
| Object.keys( this.filters ).forEach( type => { | ||
| const label = document.createElement( 'label' ); | ||
| label.className = 'custom-checkbox'; | ||
| label.style.color = `var(--${type === 'info' ? 'text-primary' : 'color-' + ( type === 'warn' ? 'yellow' : 'red' )})`; | ||
| const checkbox = document.createElement( 'input' ); | ||
| checkbox.type = 'checkbox'; | ||
| checkbox.checked = this.filters[ type ]; | ||
| checkbox.dataset.type = type; | ||
| const checkmark = document.createElement( 'span' ); | ||
| checkmark.className = 'checkmark'; | ||
| label.appendChild( checkbox ); | ||
| label.appendChild( checkmark ); | ||
| label.append( type.charAt( 0 ).toUpperCase() + type.slice( 1 ) ); | ||
| filtersGroup.appendChild( label ); | ||
| } ); | ||
| filtersGroup.addEventListener( 'change', ( e ) => { | ||
| const type = e.target.dataset.type; | ||
| if ( type in this.filters ) { | ||
| this.filters[ type ] = e.target.checked; | ||
| this.applyFilters(); | ||
| } | ||
| } ); | ||
| header.appendChild( filterInput ); | ||
| header.appendChild( filtersGroup ); | ||
| this.content.appendChild( header ); | ||
| } | ||
| applyFilters() { | ||
| const messages = this.logContainer.querySelectorAll( '.log-message' ); | ||
| messages.forEach( msg => { | ||
| const type = msg.dataset.type; | ||
| const text = msg.dataset.rawText.toLowerCase(); | ||
| const showByType = this.filters[ type ]; | ||
| const showByText = text.includes( this.filterText ); | ||
| msg.classList.toggle( 'hidden', ! ( showByType && showByText ) ); | ||
| } ); | ||
| } | ||
| _getIcon( type, subType ) { | ||
| let icon; | ||
| if ( subType === 'tip' ) { | ||
| icon = '💭'; | ||
| } else if ( subType === 'tsl' ) { | ||
| icon = '✨'; | ||
| } else if ( subType === 'webgpurenderer' ) { | ||
| icon = '🎨'; | ||
| } else if ( type === 'warn' ) { | ||
| icon = '⚠️'; | ||
| } else if ( type === 'error' ) { | ||
| icon = '🔴'; | ||
| } else if ( type === 'info' ) { | ||
| icon = 'ℹ️'; | ||
| } | ||
| return icon; | ||
| } | ||
| _formatMessage( type, text ) { | ||
| const fragment = document.createDocumentFragment(); | ||
| const prefixMatch = text.match( /^([\w\.]+:\s)/ ); | ||
| let content = text; | ||
| if ( prefixMatch ) { | ||
| const fullPrefix = prefixMatch[ 0 ]; | ||
| const parts = fullPrefix.slice( 0, - 2 ).split( '.' ); | ||
| const shortPrefix = ( parts.length > 1 ? parts[ parts.length - 1 ] : parts[ 0 ] ) + ':'; | ||
| const icon = this._getIcon( type, shortPrefix.split( ':' )[ 0 ].toLowerCase() ); | ||
| fragment.appendChild( document.createTextNode( icon + ' ' ) ); | ||
| const prefixSpan = document.createElement( 'span' ); | ||
| prefixSpan.className = 'log-prefix'; | ||
| prefixSpan.textContent = shortPrefix; | ||
| fragment.appendChild( prefixSpan ); | ||
| content = text.substring( fullPrefix.length ); | ||
| } | ||
| const parts = content.split( /(".*?"|'.*?'|`.*?`)/g ).map( p => p.trim() ).filter( Boolean ); | ||
| parts.forEach( ( part, index ) => { | ||
| if ( /^("|'|`)/.test( part ) ) { | ||
| const codeSpan = document.createElement( 'span' ); | ||
| codeSpan.className = 'log-code'; | ||
| codeSpan.textContent = part.slice( 1, - 1 ); | ||
| fragment.appendChild( codeSpan ); | ||
| } else { | ||
| if ( index > 0 ) part = ' ' + part; // add space before parts except the first | ||
| if ( index < parts.length - 1 ) part += ' '; // add space between parts | ||
| fragment.appendChild( document.createTextNode( part ) ); | ||
| } | ||
| } ); | ||
| return fragment; | ||
| } | ||
| addMessage( type, text ) { | ||
| const msg = document.createElement( 'div' ); | ||
| msg.className = `log-message ${type}`; | ||
| msg.dataset.type = type; | ||
| msg.dataset.rawText = text; | ||
| msg.appendChild( this._formatMessage( type, text ) ); | ||
| const showByType = this.filters[ type ]; | ||
| const showByText = text.toLowerCase().includes( this.filterText ); | ||
| msg.classList.toggle( 'hidden', ! ( showByType && showByText ) ); | ||
| this.logContainer.appendChild( msg ); | ||
| this.logContainer.scrollTop = this.logContainer.scrollHeight; | ||
| if ( this.logContainer.children.length > 200 ) { | ||
| this.logContainer.removeChild( this.logContainer.firstChild ); | ||
| } | ||
| } | ||
| } | ||
| export { Console }; |
| 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'; | ||
| class ParametersGroup { | ||
| constructor( parameters, name ) { | ||
| this.parameters = parameters; | ||
| this.name = name; | ||
| this.paramList = new Item( name ); | ||
| } | ||
| close() { | ||
| this.paramList.close(); | ||
| return this; | ||
| } | ||
| add( object, property, ...params ) { | ||
| const value = object[ property ]; | ||
| const type = typeof value; | ||
| let item = null; | ||
| if ( typeof params[ 0 ] === 'object' ) { | ||
| item = this.addSelect( object, property, params[ 0 ] ); | ||
| } else if ( type === 'number' ) { | ||
| if ( params.length >= 2 ) { | ||
| item = this.addSlider( object, property, ...params ); | ||
| } else { | ||
| item = this.addNumber( object, property, ...params ); | ||
| } | ||
| } else if ( type === 'boolean' ) { | ||
| item = this.addBoolean( object, property ); | ||
| } else if ( type === 'function' ) { | ||
| item = this.addButton( object, property, ...params ); | ||
| } | ||
| return item; | ||
| } | ||
| _addParameter( object, property, editor, subItem ) { | ||
| editor.name = ( name ) => { | ||
| subItem.data[ 0 ].textContent = name; | ||
| return editor; | ||
| }; | ||
| editor.listen = () => { | ||
| const update = () => { | ||
| const value = editor.getValue(); | ||
| const propertyValue = object[ property ]; | ||
| if ( value !== propertyValue ) { | ||
| editor.setValue( propertyValue ); | ||
| } | ||
| requestAnimationFrame( update ); | ||
| }; | ||
| requestAnimationFrame( update ); | ||
| return editor; | ||
| }; | ||
| } | ||
| addFolder( name ) { | ||
| const group = new ParametersGroup( this.parameters, name ); | ||
| this.paramList.add( group.paramList ); | ||
| return group; | ||
| } | ||
| addBoolean( object, property ) { | ||
| const value = object[ property ]; | ||
| const editor = new ValueCheckbox( { 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 ); | ||
| // extends logic to toggle checkbox when clicking on the row | ||
| const itemRow = subItem.domElement.firstChild; | ||
| itemRow.classList.add( 'actionable' ); | ||
| itemRow.addEventListener( 'click', ( e ) => { | ||
| if ( e.target.closest( 'label' ) ) return; | ||
| const checkbox = itemRow.querySelector( 'input[type="checkbox"]' ); | ||
| if ( checkbox ) { | ||
| checkbox.checked = ! checkbox.checked; | ||
| checkbox.dispatchEvent( new Event( 'change' ) ); | ||
| } | ||
| } ); | ||
| // extend object property | ||
| this._addParameter( object, property, editor, subItem ); | ||
| return editor; | ||
| } | ||
| addSelect( object, property, options ) { | ||
| const value = object[ property ]; | ||
| const editor = new ValueSelect( { options, 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; | ||
| } | ||
| addColor( object, property ) { | ||
| const value = object[ property ]; | ||
| const editor = new ValueColor( { 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; | ||
| } | ||
| addSlider( object, property, min = 0, max = 1, step = 0.01 ) { | ||
| const value = object[ property ]; | ||
| const editor = new ValueSlider( { value, min, max, step } ); | ||
| 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; | ||
| } | ||
| addNumber( object, property, ...params ) { | ||
| const value = object[ property ]; | ||
| const [ min, max ] = params; | ||
| const editor = new ValueNumber( { value, min, max } ); | ||
| 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; | ||
| } | ||
| addButton( object, property ) { | ||
| const value = object[ property ]; | ||
| const editor = new ValueButton( { text: property, value } ); | ||
| editor.addEventListener( 'change', ( { value } ) => { | ||
| object[ property ] = value; | ||
| } ); | ||
| const subItem = new Item( editor.domElement ); | ||
| subItem.itemRow.childNodes[ 0 ].style.gridColumn = '1 / -1'; | ||
| this.paramList.add( subItem ); | ||
| const itemRow = subItem.domElement.firstChild; | ||
| itemRow.classList.add( 'actionable' ); | ||
| // extend object property | ||
| editor.name = ( name ) => { | ||
| editor.domElement.childNodes[ 0 ].textContent = name; | ||
| return editor; | ||
| }; | ||
| return editor; | ||
| } | ||
| } | ||
| class Parameters extends Tab { | ||
| constructor() { | ||
| super( 'Parameters' ); | ||
| const paramList = new List( 'Property', 'Value' ); | ||
| paramList.domElement.classList.add( 'parameters' ); | ||
| paramList.setGridStyle( '.5fr 1fr' ); | ||
| paramList.domElement.style.minWidth = '300px'; | ||
| const scrollWrapper = document.createElement( 'div' ); | ||
| scrollWrapper.className = 'list-scroll-wrapper'; | ||
| scrollWrapper.appendChild( paramList.domElement ); | ||
| this.content.appendChild( scrollWrapper ); | ||
| this.paramList = paramList; | ||
| } | ||
| createGroup( name ) { | ||
| const group = new ParametersGroup( this, name ); | ||
| this.paramList.add( group.paramList ); | ||
| return group; | ||
| } | ||
| } | ||
| export { Parameters }; |
| import { Tab } from '../ui/Tab.js'; | ||
| import { List } from '../ui/List.js'; | ||
| import { Graph } from '../ui/Graph.js'; | ||
| import { Item } from '../ui/Item.js'; | ||
| import { createValueSpan, setText } from '../ui/utils.js'; | ||
| class Performance extends Tab { | ||
| constructor() { | ||
| super( 'Performance' ); | ||
| const perfList = new List( 'Name', 'CPU', 'GPU', 'Total' ); | ||
| perfList.setGridStyle( 'minmax(200px, 2fr) 80px 80px 80px' ); | ||
| perfList.domElement.style.minWidth = '600px'; | ||
| const scrollWrapper = document.createElement( 'div' ); | ||
| scrollWrapper.className = 'list-scroll-wrapper'; | ||
| scrollWrapper.appendChild( perfList.domElement ); | ||
| this.content.appendChild( scrollWrapper ); | ||
| // | ||
| const graphContainer = document.createElement( 'div' ); | ||
| graphContainer.className = 'graph-container'; | ||
| const graph = new Graph(); | ||
| graph.addLine( 'fps', '--accent-color' ); | ||
| //graph.addLine( 'gpu', '--color-yellow' ); | ||
| graphContainer.append( graph.domElement ); | ||
| // | ||
| /* | ||
| const label = document.createElement( 'label' ); | ||
| label.className = 'custom-checkbox'; | ||
| const checkbox = document.createElement( 'input' ); | ||
| checkbox.type = 'checkbox'; | ||
| const checkmark = document.createElement( 'span' ); | ||
| checkmark.className = 'checkmark'; | ||
| label.appendChild( checkbox ); | ||
| label.appendChild( checkmark ); | ||
| */ | ||
| const graphStats = new Item( 'Graph Stats', createValueSpan(), createValueSpan(), createValueSpan( 'graph-fps-counter' ) ); | ||
| perfList.add( graphStats ); | ||
| const graphItem = new Item( graphContainer ); | ||
| graphItem.itemRow.childNodes[ 0 ].style.gridColumn = '1 / -1'; | ||
| graphStats.add( graphItem ); | ||
| // | ||
| const frameStats = new Item( 'Frame Stats', createValueSpan(), createValueSpan(), createValueSpan() ); | ||
| perfList.add( frameStats ); | ||
| const miscellaneous = new Item( 'Miscellaneous & Idle', createValueSpan(), createValueSpan(), createValueSpan() ); | ||
| miscellaneous.domElement.firstChild.style.backgroundColor = '#00ff0b1a'; | ||
| miscellaneous.domElement.firstChild.classList.add( 'no-hover' ); | ||
| frameStats.add( miscellaneous ); | ||
| // | ||
| this.notInUse = new Map(); | ||
| this.frameStats = frameStats; | ||
| this.graphStats = graphStats; | ||
| this.graph = graph; | ||
| this.miscellaneous = miscellaneous; | ||
| // | ||
| this.currentRender = null; | ||
| this.currentItem = null; | ||
| this.frameItems = new Map(); | ||
| } | ||
| resolveStats( inspector, stats ) { | ||
| const data = inspector.getStatsData( stats.cid ); | ||
| let item = data.item; | ||
| if ( item === undefined ) { | ||
| item = new Item( createValueSpan(), createValueSpan(), createValueSpan(), createValueSpan() ); | ||
| if ( stats.name ) { | ||
| if ( stats.isComputeStats === true ) { | ||
| stats.name = `${ stats.name } [ Compute ]`; | ||
| } | ||
| } else { | ||
| stats.name = `Unnamed ${ stats.cid }`; | ||
| } | ||
| item.userData.name = stats.name; | ||
| this.currentItem.add( item ); | ||
| data.item = item; | ||
| } else { | ||
| item.userData.name = stats.name; | ||
| if ( this.notInUse.has( stats.cid ) ) { | ||
| item.domElement.firstElementChild.classList.remove( 'alert' ); | ||
| this.notInUse.delete( stats.cid ); | ||
| } | ||
| const statsIndex = stats.parent.children.indexOf( stats ); | ||
| if ( item.parent === null || item.parent.children.indexOf( item ) !== statsIndex ) { | ||
| this.currentItem.add( item, statsIndex ); | ||
| } | ||
| } | ||
| let name = item.userData.name; | ||
| if ( stats.isComputeStats ) { | ||
| name += ' [ Compute ]'; | ||
| } | ||
| setText( item.data[ 0 ], name ); | ||
| setText( item.data[ 1 ], data.cpu.toFixed( 2 ) ); | ||
| setText( item.data[ 2 ], stats.gpuNotAvailable === true ? '-' : data.gpu.toFixed( 2 ) ); | ||
| setText( item.data[ 3 ], data.total.toFixed( 2 ) ); | ||
| // | ||
| const previousItem = this.currentItem; | ||
| this.currentItem = item; | ||
| for ( const child of stats.children ) { | ||
| this.resolveStats( inspector, child ); | ||
| } | ||
| this.currentItem = previousItem; | ||
| this.frameItems.set( stats.cid, item ); | ||
| } | ||
| updateGraph( inspector/*, frame*/ ) { | ||
| this.graph.addPoint( 'fps', inspector.fps ); | ||
| this.graph.update(); | ||
| } | ||
| addNotInUse( cid, item ) { | ||
| item.domElement.firstElementChild.classList.add( 'alert' ); | ||
| this.notInUse.set( cid, { | ||
| item, | ||
| time: performance.now() | ||
| } ); | ||
| this.updateNotInUse( cid ); | ||
| } | ||
| updateNotInUse( cid ) { | ||
| const { item, time } = this.notInUse.get( cid ); | ||
| const current = performance.now(); | ||
| const duration = 5; | ||
| const remaining = duration - Math.floor( ( current - time ) / 1000 ); | ||
| if ( remaining >= 0 ) { | ||
| const counter = '*'.repeat( Math.max( 0, remaining ) ); | ||
| const element = item.domElement.querySelector( '.list-item-cell .value' ); | ||
| setText( element, item.userData.name + ' (not in use) ' + counter ); | ||
| } else { | ||
| item.domElement.firstElementChild.classList.remove( 'alert' ); | ||
| item.parent.remove( item ); | ||
| this.notInUse.delete( cid ); | ||
| } | ||
| } | ||
| updateText( inspector, frame ) { | ||
| const oldFrameItems = new Map( this.frameItems ); | ||
| this.frameItems.clear(); | ||
| this.currentItem = this.frameStats; | ||
| for ( const child of frame.children ) { | ||
| this.resolveStats( inspector, child ); | ||
| } | ||
| // remove unused frame items | ||
| for ( const [ cid, item ] of oldFrameItems ) { | ||
| if ( ! this.frameItems.has( cid ) ) { | ||
| this.addNotInUse( cid, item ); | ||
| oldFrameItems.delete( cid ); | ||
| } | ||
| } | ||
| // update not in use items | ||
| for ( const cid of this.notInUse.keys() ) { | ||
| this.updateNotInUse( cid ); | ||
| } | ||
| // | ||
| setText( 'graph-fps-counter', inspector.fps.toFixed() + ' FPS' ); | ||
| // | ||
| setText( this.frameStats.data[ 1 ], frame.cpu.toFixed( 2 ) ); | ||
| setText( this.frameStats.data[ 2 ], frame.gpu.toFixed( 2 ) ); | ||
| setText( this.frameStats.data[ 3 ], frame.total.toFixed( 2 ) ); | ||
| // | ||
| setText( this.miscellaneous.data[ 1 ], frame.miscellaneous.toFixed( 2 ) ); | ||
| setText( this.miscellaneous.data[ 2 ], '-' ); | ||
| setText( this.miscellaneous.data[ 3 ], frame.miscellaneous.toFixed( 2 ) ); | ||
| // | ||
| this.currentItem = null; | ||
| } | ||
| } | ||
| export { Performance }; |
| import { Tab } from '../ui/Tab.js'; | ||
| import { List } from '../ui/List.js'; | ||
| import { Item } from '../ui/Item.js'; | ||
| import { RendererUtils, NoToneMapping, LinearSRGBColorSpace } from 'three/webgpu'; | ||
| class Viewer extends Tab { | ||
| constructor() { | ||
| super( 'Viewer' ); | ||
| const nodeList = new List( 'Viewer', 'Name' ); | ||
| nodeList.setGridStyle( '150px minmax(200px, 2fr)' ); | ||
| nodeList.domElement.style.minWidth = '600px'; | ||
| const scrollWrapper = document.createElement( 'div' ); | ||
| scrollWrapper.className = 'list-scroll-wrapper'; | ||
| scrollWrapper.appendChild( nodeList.domElement ); | ||
| this.content.appendChild( scrollWrapper ); | ||
| const nodes = new Item( 'Nodes' ); | ||
| nodeList.add( nodes ); | ||
| // | ||
| this.itemLibrary = new Map(); | ||
| this.folderLibrary = new Map(); | ||
| this.currentDataList = []; | ||
| this.nodeList = nodeList; | ||
| this.nodes = nodes; | ||
| } | ||
| getFolder( name ) { | ||
| let folder = this.folderLibrary.get( name ); | ||
| if ( folder === undefined ) { | ||
| folder = new Item( name ); | ||
| this.folderLibrary.set( name, folder ); | ||
| this.nodeList.add( folder ); | ||
| } | ||
| return folder; | ||
| } | ||
| addNodeItem( canvasData ) { | ||
| let item = this.itemLibrary.get( canvasData.id ); | ||
| if ( item === undefined ) { | ||
| const name = canvasData.name; | ||
| const domElement = canvasData.canvasTarget.domElement; | ||
| item = new Item( domElement, name ); | ||
| item.itemRow.children[ 1 ].style[ 'justify-content' ] = 'flex-start'; | ||
| this.itemLibrary.set( canvasData.id, item ); | ||
| } | ||
| return item; | ||
| } | ||
| update( renderer, canvasDataList ) { | ||
| if ( ! this.isActive ) return; | ||
| // | ||
| const previousDataList = [ ...this.currentDataList ]; | ||
| // remove old | ||
| for ( const canvasData of previousDataList ) { | ||
| if ( this.itemLibrary.has( canvasData.id ) && canvasDataList.indexOf( canvasData ) === - 1 ) { | ||
| const item = this.itemLibrary.get( canvasData.id ); | ||
| const parent = item.parent; | ||
| parent.remove( item ); | ||
| if ( this.folderLibrary.has( parent.data[ 0 ] ) && parent.children.length === 0 ) { | ||
| parent.parent.remove( parent ); | ||
| this.folderLibrary.delete( parent.data[ 0 ] ); | ||
| } | ||
| this.itemLibrary.delete( canvasData.id ); | ||
| } | ||
| } | ||
| // | ||
| const indexes = {}; | ||
| for ( const canvasData of canvasDataList ) { | ||
| const item = this.addNodeItem( canvasData ); | ||
| const previousCanvasTarget = renderer.getCanvasTarget(); | ||
| const path = canvasData.path; | ||
| if ( path ) { | ||
| const folder = this.getFolder( path ); | ||
| if ( indexes[ path ] === undefined ) { | ||
| indexes[ path ] = 0; | ||
| } | ||
| if ( folder.parent === null || item.parent !== folder || folder.children.indexOf( item ) !== indexes[ path ] ) { | ||
| folder.add( item ); | ||
| } | ||
| indexes[ path ] ++; | ||
| } else { | ||
| if ( ! item.parent ) { | ||
| this.nodes.add( item ); | ||
| } | ||
| } | ||
| this.currentDataList = canvasDataList; | ||
| // | ||
| const state = RendererUtils.resetRendererState( renderer ); | ||
| renderer.toneMapping = NoToneMapping; | ||
| renderer.outputColorSpace = LinearSRGBColorSpace; | ||
| renderer.setCanvasTarget( canvasData.canvasTarget ); | ||
| canvasData.quad.render( renderer ); | ||
| renderer.setCanvasTarget( previousCanvasTarget ); | ||
| RendererUtils.restoreRendererState( renderer, state ); | ||
| } | ||
| } | ||
| } | ||
| export { Viewer }; |
| export class Graph { | ||
| constructor( maxPoints = 512 ) { | ||
| this.maxPoints = maxPoints; | ||
| this.lines = {}; | ||
| this.limit = 0; | ||
| this.limitIndex = 0; | ||
| this.domElement = document.createElementNS( 'http://www.w3.org/2000/svg', 'svg' ); | ||
| this.domElement.setAttribute( 'class', 'graph-svg' ); | ||
| } | ||
| addLine( id, color ) { | ||
| const path = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' ); | ||
| path.setAttribute( 'class', 'graph-path' ); | ||
| path.style.stroke = `var(${color})`; | ||
| path.style.fill = `var(${color})`; | ||
| this.domElement.appendChild( path ); | ||
| this.lines[ id ] = { path, color, points: [] }; | ||
| } | ||
| addPoint( lineId, value ) { | ||
| const line = this.lines[ lineId ]; | ||
| if ( ! line ) return; | ||
| line.points.push( value ); | ||
| if ( line.points.length > this.maxPoints ) { | ||
| line.points.shift(); | ||
| } | ||
| if ( value > this.limit ) { | ||
| this.limit = value; | ||
| this.limitIndex = 0; | ||
| } | ||
| } | ||
| resetLimit() { | ||
| this.limit = 0; | ||
| this.limitIndex = 0; | ||
| } | ||
| update() { | ||
| const svgWidth = this.domElement.clientWidth; | ||
| const svgHeight = this.domElement.clientHeight; | ||
| if ( svgWidth === 0 ) return; | ||
| const pointStep = svgWidth / ( this.maxPoints - 1 ); | ||
| for ( const id in this.lines ) { | ||
| const line = this.lines[ id ]; | ||
| let pathString = `M 0,${ svgHeight }`; | ||
| for ( let i = 0; i < line.points.length; i ++ ) { | ||
| const x = i * pointStep; | ||
| const y = svgHeight - ( line.points[ i ] / this.limit ) * svgHeight; | ||
| pathString += ` L ${ x },${ y }`; | ||
| } | ||
| pathString += ` L ${( line.points.length - 1 ) * pointStep},${ svgHeight } Z`; | ||
| const offset = svgWidth - ( ( line.points.length - 1 ) * pointStep ); | ||
| line.path.setAttribute( 'transform', `translate(${ offset }, 0)` ); | ||
| line.path.setAttribute( 'd', pathString ); | ||
| } | ||
| // | ||
| if ( this.limitIndex ++ > this.maxPoints ) { | ||
| this.resetLimit(); | ||
| } | ||
| } | ||
| } |
| export class Item { | ||
| constructor( ...data ) { | ||
| this.children = []; | ||
| this.isOpen = true; | ||
| this.childrenContainer = null; | ||
| this.parent = null; | ||
| this.domElement = document.createElement( 'div' ); | ||
| this.domElement.className = 'list-item-wrapper'; | ||
| this.itemRow = document.createElement( 'div' ); | ||
| this.itemRow.className = 'list-item-row'; | ||
| this.userData = {}; | ||
| this.data = data; | ||
| this.data.forEach( ( cellData ) => { | ||
| const cell = document.createElement( 'div' ); | ||
| cell.className = 'list-item-cell'; | ||
| if ( cellData instanceof HTMLElement ) { | ||
| cell.appendChild( cellData ); | ||
| } else { | ||
| cell.append( String( cellData ) ); | ||
| } | ||
| this.itemRow.appendChild( cell ); | ||
| } ); | ||
| this.domElement.appendChild( this.itemRow ); | ||
| // Bindings | ||
| this.onItemClick = this.onItemClick.bind( this ); | ||
| } | ||
| onItemClick( e ) { | ||
| if ( e.target.closest( 'button, a, input, label' ) ) return; | ||
| this.toggle(); | ||
| } | ||
| add( item, index = this.children.length ) { | ||
| if ( item.parent !== null ) { | ||
| item.parent.remove( item ); | ||
| } | ||
| item.parent = this; | ||
| this.children.splice( index, 0, item ); | ||
| this.itemRow.classList.add( 'collapsible' ); | ||
| if ( ! this.childrenContainer ) { | ||
| this.childrenContainer = document.createElement( 'div' ); | ||
| this.childrenContainer.className = 'list-children-container'; | ||
| this.childrenContainer.classList.toggle( 'closed', ! this.isOpen ); | ||
| this.domElement.appendChild( this.childrenContainer ); | ||
| this.itemRow.addEventListener( 'click', this.onItemClick ); | ||
| } | ||
| this.childrenContainer.insertBefore( | ||
| item.domElement, | ||
| this.childrenContainer.children[ index ] || null | ||
| ); | ||
| this.updateToggler(); | ||
| return this; | ||
| } | ||
| remove( item ) { | ||
| const index = this.children.indexOf( item ); | ||
| if ( index !== - 1 ) { | ||
| this.children.splice( index, 1 ); | ||
| this.childrenContainer.removeChild( item.domElement ); | ||
| item.parent = null; | ||
| if ( this.children.length === 0 ) { | ||
| this.itemRow.classList.remove( 'collapsible' ); | ||
| this.itemRow.removeEventListener( 'click', this.onItemClick ); | ||
| this.childrenContainer.remove(); | ||
| this.childrenContainer = null; | ||
| } | ||
| this.updateToggler(); | ||
| } | ||
| return this; | ||
| } | ||
| updateToggler() { | ||
| const firstCell = this.itemRow.querySelector( '.list-item-cell:first-child' ); | ||
| let toggler = this.itemRow.querySelector( '.item-toggler' ); | ||
| if ( this.children.length > 0 ) { | ||
| if ( ! toggler ) { | ||
| toggler = document.createElement( 'span' ); | ||
| toggler.className = 'item-toggler'; | ||
| firstCell.prepend( toggler ); | ||
| } | ||
| if ( this.isOpen ) { | ||
| this.itemRow.classList.add( 'open' ); | ||
| } | ||
| } else if ( toggler ) { | ||
| toggler.remove(); | ||
| } | ||
| } | ||
| toggle() { | ||
| this.isOpen = ! this.isOpen; | ||
| this.itemRow.classList.toggle( 'open', this.isOpen ); | ||
| if ( this.childrenContainer ) { | ||
| this.childrenContainer.classList.toggle( 'closed', ! this.isOpen ); | ||
| } | ||
| return this; | ||
| } | ||
| close() { | ||
| if ( this.isOpen ) { | ||
| this.toggle(); | ||
| } | ||
| return this; | ||
| } | ||
| } |
| export class List { | ||
| constructor( ...headers ) { | ||
| this.headers = headers; | ||
| this.children = []; | ||
| this.domElement = document.createElement( 'div' ); | ||
| this.domElement.className = 'list-container'; | ||
| this.domElement.style.padding = '10px'; | ||
| this.id = `list-${Math.random().toString( 36 ).substr( 2, 9 )}`; | ||
| this.domElement.dataset.listId = this.id; | ||
| this.gridStyleElement = document.createElement( 'style' ); | ||
| this.domElement.appendChild( this.gridStyleElement ); | ||
| const headerRow = document.createElement( 'div' ); | ||
| headerRow.className = 'list-header'; | ||
| this.headers.forEach( headerText => { | ||
| const headerCell = document.createElement( 'div' ); | ||
| headerCell.className = 'list-header-cell'; | ||
| headerCell.textContent = headerText; | ||
| headerRow.appendChild( headerCell ); | ||
| } ); | ||
| this.domElement.appendChild( headerRow ); | ||
| } | ||
| setGridStyle( gridTemplate ) { | ||
| this.gridStyleElement.textContent = ` | ||
| [data-list-id="${this.id}"] > .list-header, | ||
| [data-list-id="${this.id}"] .list-item-row { | ||
| grid-template-columns: ${gridTemplate}; | ||
| } | ||
| `; | ||
| } | ||
| add( item ) { | ||
| if ( item.parent !== null ) { | ||
| item.parent.remove( item ); | ||
| } | ||
| item.domElement.classList.add( 'header-wrapper', 'section-start' ); | ||
| item.parent = this; | ||
| this.children.push( item ); | ||
| this.domElement.appendChild( item.domElement ); | ||
| } | ||
| remove( item ) { | ||
| const index = this.children.indexOf( item ); | ||
| if ( index !== - 1 ) { | ||
| this.children.splice( index, 1 ); | ||
| this.domElement.removeChild( item.domElement ); | ||
| item.parent = null; | ||
| } | ||
| return this; | ||
| } | ||
| } |
| import { Style } from './Style.js'; | ||
| export class Profiler { | ||
| constructor() { | ||
| this.tabs = {}; | ||
| this.activeTabId = null; | ||
| this.isResizing = false; | ||
| this.lastHeight = 350; | ||
| Style.init(); | ||
| this.setupShell(); | ||
| this.setupResizing(); | ||
| } | ||
| setupShell() { | ||
| this.domElement = document.createElement( 'div' ); | ||
| this.domElement.id = 'profiler-shell'; | ||
| this.toggleButton = document.createElement( 'button' ); | ||
| this.toggleButton.id = 'profiler-toggle'; | ||
| this.toggleButton.innerHTML = ` | ||
| <span id="toggle-text"> | ||
| <span id="fps-counter">-</span> | ||
| <span class="fps-label">FPS</span> | ||
| </span> | ||
| <!-- <span class="toggle-separator"></span> --> | ||
| <span id="toggle-icon"> | ||
| <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-device-ipad-horizontal-search"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M11.5 20h-6.5a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v5.5" /><path d="M9 17h2" /><path d="M18 18m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0" /><path d="M20.2 20.2l1.8 1.8" /></svg> | ||
| </span> | ||
| `; | ||
| this.toggleButton.onclick = () => this.togglePanel(); | ||
| this.panel = document.createElement( 'div' ); | ||
| this.panel.id = 'profiler-panel'; | ||
| const header = document.createElement( 'div' ); | ||
| header.className = 'profiler-header'; | ||
| this.tabsContainer = document.createElement( 'div' ); | ||
| this.tabsContainer.className = 'profiler-tabs'; | ||
| const controls = document.createElement( 'div' ); | ||
| controls.className = 'profiler-controls'; | ||
| this.maximizeBtn = document.createElement( 'button' ); | ||
| this.maximizeBtn.id = 'maximize-btn'; | ||
| this.maximizeBtn.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/></svg>'; | ||
| this.maximizeBtn.onclick = () => this.toggleMaximize(); | ||
| const hideBtn = document.createElement( 'button' ); | ||
| hideBtn.id = 'hide-panel-btn'; | ||
| hideBtn.textContent = '-'; | ||
| hideBtn.onclick = () => this.togglePanel(); | ||
| controls.append( this.maximizeBtn, hideBtn ); | ||
| header.append( this.tabsContainer, controls ); | ||
| this.contentWrapper = document.createElement( 'div' ); | ||
| this.contentWrapper.className = 'profiler-content-wrapper'; | ||
| const resizer = document.createElement( 'div' ); | ||
| resizer.className = 'panel-resizer'; | ||
| this.panel.append( resizer, header, this.contentWrapper ); | ||
| this.domElement.append( this.toggleButton, this.panel ); | ||
| } | ||
| setupResizing() { | ||
| const resizer = this.panel.querySelector( '.panel-resizer' ); | ||
| const onStart = ( e ) => { | ||
| this.isResizing = true; | ||
| this.panel.classList.add( 'resizing' ); | ||
| const startY = e.clientY || e.touches[ 0 ].clientY; | ||
| const startHeight = this.panel.offsetHeight; | ||
| const onMove = ( moveEvent ) => { | ||
| if ( ! this.isResizing ) return; | ||
| moveEvent.preventDefault(); | ||
| const currentY = moveEvent.clientY || moveEvent.touches[ 0 ].clientY; | ||
| const newHeight = startHeight - ( currentY - startY ); | ||
| if ( newHeight > 100 && newHeight < window.innerHeight - 50 ) { | ||
| this.panel.style.height = `${newHeight}px`; | ||
| } | ||
| }; | ||
| const onEnd = () => { | ||
| this.isResizing = false; | ||
| this.panel.classList.remove( 'resizing' ); | ||
| document.removeEventListener( 'mousemove', onMove ); | ||
| document.removeEventListener( 'mouseup', onEnd ); | ||
| document.removeEventListener( 'touchmove', onMove ); | ||
| document.removeEventListener( 'touchend', onEnd ); | ||
| if ( ! this.panel.classList.contains( 'maximized' ) ) { | ||
| this.lastHeight = this.panel.offsetHeight; | ||
| } | ||
| }; | ||
| document.addEventListener( 'mousemove', onMove ); | ||
| document.addEventListener( 'mouseup', onEnd ); | ||
| document.addEventListener( 'touchmove', onMove, { passive: false } ); | ||
| document.addEventListener( 'touchend', onEnd ); | ||
| }; | ||
| resizer.addEventListener( 'mousedown', onStart ); | ||
| resizer.addEventListener( 'touchstart', onStart ); | ||
| } | ||
| toggleMaximize() { | ||
| if ( this.panel.classList.contains( 'maximized' ) ) { | ||
| this.panel.classList.remove( 'maximized' ); | ||
| this.panel.style.height = `${ this.lastHeight }px`; | ||
| this.maximizeBtn.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/></svg>'; | ||
| } else { | ||
| this.lastHeight = this.panel.offsetHeight; | ||
| this.panel.classList.add( 'maximized' ); | ||
| this.panel.style.height = '100vh'; | ||
| this.maximizeBtn.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="8" y="8" width="12" height="12" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg>'; | ||
| } | ||
| } | ||
| addTab( tab ) { | ||
| this.tabs[ tab.id ] = tab; | ||
| tab.button.onclick = () => this.setActiveTab( tab.id ); | ||
| this.tabsContainer.appendChild( tab.button ); | ||
| this.contentWrapper.appendChild( tab.content ); | ||
| } | ||
| setActiveTab( id ) { | ||
| if ( this.activeTabId ) this.tabs[ this.activeTabId ].setActive( false ); | ||
| this.activeTabId = id; | ||
| this.tabs[ id ].setActive( true ); | ||
| } | ||
| togglePanel() { | ||
| this.panel.classList.toggle( 'visible' ); | ||
| this.toggleButton.classList.toggle( 'hidden' ); | ||
| } | ||
| } |
| export class Style { | ||
| static init() { | ||
| if ( document.getElementById( 'profiler-styles' ) ) return; | ||
| const css = ` | ||
| :root { | ||
| --profiler-bg: #1e1e24f5; | ||
| --profiler-header-bg: #2a2a33aa; | ||
| --profiler-header: #2a2a33; | ||
| --profiler-border: #4a4a5a; | ||
| --text-primary: #e0e0e0; | ||
| --text-secondary: #9a9aab; | ||
| --accent-color: #00aaff; | ||
| --color-green: #4caf50; | ||
| --color-yellow: #ffc107; | ||
| --color-red: #f44336; | ||
| --font-family: 'Inter', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | ||
| --font-mono: 'Fira Code', 'Courier New', Courier, monospace; | ||
| } | ||
| @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600&family=Fira+Code&display=swap'); | ||
| #profiler-panel *, #profiler-toggle * { | ||
| text-transform: initial; | ||
| line-height: normal; | ||
| box-sizing: border-box; | ||
| -webkit-font-smoothing: antialiased; | ||
| -moz-osx-font-smoothing: grayscale; | ||
| } | ||
| #profiler-toggle { | ||
| position: fixed; | ||
| top: 15px; | ||
| right: 15px; | ||
| background-color: rgba(30, 30, 36, 0.85); | ||
| border: 1px solid #4a4a5a54; | ||
| border-radius: 6px 12px 12px 6px; | ||
| color: var(--text-primary); | ||
| cursor: pointer; | ||
| z-index: 1001; | ||
| transition: all 0.2s ease-in-out; | ||
| font-size: 14px; | ||
| backdrop-filter: blur(8px); | ||
| box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3); | ||
| display: flex; | ||
| align-items: stretch; | ||
| padding: 0; | ||
| overflow: hidden; | ||
| font-family: var(--font-family); | ||
| } | ||
| #profiler-toggle:hover { | ||
| border-color: var(--accent-color); | ||
| } | ||
| #profiler-toggle.hidden { | ||
| opacity: 0; | ||
| pointer-events: none; | ||
| } | ||
| #toggle-icon { | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
| width: 40px; | ||
| font-size: 20px; | ||
| transition: background-color 0.2s; | ||
| } | ||
| #profiler-toggle:hover #toggle-icon { | ||
| background-color: rgba(255, 255, 255, 0.05); | ||
| } | ||
| .toggle-separator { | ||
| width: 1px; | ||
| background-color: var(--profiler-border); | ||
| } | ||
| #toggle-text { | ||
| display: flex; | ||
| align-items: baseline; | ||
| padding: 8px 14px; | ||
| min-width: 80px; | ||
| justify-content: right; | ||
| } | ||
| #toggle-text .fps-label { | ||
| font-size: 0.7em; | ||
| margin-left: 10px; | ||
| color: #999; | ||
| } | ||
| #profiler-panel { | ||
| position: fixed; | ||
| z-index: 1001 !important; | ||
| bottom: 0; | ||
| left: 0; | ||
| right: 0; | ||
| height: 350px; | ||
| background-color: var(--profiler-bg); | ||
| backdrop-filter: blur(8px); | ||
| border-top: 2px solid var(--profiler-border); | ||
| color: var(--text-primary); | ||
| display: flex; | ||
| flex-direction: column; | ||
| z-index: 1000; | ||
| /*box-shadow: 0 -5px 25px rgba(0, 0, 0, 0.5);*/ | ||
| transform: translateY(100%); | ||
| transition: transform 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94), height 0.3s ease-out; | ||
| font-family: var(--font-mono); | ||
| } | ||
| #profiler-panel.resizing { | ||
| transition: none; | ||
| } | ||
| #profiler-panel.visible { | ||
| transform: translateY(0); | ||
| } | ||
| #profiler-panel.maximized { | ||
| height: 100vh; | ||
| } | ||
| .panel-resizer { | ||
| position: absolute; | ||
| top: -2px; | ||
| left: 0; | ||
| width: 100%; | ||
| height: 5px; | ||
| cursor: ns-resize; | ||
| z-index: 1001; | ||
| } | ||
| .profiler-header { | ||
| display: flex; | ||
| background-color: var(--profiler-header-bg); | ||
| border-bottom: 1px solid var(--profiler-border); | ||
| flex-shrink: 0; | ||
| justify-content: space-between; | ||
| align-items: stretch; | ||
| overflow-x: auto; | ||
| overflow-y: hidden; | ||
| width: calc(100% - 89px); | ||
| height: 38px; | ||
| } | ||
| .profiler-tabs { | ||
| display: flex; | ||
| } | ||
| .profiler-controls { | ||
| display: flex; | ||
| position: absolute; | ||
| right: 0; | ||
| top: 0; | ||
| height: 38px; | ||
| background: var(--profiler-header-bg); | ||
| border-bottom: 1px solid var(--profiler-border); | ||
| } | ||
| .tab-btn { | ||
| background: transparent; | ||
| border: none; | ||
| /*border-right: 1px solid var(--profiler-border);*/ | ||
| color: var(--text-secondary); | ||
| padding: 8px 18px; | ||
| cursor: pointer; | ||
| display: flex; | ||
| align-items: center; | ||
| font-family: var(--font-family); | ||
| font-weight: 600; | ||
| font-size: 14px; | ||
| } | ||
| .tab-btn.active { | ||
| border-bottom: 2px solid var(--accent-color); | ||
| color: white; | ||
| } | ||
| #maximize-btn, | ||
| #hide-panel-btn { | ||
| background: transparent; | ||
| border: none; | ||
| border-left: 1px solid var(--profiler-border); | ||
| color: var(--text-secondary); | ||
| width: 45px; | ||
| cursor: pointer; | ||
| transition: all 0.2s; | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
| } | ||
| #maximize-btn:hover, | ||
| #hide-panel-btn:hover { | ||
| background-color: rgba(255, 255, 255, 0.1); | ||
| color: var(--text-primary); | ||
| } | ||
| .profiler-content-wrapper { | ||
| flex-grow: 1; | ||
| overflow: hidden; | ||
| position: relative; | ||
| } | ||
| .profiler-content { | ||
| position: absolute; | ||
| top: 0; | ||
| left: 0; | ||
| width: 100%; | ||
| height: 100%; | ||
| overflow-y: auto; | ||
| font-size: 13px; | ||
| visibility: hidden; | ||
| opacity: 0; | ||
| transition: opacity 0.2s, visibility 0.2s; | ||
| box-sizing: border-box; | ||
| display: flex; | ||
| flex-direction: column; | ||
| } | ||
| .profiler-content.active { | ||
| visibility: visible; | ||
| opacity: 1; | ||
| } | ||
| .profiler-content { | ||
| overflow: auto; /* make sure scrollbars can appear */ | ||
| } | ||
| .profiler-content::-webkit-scrollbar { | ||
| width: 8px; | ||
| height: 8px; | ||
| } | ||
| .profiler-content::-webkit-scrollbar-track { | ||
| background: transparent; | ||
| } | ||
| .profiler-content::-webkit-scrollbar-thumb { | ||
| background-color: rgba(0, 0, 0, 0.25); | ||
| border-radius: 10px; | ||
| transition: background 0.3s ease; | ||
| } | ||
| .profiler-content::-webkit-scrollbar-thumb:hover { | ||
| background-color: rgba(0, 0, 0, 0.4); | ||
| } | ||
| .profiler-content::-webkit-scrollbar-corner { | ||
| background: transparent; | ||
| } | ||
| .profiler-content { | ||
| scrollbar-width: thin; /* "auto" | "thin" */ | ||
| scrollbar-color: rgba(0, 0, 0, 0.25) transparent; | ||
| } | ||
| .list-item-row { | ||
| display: grid; | ||
| align-items: center; | ||
| padding: 4px 8px; | ||
| border-radius: 3px; | ||
| transition: background-color 0.2s; | ||
| gap: 10px; | ||
| border-bottom: none; | ||
| } | ||
| .list-item-wrapper { | ||
| margin-top: 2px; | ||
| margin-bottom: 2px; | ||
| } | ||
| .list-item-wrapper:first-child { | ||
| /*margin-top: 0;*/ | ||
| } | ||
| .list-item-wrapper:not(.header-wrapper):nth-child(odd) > .list-item-row { | ||
| background-color: rgba(0,0,0,0.1); | ||
| } | ||
| .list-item-wrapper.header-wrapper>.list-item-row { | ||
| color: var(--accent-color); | ||
| background-color: rgba(0, 170, 255, 0.1); | ||
| } | ||
| .list-item-wrapper.header-wrapper>.list-item-row>.list-item-cell:first-child { | ||
| font-weight: 600; | ||
| } | ||
| .list-item-row.collapsible, | ||
| .list-item-row.actionable { | ||
| cursor: pointer; | ||
| } | ||
| .list-item-row.collapsible { | ||
| background-color: rgba(0, 170, 255, 0.15) !important; | ||
| } | ||
| .list-item-row.collapsible.alert, | ||
| .list-item-row.alert { | ||
| background-color: rgba(244, 67, 54, 0.1) !important; | ||
| } | ||
| @media (hover: hover) { | ||
| .list-item-row:hover:not(.collapsible):not(.no-hover), | ||
| .list-item-row:hover:not(.no-hover), | ||
| .list-item-row.actionable:hover, | ||
| .list-item-row.collapsible.actionable:hover { | ||
| background-color: rgba(255, 255, 255, 0.05) !important; | ||
| } | ||
| .list-item-row.collapsible:hover { | ||
| background-color: rgba(0, 170, 255, 0.25) !important; | ||
| } | ||
| } | ||
| .list-item-cell { | ||
| white-space: pre; | ||
| display: flex; | ||
| align-items: center; | ||
| } | ||
| .list-item-cell:not(:first-child) { | ||
| justify-content: flex-end; | ||
| font-weight: 600; | ||
| } | ||
| .list-header { | ||
| display: grid; | ||
| align-items: center; | ||
| padding: 4px 8px; | ||
| font-weight: 600; | ||
| color: var(--text-secondary); | ||
| padding-bottom: 6px; | ||
| border-bottom: 1px solid var(--profiler-border); | ||
| margin-bottom: 5px; | ||
| gap: 10px; | ||
| } | ||
| .list-item-wrapper.section-start { | ||
| margin-top: 5px; | ||
| margin-bottom: 5px; | ||
| } | ||
| .list-header .list-header-cell:not(:first-child) { | ||
| text-align: right; | ||
| } | ||
| .list-children-container { | ||
| padding-left: 1.5em; | ||
| overflow: hidden; | ||
| transition: max-height 0.1s ease-out; | ||
| margin-top: 2px; | ||
| } | ||
| .list-children-container.closed { | ||
| max-height: 0; | ||
| } | ||
| .item-toggler { | ||
| display: inline-block; | ||
| margin-right: 0.8em; | ||
| text-align: left; | ||
| } | ||
| .list-item-row.open .item-toggler::before { | ||
| content: '-'; | ||
| } | ||
| .list-item-row:not(.open) .item-toggler::before { | ||
| content: '+'; | ||
| } | ||
| .list-item-cell .value.good { | ||
| color: var(--color-green); | ||
| } | ||
| .list-item-cell .value.warn { | ||
| color: var(--color-yellow); | ||
| } | ||
| .list-item-cell .value.bad { | ||
| color: var(--color-red); | ||
| } | ||
| .list-scroll-wrapper { | ||
| overflow-x: auto; | ||
| width: 100%; | ||
| } | ||
| .list-container.parameters .list-item-row:not(.collapsible) { | ||
| height: 31px; | ||
| } | ||
| .graph-container { | ||
| width: 100%; | ||
| box-sizing: border-box; | ||
| padding: 8px 0; | ||
| position: relative; | ||
| } | ||
| .graph-svg { | ||
| width: 100%; | ||
| height: 80px; | ||
| background-color: var(--profiler-header); | ||
| border: 1px solid var(--profiler-border); | ||
| border-radius: 4px; | ||
| } | ||
| .graph-path { | ||
| stroke-width: 2; | ||
| fill-opacity: 0.4; | ||
| } | ||
| .console-header { | ||
| padding: 10px; | ||
| border-bottom: 1px solid var(--profiler-border); | ||
| display: flex; | ||
| gap: 20px; | ||
| flex-shrink: 0; | ||
| align-items: center; | ||
| justify-content: space-between; | ||
| } | ||
| .console-filters-group { | ||
| display: flex; | ||
| gap: 20px; | ||
| } | ||
| .console-filter-input { | ||
| background-color: var(--profiler-bg); | ||
| border: 1px solid var(--profiler-border); | ||
| color: var(--text-primary); | ||
| border-radius: 4px; | ||
| padding: 4px 8px; | ||
| font-family: var(--font-mono); | ||
| flex-grow: 1; | ||
| max-width: 300px; | ||
| border-radius: 15px; | ||
| } | ||
| #console-log { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 4px; | ||
| padding: 10px; | ||
| overflow-y: auto; | ||
| flex-grow: 1; | ||
| } | ||
| .log-message { | ||
| padding: 2px 5px; | ||
| white-space: pre-wrap; | ||
| word-break: break-all; | ||
| border-radius: 3px; | ||
| line-height: 1.5 !important; | ||
| } | ||
| .log-message.hidden { | ||
| display: none; | ||
| } | ||
| .log-message.info { | ||
| color: var(--text-primary); | ||
| } | ||
| .log-message.warn { | ||
| color: var(--color-yellow); | ||
| } | ||
| .log-message.error { | ||
| color: #f9dedc; | ||
| background-color: rgba(244, 67, 54, 0.1); | ||
| } | ||
| .log-prefix { | ||
| color: var(--text-secondary); | ||
| margin-right: 8px; | ||
| } | ||
| .log-code { | ||
| background-color: rgba(255, 255, 255, 0.1); | ||
| border-radius: 3px; | ||
| padding: 1px 4px; | ||
| } | ||
| .thumbnail-container { | ||
| display: flex; | ||
| align-items: center; | ||
| } | ||
| .thumbnail-svg { | ||
| width: 40px; | ||
| height: 22.5px; | ||
| flex-shrink: 0; | ||
| margin-right: 8px; | ||
| } | ||
| .param-control { | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: flex-end; | ||
| gap: 10px; | ||
| width: 100%; | ||
| } | ||
| .param-control input, | ||
| .param-control select, | ||
| .param-control button { | ||
| background-color: var(--profiler-bg); | ||
| border: 1px solid var(--profiler-border); | ||
| color: var(--text-primary); | ||
| border-radius: 4px; | ||
| padding: 4px 6px; | ||
| padding-bottom: 2px; | ||
| font-family: var(--font-mono); | ||
| width: 100%; | ||
| box-sizing: border-box; | ||
| } | ||
| .param-control select { | ||
| padding-top: 3px; | ||
| padding-bottom: 1px; | ||
| } | ||
| .param-control input[type="number"] { | ||
| cursor: ns-resize; | ||
| } | ||
| .param-control input[type="color"] { | ||
| padding: 2px; | ||
| } | ||
| .param-control button { | ||
| cursor: pointer; | ||
| transition: background-color 0.2s; | ||
| } | ||
| .param-control button:hover { | ||
| background-color: var(--profiler-header); | ||
| } | ||
| .param-control-vector { | ||
| display: flex; | ||
| gap: 5px; | ||
| } | ||
| .custom-checkbox { | ||
| display: inline-flex; | ||
| align-items: center; | ||
| cursor: pointer; | ||
| gap: 8px; | ||
| } | ||
| .custom-checkbox input { | ||
| display: none; | ||
| } | ||
| .custom-checkbox .checkmark { | ||
| width: 14px; | ||
| height: 14px; | ||
| border: 1px solid var(--profiler-border); | ||
| border-radius: 3px; | ||
| display: inline-flex; | ||
| justify-content: center; | ||
| align-items: center; | ||
| transition: background-color 0.2s, border-color 0.2s; | ||
| } | ||
| .custom-checkbox .checkmark::after { | ||
| content: ''; | ||
| width: 8px; | ||
| height: 8px; | ||
| background-color: var(--accent-color); | ||
| border-radius: 1px; | ||
| display: block; | ||
| transform: scale(0); | ||
| transition: transform 0.2s; | ||
| } | ||
| .custom-checkbox input:checked+.checkmark { | ||
| border-color: var(--accent-color); | ||
| } | ||
| .custom-checkbox input:checked+.checkmark::after { | ||
| transform: scale(1); | ||
| } | ||
| .param-control input[type="range"] { | ||
| -webkit-appearance: none; | ||
| appearance: none; | ||
| width: 100%; | ||
| height: 16px; | ||
| background: var(--profiler-header); | ||
| border-radius: 5px; | ||
| border: 1px solid var(--profiler-border); | ||
| outline: none; | ||
| padding: 0px; | ||
| padding-top: 8px; | ||
| } | ||
| .param-control input[type="range"]::-webkit-slider-thumb { | ||
| -webkit-appearance: none; | ||
| appearance: none; | ||
| width: 18px; | ||
| height: 18px; | ||
| background: var(--profiler-bg); | ||
| border: 1px solid var(--accent-color); | ||
| border-radius: 3px; | ||
| cursor: pointer; | ||
| margin-top: -8px; | ||
| } | ||
| .param-control input[type="range"]::-moz-range-thumb { | ||
| width: 18px; | ||
| height: 18px; | ||
| background: var(--profiler-bg); | ||
| border: 2px solid var(--accent-color); | ||
| border-radius: 3px; | ||
| cursor: pointer; | ||
| } | ||
| .param-control input[type="range"]::-moz-range-track { | ||
| width: 100%; | ||
| height: 16px; | ||
| background: var(--profiler-header); | ||
| border-radius: 5px; | ||
| border: 1px solid var(--profiler-border); | ||
| } | ||
| @media screen and (max-width: 768px) and (orientation: portrait) { | ||
| .console-filter-input { | ||
| max-width: 100px; | ||
| } | ||
| } | ||
| `; | ||
| const styleElement = document.createElement( 'style' ); | ||
| styleElement.id = 'profiler-styles'; | ||
| styleElement.textContent = css; | ||
| document.head.appendChild( styleElement ); | ||
| } | ||
| } |
| export class Tab { | ||
| constructor( title ) { | ||
| this.id = title.toLowerCase(); | ||
| this.button = document.createElement( 'button' ); | ||
| this.button.className = 'tab-btn'; | ||
| this.button.textContent = title; | ||
| this.content = document.createElement( 'div' ); | ||
| this.content.id = `${this.id}-content`; | ||
| this.content.className = 'profiler-content'; | ||
| this.isActive = false; | ||
| this.isVisible = true; | ||
| } | ||
| setActive( isActive ) { | ||
| this.button.classList.toggle( 'active', isActive ); | ||
| this.content.classList.toggle( 'active', isActive ); | ||
| this.isActive = isActive; | ||
| } | ||
| show() { | ||
| this.content.style.display = ''; | ||
| this.button.style.display = ''; | ||
| this.isVisible = true; | ||
| } | ||
| hide() { | ||
| this.content.style.display = 'none'; | ||
| this.button.style.display = 'none'; | ||
| this.isVisible = false; | ||
| } | ||
| } |
| export function createValueSpan( id = null ) { | ||
| const span = document.createElement( 'span' ); | ||
| span.className = 'value'; | ||
| if ( id !== null ) span.id = id; | ||
| return span; | ||
| } | ||
| export function setText( element, text ) { | ||
| const el = element instanceof HTMLElement ? element : document.getElementById( element ); | ||
| if ( el && el.textContent !== text ) { | ||
| el.textContent = text; | ||
| } | ||
| } | ||
| export function getText( element ) { | ||
| const el = element instanceof HTMLElement ? element : document.getElementById( element ); | ||
| return el ? el.textContent : null; | ||
| } | ||
| export function splitPath( fullPath ) { | ||
| const lastSlash = fullPath.lastIndexOf( '/' ); | ||
| if ( lastSlash === - 1 ) { | ||
| return { | ||
| path: '', | ||
| name: fullPath.trim() | ||
| }; | ||
| } | ||
| const path = fullPath.substring( 0, lastSlash ).trim(); | ||
| const name = fullPath.substring( lastSlash + 1 ).trim(); | ||
| return { path, name }; | ||
| } | ||
| export function splitCamelCase( str ) { | ||
| return str.replace( /([a-z0-9])([A-Z])/g, '$1 $2' ).trim(); | ||
| } |
| import { EventDispatcher } from 'three'; | ||
| class Value extends EventDispatcher { | ||
| constructor() { | ||
| super(); | ||
| this.domElement = document.createElement( 'div' ); | ||
| this.domElement.className = 'param-control'; | ||
| this._onChangeFunction = null; | ||
| this.addEventListener( 'change', ( e ) => { | ||
| // defer to avoid issues when changing multiple values in the same call stack | ||
| requestAnimationFrame( () => { | ||
| if ( this._onChangeFunction ) this._onChangeFunction( e.value ); | ||
| } ); | ||
| } ); | ||
| } | ||
| setValue( /*val*/ ) { | ||
| this.dispatchChange(); | ||
| return this; | ||
| } | ||
| getValue() { | ||
| return null; | ||
| } | ||
| dispatchChange() { | ||
| this.dispatchEvent( { type: 'change', value: this.getValue() } ); | ||
| } | ||
| onChange( callback ) { | ||
| this._onChangeFunction = callback; | ||
| return this; | ||
| } | ||
| } | ||
| class ValueNumber extends Value { | ||
| constructor( { value = 0, step = 0.1, min = - Infinity, max = Infinity } ) { | ||
| super(); | ||
| this.input = document.createElement( 'input' ); | ||
| this.input.type = 'number'; | ||
| this.input.value = value; | ||
| this.input.step = step; | ||
| this.input.min = min; | ||
| this.input.max = max; | ||
| this.input.addEventListener( 'change', this._onChangeValue.bind( this ) ); | ||
| this.domElement.appendChild( this.input ); | ||
| this.addDragHandler(); | ||
| } | ||
| _onChangeValue() { | ||
| const value = parseFloat( this.input.value ); | ||
| const min = parseFloat( this.input.min ); | ||
| const max = parseFloat( this.input.max ); | ||
| if ( value > max ) { | ||
| this.input.value = max; | ||
| } else if ( value < min ) { | ||
| this.input.value = min; | ||
| } else if ( isNaN( value ) ) { | ||
| this.input.value = min; | ||
| } | ||
| this.dispatchChange(); | ||
| } | ||
| addDragHandler() { | ||
| let isDragging = false; | ||
| let startY, startValue; | ||
| this.input.addEventListener( 'mousedown', ( e ) => { | ||
| isDragging = true; | ||
| startY = e.clientY; | ||
| startValue = parseFloat( this.input.value ); | ||
| document.body.style.cursor = 'ns-resize'; | ||
| } ); | ||
| document.addEventListener( 'mousemove', ( e ) => { | ||
| if ( isDragging ) { | ||
| const deltaY = startY - e.clientY; | ||
| const step = parseFloat( this.input.step ) || 1; | ||
| const min = parseFloat( this.input.min ); | ||
| const max = parseFloat( this.input.max ); | ||
| let stepSize = step; | ||
| if ( ! isNaN( max ) && isFinite( min ) ) { | ||
| stepSize = ( max - min ) / 100; | ||
| } | ||
| const change = deltaY * stepSize; | ||
| let newValue = startValue + change; | ||
| newValue = Math.max( min, Math.min( newValue, max ) ); | ||
| const precision = ( String( step ).split( '.' )[ 1 ] || [] ).length; | ||
| this.input.value = newValue.toFixed( precision ); | ||
| this.input.dispatchEvent( new Event( 'input' ) ); | ||
| this.dispatchChange(); | ||
| } | ||
| } ); | ||
| document.addEventListener( 'mouseup', () => { | ||
| if ( isDragging ) { | ||
| isDragging = false; | ||
| document.body.style.cursor = 'default'; | ||
| } | ||
| } ); | ||
| } | ||
| getValue() { | ||
| return parseFloat( this.input.value ); | ||
| } | ||
| } | ||
| class ValueCheckbox extends Value { | ||
| constructor( { value = false } ) { | ||
| super(); | ||
| const label = document.createElement( 'label' ); | ||
| label.className = 'custom-checkbox'; | ||
| const checkbox = document.createElement( 'input' ); | ||
| checkbox.type = 'checkbox'; | ||
| checkbox.checked = value; | ||
| this.checkbox = checkbox; | ||
| const checkmark = document.createElement( 'span' ); | ||
| checkmark.className = 'checkmark'; | ||
| label.appendChild( checkbox ); | ||
| label.appendChild( checkmark ); | ||
| this.domElement.appendChild( label ); | ||
| checkbox.addEventListener( 'change', () => { | ||
| this.dispatchChange(); | ||
| } ); | ||
| } | ||
| getValue() { | ||
| return this.checkbox.checked; | ||
| } | ||
| } | ||
| class ValueSlider extends Value { | ||
| constructor( { value = 0, min = 0, max = 1, step = 0.01 } ) { | ||
| super(); | ||
| this.slider = document.createElement( 'input' ); | ||
| this.slider.type = 'range'; | ||
| this.slider.min = min; | ||
| this.slider.max = max; | ||
| this.slider.step = step; | ||
| const numberValue = new ValueNumber( { value, min, max, step } ); | ||
| this.numberInput = numberValue.input; | ||
| this.numberInput.style.width = '60px'; | ||
| this.numberInput.style.flexShrink = '0'; | ||
| this.slider.value = value; | ||
| this.domElement.append( this.slider, this.numberInput ); | ||
| this.slider.addEventListener( 'input', () => { | ||
| this.numberInput.value = this.slider.value; | ||
| this.dispatchChange(); | ||
| } ); | ||
| numberValue.addEventListener( 'change', () => { | ||
| this.slider.value = parseFloat( this.numberInput.value ); | ||
| this.dispatchChange(); | ||
| } ); | ||
| } | ||
| setValue( val ) { | ||
| this.slider.value = val; | ||
| this.numberInput.value = val; | ||
| return super.setValue( val ); | ||
| } | ||
| getValue() { | ||
| return parseFloat( this.slider.value ); | ||
| } | ||
| step( value ) { | ||
| this.slider.step = value; | ||
| this.numberInput.step = value; | ||
| return this; | ||
| } | ||
| } | ||
| class ValueSelect extends Value { | ||
| constructor( { options = [], value = '' } ) { | ||
| super(); | ||
| const select = document.createElement( 'select' ); | ||
| const createOption = ( name, optionValue ) => { | ||
| const optionEl = document.createElement( 'option' ); | ||
| optionEl.value = name; | ||
| optionEl.textContent = name; | ||
| if ( optionValue == value ) optionEl.selected = true; | ||
| select.appendChild( optionEl ); | ||
| return optionEl; | ||
| }; | ||
| if ( Array.isArray( options ) ) { | ||
| options.forEach( opt => createOption( opt, opt ) ); | ||
| } else { | ||
| Object.entries( options ).forEach( ( [ key, value ] ) => createOption( key, value ) ); | ||
| } | ||
| this.domElement.appendChild( select ); | ||
| // | ||
| select.addEventListener( 'change', () => { | ||
| this.dispatchChange(); | ||
| } ); | ||
| this.options = options; | ||
| this.select = select; | ||
| } | ||
| getValue() { | ||
| const options = this.options; | ||
| if ( Array.isArray( options ) ) { | ||
| return options[ this.select.selectedIndex ]; | ||
| } else { | ||
| return options[ this.select.value ]; | ||
| } | ||
| } | ||
| } | ||
| class ValueColor extends Value { | ||
| constructor( { value = '#ffffff' } ) { | ||
| super(); | ||
| const colorInput = document.createElement( 'input' ); | ||
| colorInput.type = 'color'; | ||
| colorInput.value = this._getColorHex( value ); | ||
| this.colorInput = colorInput; | ||
| this._value = value; | ||
| colorInput.addEventListener( 'input', () => { | ||
| const colorValue = colorInput.value; | ||
| if ( this._value.isColor ) { | ||
| this._value.setHex( parseInt( colorValue.slice( 1 ), 16 ) ); | ||
| } else { | ||
| this._value = colorValue; | ||
| } | ||
| this.dispatchChange(); | ||
| } ); | ||
| this.domElement.appendChild( colorInput ); | ||
| } | ||
| _getColorHex( color ) { | ||
| if ( color.isColor ) { | ||
| color = color.getHex(); | ||
| } | ||
| if ( typeof color === 'number' ) { | ||
| color = `#${ color.toString( 16 ) }`; | ||
| } else if ( color[ 0 ] !== '#' ) { | ||
| color = '#' + color; | ||
| } | ||
| return color; | ||
| } | ||
| getValue() { | ||
| let value = this._value; | ||
| if ( typeof value === 'string' ) { | ||
| value = parseInt( value.slice( 1 ), 16 ); | ||
| } | ||
| return value; | ||
| } | ||
| } | ||
| class ValueButton extends Value { | ||
| constructor( { text = 'Button', value = () => {} } ) { | ||
| super(); | ||
| const button = document.createElement( 'button' ); | ||
| button.textContent = text; | ||
| button.onclick = value; | ||
| this.domElement.appendChild( button ); | ||
| } | ||
| } | ||
| export { Value, ValueNumber, ValueCheckbox, ValueSlider, ValueSelect, ValueColor, ValueButton }; |
| import { RenderTarget, Vector2, TempNode, QuadMesh, NodeMaterial, RendererUtils, MathUtils } from 'three/webgpu'; | ||
| import { clamp, normalize, reference, nodeObject, Fn, NodeUpdateType, uniform, vec4, passTexture, uv, logarithmicDepthToViewZ, viewZToPerspectiveDepth, getViewPosition, screenCoordinate, float, sub, fract, dot, vec2, rand, vec3, Loop, mul, PI, cos, sin, uint, cross, acos, sign, pow, luminance, If, max, abs, Break, sqrt, HALF_PI, div, ceil, shiftRight, convertToTexture, bool, getNormalFromDepth, interleavedGradientNoise } from 'three/tsl'; | ||
| const _quadMesh = /*@__PURE__*/ new QuadMesh(); | ||
| const _size = /*@__PURE__*/ new Vector2(); | ||
| // From Activision GTAO paper: https://www.activision.com/cdn/research/s2016_pbs_activision_occlusion.pptx | ||
| const _temporalRotations = [ 60, 300, 180, 240, 120, 0 ]; | ||
| const _spatialOffsets = [ 0, 0.5, 0.25, 0.75 ]; | ||
| let _rendererState; | ||
| /** | ||
| * Post processing node for applying Screen Space Global Illumination (SSGI) to a scene. | ||
| * | ||
| * References: | ||
| * - {@link https://github.com/cdrinmatane/SSRT3}. | ||
| * - {@link https://cdrinmatane.github.io/posts/ssaovb-code/}. | ||
| * - {@link https://cdrinmatane.github.io/cgspotlight-slides/ssilvb_slides.pdf}. | ||
| * | ||
| * The quality and performance of the effect mainly depend on `sliceCount` and `stepCount`. | ||
| * The total number of samples taken per pixel is `sliceCount` * `stepCount` * `2`. Here are some | ||
| * recommended presets depending on whether temporal filtering is used or not. | ||
| * | ||
| * With temporal filtering (recommended): | ||
| * | ||
| * - Low: `sliceCount` of `1`, `stepCount` of `12`. | ||
| * - Medium: `sliceCount` of `2`, `stepCount` of `8`. | ||
| * - High: `sliceCount` of `3`, `stepCount` of `16`. | ||
| * | ||
| * Use for a higher slice count if you notice temporal instabilities like flickering. Reduce the sample | ||
| * count then to mitigate the performance lost. | ||
| * | ||
| * Without temporal filtering: | ||
| * | ||
| * - Low: `sliceCount` of `2`, `stepCount` of `6`. | ||
| * - Medium: `sliceCount` of `3`, `stepCount` of `8`. | ||
| * - High: `sliceCount` of `4`, `stepCount` of `12`. | ||
| * | ||
| * @augments TempNode | ||
| * @three_import import { ssgi } from 'three/addons/tsl/display/SSGINode.js'; | ||
| */ | ||
| class SSGINode extends TempNode { | ||
| static get type() { | ||
| return 'SSGINode'; | ||
| } | ||
| /** | ||
| * Constructs a new SSGI node. | ||
| * | ||
| * @param {TextureNode} beautyNode - A texture node that represents the beauty or scene pass. | ||
| * @param {TextureNode} depthNode - A texture node that represents the scene's depth. | ||
| * @param {TextureNode} normalNode - A texture node that represents the scene's normals. | ||
| * @param {PerspectiveCamera} camera - The camera the scene is rendered with. | ||
| */ | ||
| constructor( beautyNode, depthNode, normalNode, camera ) { | ||
| super( 'vec4' ); | ||
| /** | ||
| * A texture node that represents the beauty or scene pass. | ||
| * | ||
| * @type {TextureNode} | ||
| */ | ||
| this.beautyNode = beautyNode; | ||
| /** | ||
| * A node that represents the scene's depth. | ||
| * | ||
| * @type {TextureNode} | ||
| */ | ||
| this.depthNode = depthNode; | ||
| /** | ||
| * A node that represents the scene's normals. If no normals are passed to the | ||
| * constructor (because MRT is not available), normals can be automatically | ||
| * reconstructed from depth values in the shader. | ||
| * | ||
| * @type {TextureNode} | ||
| */ | ||
| this.normalNode = normalNode; | ||
| /** | ||
| * The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node renders | ||
| * its effect once per frame in `updateBefore()`. | ||
| * | ||
| * @type {string} | ||
| * @default 'frame' | ||
| */ | ||
| this.updateBeforeType = NodeUpdateType.FRAME; | ||
| /** | ||
| * Number of per-pixel hemisphere slices. This has a big performance cost and should be kept as low as possible. | ||
| * Should be in the range `[1, 4]`. | ||
| * | ||
| * @type {UniformNode<uint>} | ||
| * @default 1 | ||
| */ | ||
| this.sliceCount = uniform( 1, 'uint' ); | ||
| /** | ||
| * Number of samples taken along one side of a given hemisphere slice. This has a big performance cost and should | ||
| * be kept as low as possible. Should be in the range `[1, 32]`. | ||
| * | ||
| * @type {UniformNode<uint>} | ||
| * @default 12 | ||
| */ | ||
| this.stepCount = uniform( 12, 'uint' ); | ||
| /** | ||
| * Power function applied to AO to make it appear darker/lighter. Should be in the range `[0, 4]`. | ||
| * | ||
| * @type {UniformNode<float>} | ||
| * @default 1 | ||
| */ | ||
| this.aoIntensity = uniform( 1, 'float' ); | ||
| /** | ||
| * Intensity of the indirect diffuse light. Should be in the range `[0, 100]`. | ||
| * | ||
| * @type {UniformNode<float>} | ||
| * @default 10 | ||
| */ | ||
| this.giIntensity = uniform( 10, 'float' ); | ||
| /** | ||
| * Effective sampling radius in world space. AO and GI can only have influence within that radius. | ||
| * Should be in the range `[1, 25]`. | ||
| * | ||
| * @type {UniformNode<float>} | ||
| * @default 12 | ||
| */ | ||
| this.radius = uniform( 12, 'float' ); | ||
| /** | ||
| * Makes the sample distance in screen space instead of world-space (helps having more detail up close). | ||
| * | ||
| * @type {UniformNode<bool>} | ||
| * @default false | ||
| */ | ||
| this.useScreenSpaceSampling = uniform( true, 'bool' ); | ||
| /** | ||
| * Controls samples distribution. It's an exponent applied at each step get increasing step size over the distance. | ||
| * Should be in the range `[1, 3]`. | ||
| * | ||
| * @type {UniformNode<float>} | ||
| * @default 2 | ||
| */ | ||
| this.expFactor = uniform( 2, 'float' ); | ||
| /** | ||
| * Constant thickness value of objects on the screen in world units. Allows light to pass behind surfaces past that thickness value. | ||
| * Should be in the range `[0.01, 10]`. | ||
| * | ||
| * @type {UniformNode<float>} | ||
| * @default 1 | ||
| */ | ||
| this.thickness = uniform( 1, 'float' ); | ||
| /** | ||
| * Whether to increase thickness linearly over distance or not (avoid losing detail over the distance). | ||
| * | ||
| * @type {UniformNode<bool>} | ||
| * @default false | ||
| */ | ||
| this.useLinearThickness = uniform( false, 'bool' ); | ||
| /** | ||
| * How much light backface surfaces emit. | ||
| * Should be in the range `[0, 1]`. | ||
| * | ||
| * @type {UniformNode<float>} | ||
| * @default 0 | ||
| */ | ||
| this.backfaceLighting = uniform( 0, 'float' ); | ||
| /** | ||
| * Whether to use temporal filtering or not. Setting this property to | ||
| * `true` requires the usage of `TRAANode`. This will help to reduce noise | ||
| * although it introduces typical TAA artifacts like ghosting and temporal | ||
| * instabilities. | ||
| * | ||
| * If setting this property to `false`, a manual denoise via `DenoiseNode` | ||
| * is required. | ||
| * | ||
| * @type {boolean} | ||
| * @default true | ||
| */ | ||
| this.useTemporalFiltering = true; | ||
| // private uniforms | ||
| /** | ||
| * The resolution of the effect. | ||
| * | ||
| * @type {UniformNode<vec2>} | ||
| */ | ||
| this._resolution = uniform( new Vector2() ); | ||
| /** | ||
| * Used to compute the effective step radius when viewSpaceSampling is `false`. | ||
| * | ||
| * @type {UniformNode<vec2>} | ||
| */ | ||
| this._halfProjScale = uniform( 1 ); | ||
| /** | ||
| * Temporal direction that influences the rotation angle for each slice. | ||
| * | ||
| * @type {UniformNode<float>} | ||
| */ | ||
| this._temporalDirection = uniform( 0 ); | ||
| /** | ||
| * Temporal offset added to the initial ray step. | ||
| * | ||
| * @type {UniformNode<float>} | ||
| */ | ||
| this._temporalOffset = uniform( 0 ); | ||
| /** | ||
| * Represents the projection matrix of the scene's camera. | ||
| * | ||
| * @private | ||
| * @type {UniformNode<mat4>} | ||
| */ | ||
| this._cameraProjectionMatrix = uniform( camera.projectionMatrix ); | ||
| /** | ||
| * Represents the inverse projection matrix of the scene's camera. | ||
| * | ||
| * @private | ||
| * @type {UniformNode<mat4>} | ||
| */ | ||
| this._cameraProjectionMatrixInverse = uniform( camera.projectionMatrixInverse ); | ||
| /** | ||
| * Represents the near value of the scene's camera. | ||
| * | ||
| * @private | ||
| * @type {ReferenceNode<float>} | ||
| */ | ||
| this._cameraNear = reference( 'near', 'float', camera ); | ||
| /** | ||
| * Represents the far value of the scene's camera. | ||
| * | ||
| * @private | ||
| * @type {ReferenceNode<float>} | ||
| */ | ||
| this._cameraFar = reference( 'far', 'float', camera ); | ||
| /** | ||
| * A reference to the scene's camera. | ||
| * | ||
| * @private | ||
| * @type {PerspectiveCamera} | ||
| */ | ||
| this._camera = camera; | ||
| /** | ||
| * The render target the GI is rendered into. | ||
| * | ||
| * @private | ||
| * @type {RenderTarget} | ||
| */ | ||
| this._ssgiRenderTarget = new RenderTarget( 1, 1, { depthBuffer: false } ); | ||
| this._ssgiRenderTarget.texture.name = 'SSGI'; | ||
| /** | ||
| * The material that is used to render the effect. | ||
| * | ||
| * @private | ||
| * @type {NodeMaterial} | ||
| */ | ||
| this._material = new NodeMaterial(); | ||
| this._material.name = 'SSGI'; | ||
| /** | ||
| * The result of the effect is represented as a separate texture node. | ||
| * | ||
| * @private | ||
| * @type {PassTextureNode} | ||
| */ | ||
| this._textureNode = passTexture( this, this._ssgiRenderTarget.texture ); | ||
| } | ||
| /** | ||
| * Returns the result of the effect as a texture node. | ||
| * | ||
| * @return {PassTextureNode} A texture node that represents the result of the effect. | ||
| */ | ||
| getTextureNode() { | ||
| return this._textureNode; | ||
| } | ||
| /** | ||
| * Sets the size of the effect. | ||
| * | ||
| * @param {number} width - The width of the effect. | ||
| * @param {number} height - The height of the effect. | ||
| */ | ||
| setSize( width, height ) { | ||
| this._resolution.value.set( width, height ); | ||
| this._ssgiRenderTarget.setSize( width, height ); | ||
| this._halfProjScale.value = height / ( Math.tan( this._camera.fov * MathUtils.DEG2RAD * 0.5 ) * 2 ) * 0.5; | ||
| } | ||
| /** | ||
| * This method is used to render the effect once per frame. | ||
| * | ||
| * @param {NodeFrame} frame - The current node frame. | ||
| */ | ||
| updateBefore( frame ) { | ||
| const { renderer } = frame; | ||
| _rendererState = RendererUtils.resetRendererState( renderer, _rendererState ); | ||
| // | ||
| const size = renderer.getDrawingBufferSize( _size ); | ||
| this.setSize( size.width, size.height ); | ||
| // update temporal uniforms | ||
| if ( this.useTemporalFiltering === true ) { | ||
| const frameId = frame.frameId; | ||
| this._temporalDirection.value = _temporalRotations[ frameId % 6 ] / 360; | ||
| this._temporalOffset.value = _spatialOffsets[ frameId % 4 ]; | ||
| } else { | ||
| this._temporalDirection.value = 1; | ||
| this._temporalOffset.value = 1; | ||
| } | ||
| // | ||
| _quadMesh.material = this._material; | ||
| _quadMesh.name = 'SSGI'; | ||
| // clear | ||
| renderer.setClearColor( 0x000000, 1 ); | ||
| // gi | ||
| renderer.setRenderTarget( this._ssgiRenderTarget ); | ||
| _quadMesh.render( renderer ); | ||
| // restore | ||
| RendererUtils.restoreRendererState( renderer, _rendererState ); | ||
| } | ||
| /** | ||
| * This method is used to setup the effect's TSL code. | ||
| * | ||
| * @param {NodeBuilder} builder - The current node builder. | ||
| * @return {PassTextureNode} | ||
| */ | ||
| setup( builder ) { | ||
| const uvNode = uv(); | ||
| const MAX_RAY = uint( 32 ); | ||
| const globalOccludedBitfield = uint( 0 ); | ||
| const sampleDepth = ( uv ) => { | ||
| const depth = this.depthNode.sample( uv ).r; | ||
| if ( builder.renderer.logarithmicDepthBuffer === true ) { | ||
| const viewZ = logarithmicDepthToViewZ( depth, this._cameraNear, this._cameraFar ); | ||
| return viewZToPerspectiveDepth( viewZ, this._cameraNear, this._cameraFar ); | ||
| } | ||
| return depth; | ||
| }; | ||
| const sampleNormal = ( uv ) => ( this.normalNode !== null ) ? this.normalNode.sample( uv ).rgb.normalize() : getNormalFromDepth( uv, this.depthNode.value, this._cameraProjectionMatrixInverse ); | ||
| const sampleBeauty = ( uv ) => this.beautyNode.sample( uv ); | ||
| // From Activision GTAO paper: https://www.activision.com/cdn/research/s2016_pbs_activision_occlusion.pptx | ||
| const spatialOffsets = Fn( ( [ position ] ) => { | ||
| return float( 0.25 ).mul( sub( position.y, position.x ).bitAnd( 3 ) ); | ||
| } ).setLayout( { | ||
| name: 'spatialOffsets', | ||
| type: 'float', | ||
| inputs: [ | ||
| { name: 'position', type: 'vec2' } | ||
| ] | ||
| } ); | ||
| const GTAOFastAcos = Fn( ( [ value ] ) => { | ||
| const outVal = abs( value ).mul( float( - 0.156583 ) ).add( HALF_PI ); | ||
| outVal.mulAssign( sqrt( abs( value ).oneMinus() ) ); | ||
| const x = value.x.greaterThanEqual( 0 ).select( outVal.x, PI.sub( outVal.x ) ); | ||
| const y = value.y.greaterThanEqual( 0 ).select( outVal.y, PI.sub( outVal.y ) ); | ||
| return vec2( x, y ); | ||
| } ).setLayout( { | ||
| name: 'GTAOFastAcos', | ||
| type: 'vec2', | ||
| inputs: [ | ||
| { name: 'value', type: 'vec2' } | ||
| ] | ||
| } ); | ||
| const bitCount = Fn( ( [ value ] ) => { | ||
| const v = uint( value ); | ||
| v.assign( v.sub( v.shiftRight( uint( 1 ) ).bitAnd( uint( 0x55555555 ) ) ) ); | ||
| v.assign( v.bitAnd( uint( 0x33333333 ) ).add( v.shiftRight( uint( 2 ) ).bitAnd( uint( 0x33333333 ) ) ) ); | ||
| return v.add( v.shiftRight( uint( 4 ) ) ).bitAnd( uint( 0xF0F0F0F ) ).mul( uint( 0x1010101 ) ).shiftRight( uint( 24 ) ); | ||
| } ).setLayout( { | ||
| name: 'bitCount', | ||
| type: 'uint', | ||
| inputs: [ | ||
| { name: 'value', type: 'uint' } | ||
| ] | ||
| } ); | ||
| const horizonSampling = Fn( ( [ directionIsRight, RADIUS, viewPosition, slideDirTexelSize, initialRayStep, uvNode, viewDir, viewNormal, n ] ) => { | ||
| const STEP_COUNT = this.stepCount.toConst(); | ||
| const EXP_FACTOR = this.expFactor.toConst(); | ||
| const THICKNESS = this.thickness.toConst(); | ||
| const BACKFACE_LIGHTING = this.backfaceLighting.toConst(); | ||
| const stepRadius = float( 0 ); | ||
| If( this.useScreenSpaceSampling.equal( true ), () => { | ||
| stepRadius.assign( RADIUS.mul( this._resolution.x.div( 2 ) ).div( float( 16 ) ) ); // SSRT3 has a bug where stepRadius is divided by STEP_COUNT twice; fix here | ||
| } ).Else( () => { | ||
| stepRadius.assign( max( RADIUS.mul( this._halfProjScale ).div( viewPosition.z.negate() ), float( STEP_COUNT ) ) ); // Port note: viewZ is negative so a negate is required | ||
| } ); | ||
| stepRadius.divAssign( float( STEP_COUNT ).add( 1 ) ); | ||
| const radiusVS = max( 1, float( STEP_COUNT.sub( 1 ) ) ).mul( stepRadius ); | ||
| const uvDirection = directionIsRight.equal( true ).select( vec2( 1, - 1 ), vec2( - 1, 1 ) ); // Port note: Because of different uv conventions, uv-y has a different sign | ||
| const samplingDirection = directionIsRight.equal( true ).select( 1, - 1 ); | ||
| const color = vec3( 0 ); | ||
| const lastSampleViewPosition = vec3( viewPosition ).toVar(); | ||
| Loop( { start: uint( 0 ), end: STEP_COUNT, type: 'uint', condition: '<' }, ( { i } ) => { | ||
| const offset = pow( abs( mul( stepRadius, float( i ).add( initialRayStep ) ).div( radiusVS ) ), EXP_FACTOR ).mul( radiusVS ).toConst(); | ||
| const uvOffset = slideDirTexelSize.mul( max( offset, float( i ).add( 1 ) ) ).toConst(); | ||
| const sampleUV = uvNode.add( uvOffset.mul( uvDirection ) ).toConst(); | ||
| If( sampleUV.x.lessThanEqual( 0 ).or( sampleUV.y.lessThanEqual( 0 ) ).or( sampleUV.x.greaterThanEqual( 1 ) ).or( sampleUV.y.greaterThanEqual( 1 ) ), () => { | ||
| Break(); | ||
| } ); | ||
| const sampleViewPosition = getViewPosition( sampleUV, sampleDepth( sampleUV ), this._cameraProjectionMatrixInverse ).toConst(); | ||
| const pixelToSample = sampleViewPosition.sub( viewPosition ).normalize().toConst(); | ||
| const linearThicknessMultiplier = this.useLinearThickness.equal( true ).select( sampleViewPosition.z.negate().div( this._cameraFar ).clamp().mul( 100 ), float( 1 ) ); | ||
| const pixelToSampleBackface = normalize( sampleViewPosition.sub( linearThicknessMultiplier.mul( viewDir ).mul( THICKNESS ) ).sub( viewPosition ) ); | ||
| let frontBackHorizon = vec2( dot( pixelToSample, viewDir ), dot( pixelToSampleBackface, viewDir ) ); | ||
| frontBackHorizon = GTAOFastAcos( clamp( frontBackHorizon, - 1, 1 ) ); | ||
| frontBackHorizon = clamp( div( mul( samplingDirection, frontBackHorizon.negate() ).sub( n.sub( HALF_PI ) ), PI ) ); // Port note: subtract half pi instead of adding it | ||
| frontBackHorizon = directionIsRight.equal( true ).select( frontBackHorizon.yx, frontBackHorizon.xy ); // Front/Back get inverted depending on angle | ||
| // inline ComputeOccludedBitfield() for easier debugging | ||
| const minHorizon = frontBackHorizon.x.toConst(); | ||
| const maxHorizon = frontBackHorizon.y.toConst(); | ||
| const startHorizonInt = uint( frontBackHorizon.mul( float( MAX_RAY ) ) ).toConst(); | ||
| const angleHorizonInt = uint( ceil( maxHorizon.sub( minHorizon ).mul( float( MAX_RAY ) ) ) ).toConst(); | ||
| const angleHorizonBitfield = angleHorizonInt.greaterThan( uint( 0 ) ).select( uint( shiftRight( uint( 0xFFFFFFFF ), uint( 32 ).sub( MAX_RAY ).add( MAX_RAY.sub( angleHorizonInt ) ) ) ), uint( 0 ) ).toConst(); | ||
| let currentOccludedBitfield = angleHorizonBitfield.shiftLeft( startHorizonInt ); | ||
| currentOccludedBitfield = currentOccludedBitfield.bitAnd( globalOccludedBitfield.bitNot() ); | ||
| globalOccludedBitfield.assign( globalOccludedBitfield.bitOr( currentOccludedBitfield ) ); | ||
| const numOccludedZones = bitCount( currentOccludedBitfield ); | ||
| // | ||
| If( numOccludedZones.greaterThan( 0 ), () => { // If a ray hit the sample, that sample is visible from shading point | ||
| const lightColor = sampleBeauty( sampleUV ); | ||
| If( luminance( lightColor ).greaterThan( 0.001 ), () => { // Continue if there is light at that location (intensity > 0) | ||
| const lightDirectionVS = normalize( pixelToSample ); | ||
| const normalDotLightDirection = clamp( dot( viewNormal, lightDirectionVS ) ); | ||
| If( normalDotLightDirection.greaterThan( 0.001 ), () => { // Continue if light is facing surface normal | ||
| const lightNormalVS = sampleNormal( sampleUV ); | ||
| // Intensity of outgoing light in the direction of the shading point | ||
| let lightNormalDotLightDirection = dot( lightNormalVS, lightDirectionVS.negate() ); | ||
| const d = sign( lightNormalDotLightDirection ).lessThan( 0 ).select( abs( lightNormalDotLightDirection ).mul( BACKFACE_LIGHTING ), abs( lightNormalDotLightDirection ) ); | ||
| lightNormalDotLightDirection = BACKFACE_LIGHTING.greaterThan( 0 ).and( dot( lightNormalVS, viewDir ).greaterThan( 0 ) ).select( d, clamp( lightNormalDotLightDirection ) ); | ||
| color.rgb.addAssign( float( numOccludedZones ).div( float( MAX_RAY ) ).mul( lightColor ).mul( normalDotLightDirection ).mul( lightNormalDotLightDirection ) ); | ||
| } ); | ||
| } ); | ||
| } ); | ||
| lastSampleViewPosition.assign( sampleViewPosition ); | ||
| } ); | ||
| return vec3( color ); | ||
| } ); | ||
| const gi = Fn( () => { | ||
| const depth = sampleDepth( uvNode ).toVar(); | ||
| depth.greaterThanEqual( 1.0 ).discard(); | ||
| const viewPosition = getViewPosition( uvNode, depth, this._cameraProjectionMatrixInverse ).toVar(); | ||
| const viewNormal = sampleNormal( uvNode ).toVar(); | ||
| const viewDir = normalize( viewPosition.xyz.negate() ).toVar(); | ||
| // | ||
| const noiseOffset = spatialOffsets( screenCoordinate ); | ||
| const noiseDirection = interleavedGradientNoise( screenCoordinate ); | ||
| const noiseJitterIdx = this._temporalDirection.mul( 0.02 ); // Port: Add noiseJitterIdx here for slightly better noise convergence with TRAA (see #31890 for more details) | ||
| const initialRayStep = fract( noiseOffset.add( this._temporalOffset ) ).add( rand( uvNode.add( noiseJitterIdx ).mul( 2 ).sub( 1 ) ) ); | ||
| const ao = float( 0 ); | ||
| const color = vec3( 0 ); | ||
| const ROTATION_COUNT = this.sliceCount.toConst(); | ||
| const AO_INTENSITY = this.aoIntensity.toConst(); | ||
| const GI_INTENSITY = this.giIntensity.toConst(); | ||
| const RADIUS = this.radius.toConst(); | ||
| Loop( { start: uint( 0 ), end: ROTATION_COUNT, type: 'uint', condition: '<' }, ( { i } ) => { | ||
| const rotationAngle = mul( float( i ).add( noiseDirection ).add( this._temporalDirection ), PI.div( float( ROTATION_COUNT ) ) ).toConst(); | ||
| const sliceDir = vec3( vec2( cos( rotationAngle ), sin( rotationAngle ) ), 0 ).toConst(); | ||
| const slideDirTexelSize = sliceDir.xy.mul( float( 1 ).div( this._resolution ) ).toConst(); | ||
| const planeNormal = normalize( cross( sliceDir, viewDir ) ).toConst(); | ||
| const tangent = cross( viewDir, planeNormal ).toConst(); | ||
| const projectedNormal = viewNormal.sub( planeNormal.mul( dot( viewNormal, planeNormal ) ) ).toConst(); | ||
| const projectedNormalNormalized = normalize( projectedNormal ).toConst(); | ||
| const cos_n = clamp( dot( projectedNormalNormalized, viewDir ), - 1, 1 ).toConst(); | ||
| const n = sign( dot( projectedNormal, tangent ) ).negate().mul( acos( cos_n ) ).toConst(); | ||
| globalOccludedBitfield.assign( 0 ); | ||
| color.addAssign( horizonSampling( bool( true ), RADIUS, viewPosition, slideDirTexelSize, initialRayStep, uvNode, viewDir, viewNormal, n ) ); | ||
| color.addAssign( horizonSampling( bool( false ), RADIUS, viewPosition, slideDirTexelSize, initialRayStep, uvNode, viewDir, viewNormal, n ) ); | ||
| ao.addAssign( float( bitCount( globalOccludedBitfield ) ).div( float( MAX_RAY ) ) ); | ||
| } ); | ||
| ao.divAssign( float( ROTATION_COUNT ) ); | ||
| ao.assign( pow( ao.clamp().oneMinus(), AO_INTENSITY ).clamp() ); | ||
| color.divAssign( float( ROTATION_COUNT ) ); | ||
| color.mulAssign( GI_INTENSITY ); | ||
| // scale color based on luminance | ||
| const maxLuminance = float( 7 ).toConst(); // 7 represent a HDR luminance value | ||
| const currentLuminance = luminance( color ); | ||
| const scale = currentLuminance.greaterThan( maxLuminance ).select( maxLuminance.div( currentLuminance ), float( 1 ) ); | ||
| color.mulAssign( scale ); | ||
| return vec4( color, ao ); | ||
| } ); | ||
| this._material.fragmentNode = gi().context( builder.getSharedContext() ); | ||
| this._material.needsUpdate = true; | ||
| // | ||
| return this._textureNode; | ||
| } | ||
| /** | ||
| * Frees internal resources. This method should be called | ||
| * when the effect is no longer required. | ||
| */ | ||
| dispose() { | ||
| this._ssgiRenderTarget.dispose(); | ||
| this._material.dispose(); | ||
| } | ||
| } | ||
| export default SSGINode; | ||
| /** | ||
| * TSL function for creating a SSGI effect. | ||
| * | ||
| * @tsl | ||
| * @function | ||
| * @param {TextureNode} beautyNode - The texture node that represents the input of the effect. | ||
| * @param {TextureNode} depthNode - A texture node that represents the scene's depth. | ||
| * @param {TextureNode} normalNode - A texture node that represents the scene's normals. | ||
| * @param {Camera} camera - The camera the scene is rendered with. | ||
| * @returns {SSGINode} | ||
| */ | ||
| export const ssgi = ( beautyNode, depthNode, normalNode, camera ) => nodeObject( new SSGINode( convertToTexture( beautyNode ), depthNode, normalNode, camera ) ); |
| import { RedFormat, RenderTarget, Vector2, RendererUtils, QuadMesh, TempNode, NodeMaterial, NodeUpdateType, UnsignedByteType } from 'three/webgpu'; | ||
| import { reference, viewZToPerspectiveDepth, logarithmicDepthToViewZ, getScreenPosition, getViewPosition, float, Break, Loop, int, max, abs, If, interleavedGradientNoise, screenCoordinate, nodeObject, Fn, passTexture, uv, uniform, perspectiveDepthToViewZ, orthographicDepthToViewZ, vec2, lightPosition, lightTargetPosition, fract, rand, mix } from 'three/tsl'; | ||
| const _quadMesh = /*@__PURE__*/ new QuadMesh(); | ||
| const _size = /*@__PURE__*/ new Vector2(); | ||
| const _spatialOffsets = [ 0, 0.5, 0.25, 0.75 ]; | ||
| let _rendererState; | ||
| /** | ||
| * Post processing node for applying Screen-Space Shadows (SSS) to a scene. | ||
| * | ||
| * Screen-Space Shadows (also known as Contact Shadows) should ideally be used to complement | ||
| * traditional shadow maps. They are best suited for rendering detailed shadows of smaller | ||
| * objects at a closer scale like intricate shadowing on highly detailed models. In other words: | ||
| * Use Shadow Maps for the foundation and Screen-Space Shadows for the details. | ||
| * | ||
| * The shadows produced by this implementation might have too hard edges for certain use cases. | ||
| * Use a box, gaussian or hash blur to soften the edges before doing the composite with the | ||
| * beauty pass. Code example: | ||
| * | ||
| * ```js | ||
| * const sssPass = sss( scenePassDepth, camera, mainLight ); | ||
| * | ||
| * const sssBlur = boxBlur( sssPass.r, { size: 2, separation: 1 } ); // optional blur | ||
| * ``` | ||
| * | ||
| * Limitations: | ||
| * | ||
| * - Ideally the maximum shadow length should not exceed `1` meter. Otherwise the effect gets | ||
| * computationally very expensive since more samples during the ray marching process are evaluated. | ||
| * You can mitigate this issue by reducing the `quality` paramter. | ||
| * - The effect can only be used with a single directional light, the main light of your scene. | ||
| * This main light usually represents the sun or daylight. | ||
| * - Like other Screen-Space techniques SSS can only honor objects in the shadowing computation that | ||
| * are currently visible within the camera's view. | ||
| * | ||
| * References: | ||
| * - {@link https://panoskarabelas.com/posts/screen_space_shadows/}. | ||
| * - {@link https://www.bendstudio.com/blog/inside-bend-screen-space-shadows/}. | ||
| * | ||
| * @augments TempNode | ||
| * @three_import import { sss } from 'three/addons/tsl/display/SSSNode.js'; | ||
| */ | ||
| class SSSNode extends TempNode { | ||
| static get type() { | ||
| return 'SSSNode'; | ||
| } | ||
| /** | ||
| * Constructs a new SSS node. | ||
| * | ||
| * @param {TextureNode} depthNode - A texture node that represents the scene's depth. | ||
| * @param {Camera} camera - The camera the scene is rendered with. | ||
| * @param {DirectionalLight} mainLight - The main directional light of the scene. | ||
| */ | ||
| constructor( depthNode, camera, mainLight ) { | ||
| super( 'float' ); | ||
| /** | ||
| * A node that represents the beauty pass's depth. | ||
| * | ||
| * @type {TextureNode} | ||
| */ | ||
| this.depthNode = depthNode; | ||
| /** | ||
| * Maximum shadow length in world units. Longer shadows result in more computational | ||
| * overhead. | ||
| * | ||
| * @type {UniformNode<float>} | ||
| * @default 0.1 | ||
| */ | ||
| this.maxDistance = uniform( 0.1, 'float' ); | ||
| /** | ||
| * Depth testing thickness. | ||
| * | ||
| * @type {UniformNode<float>} | ||
| * @default 0.01 | ||
| */ | ||
| this.thickness = uniform( 0.01, 'float' ); | ||
| /** | ||
| * Shadow intensity. Must be in the range `[0, 1]`. | ||
| * | ||
| * @type {UniformNode<float>} | ||
| * @default 0.5 | ||
| */ | ||
| this.shadowIntensity = uniform( 0.5, 'float' ); | ||
| /** | ||
| * This parameter controls how detailed the raymarching process works. | ||
| * The value ranges is `[0,1]` where `1` means best quality (the maximum number | ||
| * of raymarching iterations/samples) and `0` means no samples at all. | ||
| * | ||
| * A quality of `0.5` is usually sufficient for most use cases. Try to keep | ||
| * this parameter as low as possible. Larger values result in noticeable more | ||
| * overhead. | ||
| * | ||
| * @type {UniformNode<float>} | ||
| * @default 0.5 | ||
| */ | ||
| this.quality = uniform( 0.5 ); | ||
| /** | ||
| * The resolution scale. Valid values are in the range | ||
| * `[0,1]`. `1` means best quality but also results in | ||
| * more computational overhead. Setting to `0.5` means | ||
| * the effect is computed in half-resolution. | ||
| * | ||
| * @type {number} | ||
| * @default 1 | ||
| */ | ||
| this.resolutionScale = 1; | ||
| /** | ||
| * Whether to use temporal filtering or not. Setting this property to | ||
| * `true` requires the usage of `TRAANode`. This will help to reduce noice | ||
| * although it introduces typical TAA artifacts like ghosting and temporal | ||
| * instabilities. | ||
| * | ||
| * @type {boolean} | ||
| * @default false | ||
| */ | ||
| this.useTemporalFiltering = false; | ||
| /** | ||
| * The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node renders | ||
| * its effect once per frame in `updateBefore()`. | ||
| * | ||
| * @type {string} | ||
| * @default 'frame' | ||
| */ | ||
| this.updateBeforeType = NodeUpdateType.FRAME; | ||
| // private uniforms | ||
| /** | ||
| * Represents the view matrix of the scene's camera. | ||
| * | ||
| * @private | ||
| * @type {UniformNode<mat4>} | ||
| */ | ||
| this._cameraViewMatrix = uniform( camera.matrixWorldInverse ); | ||
| /** | ||
| * Represents the projection matrix of the scene's camera. | ||
| * | ||
| * @private | ||
| * @type {UniformNode<mat4>} | ||
| */ | ||
| this._cameraProjectionMatrix = uniform( camera.projectionMatrix ); | ||
| /** | ||
| * Represents the inverse projection matrix of the scene's camera. | ||
| * | ||
| * @private | ||
| * @type {UniformNode<mat4>} | ||
| */ | ||
| this._cameraProjectionMatrixInverse = uniform( camera.projectionMatrixInverse ); | ||
| /** | ||
| * Represents the near value of the scene's camera. | ||
| * | ||
| * @private | ||
| * @type {ReferenceNode<float>} | ||
| */ | ||
| this._cameraNear = reference( 'near', 'float', camera ); | ||
| /** | ||
| * Represents the far value of the scene's camera. | ||
| * | ||
| * @private | ||
| * @type {ReferenceNode<float>} | ||
| */ | ||
| this._cameraFar = reference( 'far', 'float', camera ); | ||
| /** | ||
| * The resolution of the pass. | ||
| * | ||
| * @private | ||
| * @type {UniformNode<vec2>} | ||
| */ | ||
| this._resolution = uniform( new Vector2() ); | ||
| /** | ||
| * Temporal offset added to the initial ray step. | ||
| * | ||
| * @type {UniformNode<float>} | ||
| */ | ||
| this._temporalOffset = uniform( 0 ); | ||
| /** | ||
| * The frame ID use when temporal filtering is enabled. | ||
| * | ||
| * @type {UniformNode<uint>} | ||
| */ | ||
| this._frameId = uniform( 0 ); | ||
| /** | ||
| * A reference to the scene's main light. | ||
| * | ||
| * @private | ||
| * @type {DirectionalLight} | ||
| */ | ||
| this._mainLight = mainLight; | ||
| /** | ||
| * The camera the scene is rendered with. | ||
| * | ||
| * @private | ||
| * @type {Camera} | ||
| */ | ||
| this._camera = camera; | ||
| /** | ||
| * The render target the SSS is rendered into. | ||
| * | ||
| * @private | ||
| * @type {RenderTarget} | ||
| */ | ||
| this._sssRenderTarget = new RenderTarget( 1, 1, { depthBuffer: false, format: RedFormat, type: UnsignedByteType } ); | ||
| this._sssRenderTarget.texture.name = 'SSS'; | ||
| /** | ||
| * The material that is used to render the effect. | ||
| * | ||
| * @private | ||
| * @type {NodeMaterial} | ||
| */ | ||
| this._material = new NodeMaterial(); | ||
| this._material.name = 'SSS'; | ||
| /** | ||
| * The result of the effect is represented as a separate texture node. | ||
| * | ||
| * @private | ||
| * @type {PassTextureNode} | ||
| */ | ||
| this._textureNode = passTexture( this, this._sssRenderTarget.texture ); | ||
| } | ||
| /** | ||
| * Returns the result of the effect as a texture node. | ||
| * | ||
| * @return {PassTextureNode} A texture node that represents the result of the effect. | ||
| */ | ||
| getTextureNode() { | ||
| return this._textureNode; | ||
| } | ||
| /** | ||
| * Sets the size of the effect. | ||
| * | ||
| * @param {number} width - The width of the effect. | ||
| * @param {number} height - The height of the effect. | ||
| */ | ||
| setSize( width, height ) { | ||
| width = Math.round( this.resolutionScale * width ); | ||
| height = Math.round( this.resolutionScale * height ); | ||
| this._resolution.value.set( width, height ); | ||
| this._sssRenderTarget.setSize( width, height ); | ||
| } | ||
| /** | ||
| * This method is used to render the effect once per frame. | ||
| * | ||
| * @param {NodeFrame} frame - The current node frame. | ||
| */ | ||
| updateBefore( frame ) { | ||
| const { renderer } = frame; | ||
| _rendererState = RendererUtils.resetRendererState( renderer, _rendererState ); | ||
| // | ||
| const size = renderer.getDrawingBufferSize( _size ); | ||
| this.setSize( size.width, size.height ); | ||
| // update temporal uniforms | ||
| if ( this.useTemporalFiltering === true ) { | ||
| const frameId = frame.frameId; | ||
| this._temporalOffset.value = _spatialOffsets[ frameId % 4 ]; | ||
| this._frameId = frame.frameId; | ||
| } else { | ||
| this._temporalOffset.value = 0; | ||
| this._frameId = 0; | ||
| } | ||
| // | ||
| _quadMesh.material = this._material; | ||
| _quadMesh.name = 'SSS'; | ||
| // clear | ||
| renderer.setClearColor( 0xffffff, 1 ); | ||
| // sss | ||
| renderer.setRenderTarget( this._sssRenderTarget ); | ||
| _quadMesh.render( renderer ); | ||
| // restore | ||
| RendererUtils.restoreRendererState( renderer, _rendererState ); | ||
| } | ||
| /** | ||
| * This method is used to setup the effect's TSL code. | ||
| * | ||
| * @param {NodeBuilder} builder - The current node builder. | ||
| * @return {PassTextureNode} | ||
| */ | ||
| setup( builder ) { | ||
| const uvNode = uv(); | ||
| const getViewZ = Fn( ( [ depth ] ) => { | ||
| let viewZNode; | ||
| if ( this._camera.isPerspectiveCamera ) { | ||
| viewZNode = perspectiveDepthToViewZ( depth, this._cameraNear, this._cameraFar ); | ||
| } else { | ||
| viewZNode = orthographicDepthToViewZ( depth, this._cameraNear, this._cameraFar ); | ||
| } | ||
| return viewZNode; | ||
| } ); | ||
| const sampleDepth = ( uv ) => { | ||
| const depth = this.depthNode.sample( uv ).r; | ||
| if ( builder.renderer.logarithmicDepthBuffer === true ) { | ||
| const viewZ = logarithmicDepthToViewZ( depth, this._cameraNear, this._cameraFar ); | ||
| return viewZToPerspectiveDepth( viewZ, this._cameraNear, this._cameraFar ); | ||
| } | ||
| return depth; | ||
| }; | ||
| const sss = Fn( () => { | ||
| const depth = sampleDepth( uvNode ).toVar(); | ||
| depth.greaterThanEqual( 1.0 ).discard(); | ||
| // compute ray position and direction (in view-space) | ||
| const rayStartPosition = getViewPosition( uvNode, depth, this._cameraProjectionMatrixInverse ).toVar( 'rayStartPosition' ); | ||
| const rayDirection = this._cameraViewMatrix.transformDirection( lightPosition( this._mainLight ).sub( lightTargetPosition( this._mainLight ) ) ).toConst( 'rayDirection' ); | ||
| const rayEndPosition = rayStartPosition.add( rayDirection.mul( this.maxDistance ) ).toConst( 'rayEndPosition' ); | ||
| // d0 and d1 are the start and maximum points of the ray in screen space | ||
| const d0 = screenCoordinate.xy.toVar(); | ||
| const d1 = getScreenPosition( rayEndPosition, this._cameraProjectionMatrix ).mul( this._resolution ).toVar(); | ||
| // below variables are used to control the raymarching process | ||
| // total length of the ray | ||
| const totalLen = d1.sub( d0 ).length().toVar(); | ||
| // offset in x and y direction | ||
| const xLen = d1.x.sub( d0.x ).toVar(); | ||
| const yLen = d1.y.sub( d0.y ).toVar(); | ||
| // determine the larger delta | ||
| // The larger difference will help to determine how much to travel in the X and Y direction each iteration and | ||
| // how many iterations are needed to travel the entire ray | ||
| const totalStep = int( max( abs( xLen ), abs( yLen ) ).mul( this.quality.clamp() ) ).toConst(); | ||
| // step sizes in the x and y directions | ||
| const xSpan = xLen.div( totalStep ).toVar(); | ||
| const ySpan = yLen.div( totalStep ).toVar(); | ||
| // compute noise based ray offset | ||
| const noise = interleavedGradientNoise( screenCoordinate ); | ||
| const offset = fract( noise.add( this._temporalOffset ) ).add( rand( uvNode.add( this._frameId ) ) ).toConst( 'offset' ); | ||
| const occlusion = float( 0 ).toVar(); | ||
| Loop( totalStep, ( { i } ) => { | ||
| // advance on the ray by computing a new position in screen coordinates | ||
| const xy = vec2( d0.x.add( xSpan.mul( float( i ).add( offset ) ) ), d0.y.add( ySpan.mul( float( i ).add( offset ) ) ) ).toVar(); | ||
| // stop processing if the new position lies outside of the screen | ||
| If( xy.x.lessThan( 0 ).or( xy.x.greaterThan( this._resolution.x ) ).or( xy.y.lessThan( 0 ) ).or( xy.y.greaterThan( this._resolution.y ) ), () => { | ||
| Break(); | ||
| } ); | ||
| // compute new uv, depth and viewZ for the next fragment | ||
| const uvNode = xy.div( this._resolution ); | ||
| const fragmentDepth = sampleDepth( uvNode ).toConst(); | ||
| const fragmentViewZ = getViewZ( fragmentDepth ).toConst( 'fragmentViewZ' ); | ||
| const s = xy.sub( d0 ).length().div( totalLen ).toVar(); | ||
| const rayPosition = mix( rayStartPosition, rayEndPosition, s ); | ||
| const depthDelta = rayPosition.z.sub( fragmentViewZ ).negate(); // Port note: viewZ values are negative in three | ||
| // check if the camera can't "see" the ray (ray depth must be larger than the camera depth, so positive depth_delta) | ||
| If( depthDelta.greaterThan( 0 ).and( depthDelta.lessThan( this.thickness ) ), () => { | ||
| // mark as occluded | ||
| occlusion.assign( this.shadowIntensity ); | ||
| Break(); | ||
| } ); | ||
| } ); | ||
| return occlusion.oneMinus(); | ||
| } ); | ||
| this._material.fragmentNode = sss().context( builder.getSharedContext() ); | ||
| this._material.needsUpdate = true; | ||
| return this._textureNode; | ||
| } | ||
| /** | ||
| * Frees internal resources. This method should be called | ||
| * when the effect is no longer required. | ||
| */ | ||
| dispose() { | ||
| this._sssRenderTarget.dispose(); | ||
| this._material.dispose(); | ||
| } | ||
| } | ||
| export default SSSNode; | ||
| /** | ||
| * TSL function for creating a SSS effect. | ||
| * | ||
| * @tsl | ||
| * @function | ||
| * @param {TextureNode} depthNode - A texture node that represents the scene's depth. | ||
| * @param {Camera} camera - The camera the scene is rendered with. | ||
| * @param {DirectionalLight} mainLight - The main directional light of the scene. | ||
| * @returns {SSSNode} | ||
| */ | ||
| export const sss = ( depthNode, camera, mainLight ) => nodeObject( new SSSNode( depthNode, camera, mainLight ) ); |
| import Node from './Node.js'; | ||
| import InspectorBase from '../../renderers/common/InspectorBase.js'; | ||
| import { addMethodChaining, nodeObject } from '../tsl/TSLCore.js'; | ||
| import { NodeUpdateType } from './constants.js'; | ||
| import { warnOnce } from '../../utils.js'; | ||
| /** | ||
| * InspectorNode is a wrapper node that allows inspection of node values during rendering. | ||
| * It can be used to debug or analyze node outputs in the rendering pipeline. | ||
| * | ||
| * @augments Node | ||
| */ | ||
| class InspectorNode extends Node { | ||
| /** | ||
| * Returns the type of the node. | ||
| * | ||
| * @returns {string} | ||
| */ | ||
| static get type() { | ||
| return 'InspectorNode'; | ||
| } | ||
| /** | ||
| * Creates an InspectorNode. | ||
| * | ||
| * @param {Node} node - The node to inspect. | ||
| * @param {string} [name=''] - Optional name for the inspector node. | ||
| * @param {Function|null} [callback=null] - Optional callback to modify the node during setup. | ||
| */ | ||
| constructor( node, name = '', callback = null ) { | ||
| super(); | ||
| this.node = node; | ||
| this.name = name; | ||
| this.callback = callback; | ||
| this.updateType = NodeUpdateType.FRAME; | ||
| this.isInspectorNode = true; | ||
| } | ||
| /** | ||
| * Returns the name of the inspector node. | ||
| * | ||
| * @returns {string} | ||
| */ | ||
| getName() { | ||
| return this.name || this.node.name; | ||
| } | ||
| /** | ||
| * Updates the inspector node, allowing inspection of the wrapped node. | ||
| * | ||
| * @param {NodeFrame} frame - A reference to the current node frame. | ||
| */ | ||
| update( frame ) { | ||
| frame.renderer.inspector.inspect( this ); | ||
| } | ||
| /** | ||
| * Returns the type of the wrapped node. | ||
| * | ||
| * @param {NodeBuilder} builder - The node builder. | ||
| * @returns {string} | ||
| */ | ||
| getNodeType( builder ) { | ||
| return this.node.getNodeType( builder ); | ||
| } | ||
| /** | ||
| * Sets up the inspector node. | ||
| * | ||
| * @param {NodeBuilder} builder - The node builder. | ||
| * @returns {Node} The setup node. | ||
| */ | ||
| setup( builder ) { | ||
| let node = this.node; | ||
| if ( builder.context.inspector === true && this.callback !== null ) { | ||
| node = this.callback( node ); | ||
| } | ||
| if ( builder.renderer.backend.isWebGPUBackend !== true && builder.renderer.inspector.constructor !== InspectorBase ) { | ||
| warnOnce( 'TSL: ".toInspector()" is only available with WebGPU.' ); | ||
| } | ||
| return node; | ||
| } | ||
| } | ||
| export default InspectorNode; | ||
| /** | ||
| * Creates an inspector node to wrap around a given node for inspection purposes. | ||
| * | ||
| * @tsl | ||
| * @param {Node} node - The node to inspect. | ||
| * @param {string} [name=''] - Optional name for the inspector node. | ||
| * @param {Function|null} [callback=null] - Optional callback to modify the node during setup. | ||
| * @returns {Node} The inspector node. | ||
| */ | ||
| export function inspector( node, name = '', callback = null ) { | ||
| node = nodeObject( node ); | ||
| return node.before( new InspectorNode( node, name, callback ) ); | ||
| } | ||
| addMethodChaining( 'toInspector', inspector ); |
| import Node from './Node.js'; | ||
| import { addMethodChaining, nodeObject } from '../tsl/TSLCore.js'; | ||
| import { warn } from '../../utils.js'; | ||
| /** | ||
| * This node can be used as a cache management component for another node. | ||
| * Caching is in general used by default in {@link NodeBuilder} but this node | ||
| * allows the usage of a shared parent cache during the build process. | ||
| * | ||
| * @augments Node | ||
| */ | ||
| class IsolateNode extends Node { | ||
| static get type() { | ||
| return 'IsolateNode'; | ||
| } | ||
| /** | ||
| * Constructs a new cache node. | ||
| * | ||
| * @param {Node} node - The node that should be cached. | ||
| * @param {boolean} [parent=true] - Whether this node refers to a shared parent cache or not. | ||
| */ | ||
| constructor( node, parent = true ) { | ||
| super(); | ||
| /** | ||
| * The node that should be cached. | ||
| * | ||
| * @type {Node} | ||
| */ | ||
| this.node = node; | ||
| /** | ||
| * Whether this node refers to a shared parent cache or not. | ||
| * | ||
| * @type {boolean} | ||
| * @default true | ||
| */ | ||
| this.parent = parent; | ||
| /** | ||
| * This flag can be used for type testing. | ||
| * | ||
| * @type {boolean} | ||
| * @readonly | ||
| * @default true | ||
| */ | ||
| this.isIsolateNode = true; | ||
| } | ||
| getNodeType( builder ) { | ||
| const previousCache = builder.getCache(); | ||
| const cache = builder.getCacheFromNode( this, this.parent ); | ||
| builder.setCache( cache ); | ||
| const nodeType = this.node.getNodeType( builder ); | ||
| builder.setCache( previousCache ); | ||
| return nodeType; | ||
| } | ||
| build( builder, ...params ) { | ||
| const previousCache = builder.getCache(); | ||
| const cache = builder.getCacheFromNode( this, this.parent ); | ||
| builder.setCache( cache ); | ||
| const data = this.node.build( builder, ...params ); | ||
| builder.setCache( previousCache ); | ||
| return data; | ||
| } | ||
| setParent( parent ) { | ||
| this.parent = parent; | ||
| return this; | ||
| } | ||
| getParent() { | ||
| return this.parent; | ||
| } | ||
| } | ||
| export default IsolateNode; | ||
| /** | ||
| * TSL function for creating a cache node. | ||
| * | ||
| * @tsl | ||
| * @function | ||
| * @param {Node} node - The node that should be cached. | ||
| * @returns {IsolateNode} | ||
| */ | ||
| export const isolate = ( node ) => new IsolateNode( nodeObject( node ) ); | ||
| /** | ||
| * TSL function for creating a cache node. | ||
| * | ||
| * @tsl | ||
| * @function | ||
| * @deprecated | ||
| * @param {Node} node - The node that should be cached. | ||
| * @param {boolean} [parent=true] - Whether this node refers to a shared parent cache or not. | ||
| * @returns {IsolateNode} | ||
| */ | ||
| export function cache( node, parent = true ) { | ||
| warn( 'TSL: "cache()" has been deprecated. Use "isolate()" instead.' ); // @deprecated r181 | ||
| return isolate( node ).setParent( parent ); | ||
| } | ||
| addMethodChaining( 'cache', cache ); | ||
| addMethodChaining( 'isolate', isolate ); |
| import BRDF_GGX from './BRDF_GGX.js'; | ||
| import DFGApprox from './DFGApprox.js'; | ||
| import { normalView } from '../../accessors/Normal.js'; | ||
| import { positionViewDirection } from '../../accessors/Position.js'; | ||
| import { EPSILON } from '../../math/MathNode.js'; | ||
| import { Fn, float } from '../../tsl/TSLBase.js'; | ||
| // GGX BRDF with multi-scattering energy compensation for direct lighting | ||
| // This provides more accurate energy conservation, especially for rough materials | ||
| // Based on "Practical Multiple Scattering Compensation for Microfacet Models" | ||
| // https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf | ||
| const BRDF_GGX_Multiscatter = /*@__PURE__*/ Fn( ( { lightDirection, f0, f90, roughness: _roughness, f, USE_IRIDESCENCE, USE_ANISOTROPY } ) => { | ||
| // Single-scattering BRDF (standard GGX) | ||
| const singleScatter = BRDF_GGX( { lightDirection, f0, f90, roughness: _roughness, f, USE_IRIDESCENCE, USE_ANISOTROPY } ); | ||
| // Multi-scattering compensation | ||
| const dotNL = normalView.dot( lightDirection ).clamp(); | ||
| const dotNV = normalView.dot( positionViewDirection ).clamp(); | ||
| // Precomputed DFG values for view and light directions | ||
| const dfgV = DFGApprox( { roughness: _roughness, dotNV } ); | ||
| const dfgL = DFGApprox( { roughness: _roughness, dotNV: dotNL } ); | ||
| // Single-scattering energy for view and light | ||
| const FssEss_V = f0.mul( dfgV.x ).add( f90.mul( dfgV.y ) ); | ||
| const FssEss_L = f0.mul( dfgL.x ).add( f90.mul( dfgL.y ) ); | ||
| const Ess_V = dfgV.x.add( dfgV.y ); | ||
| const Ess_L = dfgL.x.add( dfgL.y ); | ||
| // Energy lost to multiple scattering | ||
| const Ems_V = float( 1.0 ).sub( Ess_V ); | ||
| const Ems_L = float( 1.0 ).sub( Ess_L ); | ||
| // Average Fresnel reflectance | ||
| const Favg = f0.add( f0.oneMinus().mul( 0.047619 ) ); // 1/21 | ||
| // Multiple scattering contribution | ||
| // Uses geometric mean of view and light contributions for better energy distribution | ||
| const Fms = FssEss_V.mul( FssEss_L ).mul( Favg ).div( float( 1.0 ).sub( Ems_V.mul( Ems_L ).mul( Favg ).mul( Favg ) ).add( EPSILON ) ); | ||
| // Energy compensation factor | ||
| const compensationFactor = Ems_V.mul( Ems_L ); | ||
| const multiScatter = Fms.mul( compensationFactor ); | ||
| return singleScatter.add( multiScatter ); | ||
| } ); | ||
| export default BRDF_GGX_Multiscatter; |
| import { EventDispatcher } from '../../core/EventDispatcher.js'; | ||
| import { Vector4 } from '../../math/Vector4.js'; | ||
| import { FramebufferTexture } from '../../textures/FramebufferTexture.js'; | ||
| import { DepthTexture } from '../../textures/DepthTexture.js'; | ||
| /** | ||
| * CanvasTarget is a class that represents the final output destination of the renderer. | ||
| * | ||
| * @augments EventDispatcher | ||
| */ | ||
| class CanvasTarget extends EventDispatcher { | ||
| /** | ||
| * Constructs a new CanvasTarget. | ||
| * | ||
| * @param {HTMLCanvasElement|OffscreenCanvas} domElement - The canvas element to render to. | ||
| */ | ||
| constructor( domElement ) { | ||
| super(); | ||
| /** | ||
| * A reference to the canvas element the renderer is drawing to. | ||
| * This value of this property will automatically be created by | ||
| * the renderer. | ||
| * | ||
| * @type {HTMLCanvasElement|OffscreenCanvas} | ||
| */ | ||
| this.domElement = domElement; | ||
| /** | ||
| * The renderer's pixel ratio. | ||
| * | ||
| * @private | ||
| * @type {number} | ||
| * @default 1 | ||
| */ | ||
| this._pixelRatio = 1; | ||
| /** | ||
| * The width of the renderer's default framebuffer in logical pixel unit. | ||
| * | ||
| * @private | ||
| * @type {number} | ||
| */ | ||
| this._width = this.domElement.width; | ||
| /** | ||
| * The height of the renderer's default framebuffer in logical pixel unit. | ||
| * | ||
| * @private | ||
| * @type {number} | ||
| */ | ||
| this._height = this.domElement.height; | ||
| /** | ||
| * The viewport of the renderer in logical pixel unit. | ||
| * | ||
| * @private | ||
| * @type {Vector4} | ||
| */ | ||
| this._viewport = new Vector4( 0, 0, this._width, this._height ); | ||
| /** | ||
| * The scissor rectangle of the renderer in logical pixel unit. | ||
| * | ||
| * @private | ||
| * @type {Vector4} | ||
| */ | ||
| this._scissor = new Vector4( 0, 0, this._width, this._height ); | ||
| /** | ||
| * Whether the scissor test should be enabled or not. | ||
| * | ||
| * @private | ||
| * @type {boolean} | ||
| */ | ||
| this._scissorTest = false; | ||
| /** | ||
| * The color texture of the default framebuffer. | ||
| * | ||
| * @type {FramebufferTexture} | ||
| */ | ||
| this.colorTexture = new FramebufferTexture(); | ||
| /** | ||
| * The depth texture of the default framebuffer. | ||
| * | ||
| * @type {DepthTexture} | ||
| */ | ||
| this.depthTexture = new DepthTexture(); | ||
| } | ||
| /** | ||
| * Returns the pixel ratio. | ||
| * | ||
| * @return {number} The pixel ratio. | ||
| */ | ||
| getPixelRatio() { | ||
| return this._pixelRatio; | ||
| } | ||
| /** | ||
| * Returns the drawing buffer size in physical pixels. This method honors the pixel ratio. | ||
| * | ||
| * @param {Vector2} target - The method writes the result in this target object. | ||
| * @return {Vector2} The drawing buffer size. | ||
| */ | ||
| getDrawingBufferSize( target ) { | ||
| return target.set( this._width * this._pixelRatio, this._height * this._pixelRatio ).floor(); | ||
| } | ||
| /** | ||
| * Returns the renderer's size in logical pixels. This method does not honor the pixel ratio. | ||
| * | ||
| * @param {Vector2} target - The method writes the result in this target object. | ||
| * @return {Vector2} The renderer's size in logical pixels. | ||
| */ | ||
| getSize( target ) { | ||
| return target.set( this._width, this._height ); | ||
| } | ||
| /** | ||
| * Sets the given pixel ratio and resizes the canvas if necessary. | ||
| * | ||
| * @param {number} [value=1] - The pixel ratio. | ||
| */ | ||
| setPixelRatio( value = 1 ) { | ||
| if ( this._pixelRatio === value ) return; | ||
| this._pixelRatio = value; | ||
| this.setSize( this._width, this._height, false ); | ||
| } | ||
| /** | ||
| * This method allows to define the drawing buffer size by specifying | ||
| * width, height and pixel ratio all at once. The size of the drawing | ||
| * buffer is computed with this formula: | ||
| * ```js | ||
| * size.x = width * pixelRatio; | ||
| * size.y = height * pixelRatio; | ||
| * ``` | ||
| * | ||
| * @param {number} width - The width in logical pixels. | ||
| * @param {number} height - The height in logical pixels. | ||
| * @param {number} pixelRatio - The pixel ratio. | ||
| */ | ||
| setDrawingBufferSize( width, height, pixelRatio ) { | ||
| // Renderer can't be resized while presenting in XR. | ||
| if ( this.xr && this.xr.isPresenting ) return; | ||
| this._width = width; | ||
| this._height = height; | ||
| this._pixelRatio = pixelRatio; | ||
| this.domElement.width = Math.floor( width * pixelRatio ); | ||
| this.domElement.height = Math.floor( height * pixelRatio ); | ||
| this.setViewport( 0, 0, width, height ); | ||
| this._dispatchResize(); | ||
| } | ||
| /** | ||
| * Sets the size of the renderer. | ||
| * | ||
| * @param {number} width - The width in logical pixels. | ||
| * @param {number} height - The height in logical pixels. | ||
| * @param {boolean} [updateStyle=true] - Whether to update the `style` attribute of the canvas or not. | ||
| */ | ||
| setSize( width, height, updateStyle = true ) { | ||
| // Renderer can't be resized while presenting in XR. | ||
| if ( this.xr && this.xr.isPresenting ) return; | ||
| this._width = width; | ||
| this._height = height; | ||
| this.domElement.width = Math.floor( width * this._pixelRatio ); | ||
| this.domElement.height = Math.floor( height * this._pixelRatio ); | ||
| if ( updateStyle === true ) { | ||
| this.domElement.style.width = width + 'px'; | ||
| this.domElement.style.height = height + 'px'; | ||
| } | ||
| this.setViewport( 0, 0, width, height ); | ||
| this._dispatchResize(); | ||
| } | ||
| /** | ||
| * Returns the scissor rectangle. | ||
| * | ||
| * @param {Vector4} target - The method writes the result in this target object. | ||
| * @return {Vector4} The scissor rectangle. | ||
| */ | ||
| getScissor( target ) { | ||
| const scissor = this._scissor; | ||
| target.x = scissor.x; | ||
| target.y = scissor.y; | ||
| target.width = scissor.width; | ||
| target.height = scissor.height; | ||
| return target; | ||
| } | ||
| /** | ||
| * Defines the scissor rectangle. | ||
| * | ||
| * @param {number | Vector4} x - The horizontal coordinate for the lower left corner of the box in logical pixel unit. | ||
| * Instead of passing four arguments, the method also works with a single four-dimensional vector. | ||
| * @param {number} y - The vertical coordinate for the lower left corner of the box in logical pixel unit. | ||
| * @param {number} width - The width of the scissor box in logical pixel unit. | ||
| * @param {number} height - The height of the scissor box in logical pixel unit. | ||
| */ | ||
| setScissor( x, y, width, height ) { | ||
| const scissor = this._scissor; | ||
| if ( x.isVector4 ) { | ||
| scissor.copy( x ); | ||
| } else { | ||
| scissor.set( x, y, width, height ); | ||
| } | ||
| } | ||
| /** | ||
| * Returns the scissor test value. | ||
| * | ||
| * @return {boolean} Whether the scissor test should be enabled or not. | ||
| */ | ||
| getScissorTest() { | ||
| return this._scissorTest; | ||
| } | ||
| /** | ||
| * Defines the scissor test. | ||
| * | ||
| * @param {boolean} boolean - Whether the scissor test should be enabled or not. | ||
| */ | ||
| setScissorTest( boolean ) { | ||
| this._scissorTest = boolean; | ||
| } | ||
| /** | ||
| * Returns the viewport definition. | ||
| * | ||
| * @param {Vector4} target - The method writes the result in this target object. | ||
| * @return {Vector4} The viewport definition. | ||
| */ | ||
| getViewport( target ) { | ||
| return target.copy( this._viewport ); | ||
| } | ||
| /** | ||
| * Defines the viewport. | ||
| * | ||
| * @param {number | Vector4} x - The horizontal coordinate for the lower left corner of the viewport origin in logical pixel unit. | ||
| * @param {number} y - The vertical coordinate for the lower left corner of the viewport origin in logical pixel unit. | ||
| * @param {number} width - The width of the viewport in logical pixel unit. | ||
| * @param {number} height - The height of the viewport in logical pixel unit. | ||
| * @param {number} minDepth - The minimum depth value of the viewport. WebGPU only. | ||
| * @param {number} maxDepth - The maximum depth value of the viewport. WebGPU only. | ||
| */ | ||
| setViewport( x, y, width, height, minDepth = 0, maxDepth = 1 ) { | ||
| const viewport = this._viewport; | ||
| if ( x.isVector4 ) { | ||
| viewport.copy( x ); | ||
| } else { | ||
| viewport.set( x, y, width, height ); | ||
| } | ||
| viewport.minDepth = minDepth; | ||
| viewport.maxDepth = maxDepth; | ||
| } | ||
| /** | ||
| * Dispatches the resize event. | ||
| * | ||
| * @private | ||
| */ | ||
| _dispatchResize() { | ||
| this.dispatchEvent( { type: 'resize' } ); | ||
| } | ||
| /** | ||
| * Frees the GPU-related resources allocated by this instance. Call this | ||
| * method whenever this instance is no longer used in your app. | ||
| * | ||
| * @fires RenderTarget#dispose | ||
| */ | ||
| dispose() { | ||
| this.dispatchEvent( { type: 'dispose' } ); | ||
| } | ||
| } | ||
| export default CanvasTarget; |
| /** | ||
| * InspectorBase is the base class for all inspectors. | ||
| * | ||
| * @class InspectorBase | ||
| */ | ||
| class InspectorBase { | ||
| /** | ||
| * Creates a new InspectorBase. | ||
| */ | ||
| constructor() { | ||
| /** | ||
| * The renderer associated with this inspector. | ||
| * | ||
| * @type {WebGLRenderer} | ||
| * @private | ||
| */ | ||
| this._renderer = null; | ||
| /** | ||
| * The current frame being processed. | ||
| * | ||
| * @type {Object} | ||
| */ | ||
| this.currentFrame = null; | ||
| } | ||
| /** | ||
| * Returns the node frame for the current renderer. | ||
| * | ||
| * @return {Object} The node frame. | ||
| */ | ||
| get nodeFrame() { | ||
| return this._renderer._nodes.nodeFrame; | ||
| } | ||
| /** | ||
| * Sets the renderer for this inspector. | ||
| * | ||
| * @param {WebGLRenderer} renderer - The renderer to associate with this inspector. | ||
| * @return {InspectorBase} This inspector instance. | ||
| */ | ||
| setRenderer( renderer ) { | ||
| this._renderer = renderer; | ||
| return this; | ||
| } | ||
| /** | ||
| * Returns the renderer associated with this inspector. | ||
| * | ||
| * @return {WebGLRenderer} The associated renderer. | ||
| */ | ||
| getRenderer() { | ||
| return this._renderer; | ||
| } | ||
| /** | ||
| * Initializes the inspector. | ||
| */ | ||
| init() { } | ||
| /** | ||
| * Called when a frame begins. | ||
| */ | ||
| begin() { } | ||
| /** | ||
| * Called when a frame ends. | ||
| */ | ||
| finish() { } | ||
| /** | ||
| * Inspects a node. | ||
| * | ||
| * @param {Node} node - The node to inspect. | ||
| */ | ||
| inspect( /*node*/ ) { } | ||
| /** | ||
| * When a compute operation is performed. | ||
| * | ||
| * @param {ComputeNode} computeNode - The compute node being executed. | ||
| * @param {number|Array<number>} dispatchSizeOrCount - The dispatch size or count. | ||
| */ | ||
| computeAsync( /*computeNode, dispatchSizeOrCount*/ ) { } | ||
| /** | ||
| * Called when a compute operation begins. | ||
| * | ||
| * @param {string} uid - A unique identifier for the render context. | ||
| * @param {ComputeNode} computeNode - The compute node being executed. | ||
| */ | ||
| beginCompute( /*uid, computeNode*/ ) { } | ||
| /** | ||
| * Called when a compute operation ends. | ||
| * | ||
| * @param {string} uid - A unique identifier for the render context. | ||
| * @param {ComputeNode} computeNode - The compute node being executed. | ||
| */ | ||
| finishCompute( /*uid*/ ) { } | ||
| /** | ||
| * Called when a render operation begins. | ||
| * | ||
| * @param {string} uid - A unique identifier for the render context. | ||
| * @param {Scene} scene - The scene being rendered. | ||
| * @param {Camera} camera - The camera being used for rendering. | ||
| * @param {?WebGLRenderTarget} renderTarget - The render target, if any. | ||
| */ | ||
| beginRender( /*uid, scene, camera, renderTarget*/ ) { } | ||
| /** | ||
| * Called when an animation loop ends. | ||
| * | ||
| * @param {string} uid - A unique identifier for the render context. | ||
| */ | ||
| finishRender( /*uid*/ ) { } | ||
| /** | ||
| * Called when a texture copy operation is performed. | ||
| * | ||
| * @param {Texture} srcTexture - The source texture. | ||
| * @param {Texture} dstTexture - The destination texture. | ||
| */ | ||
| copyTextureToTexture( /*srcTexture, dstTexture*/ ) { } | ||
| /** | ||
| * Called when a framebuffer copy operation is performed. | ||
| * | ||
| * @param {Texture} framebufferTexture - The texture associated with the framebuffer. | ||
| */ | ||
| copyFramebufferToTexture( /*framebufferTexture*/ ) { } | ||
| } | ||
| export default InspectorBase; |
| /** | ||
| * Precomputed DFG LUT for Image-Based Lighting | ||
| * Resolution: 32x32 | ||
| * Samples: 4096 per texel | ||
| * Format: RG16F (2 half floats per texel: scale, bias) | ||
| */ | ||
| import { DataTexture } from '../../textures/DataTexture.js'; | ||
| import { RGFormat, HalfFloatType, LinearFilter, ClampToEdgeWrapping } from '../../constants.js'; | ||
| const DATA = new Uint16Array( [ | ||
| 0x2cd9, 0x3b64, 0x2d0e, 0x3b43, 0x2e20, 0x3aa7, 0x3061, 0x39fb, 0x325e, 0x397c, 0x3454, 0x3908, 0x357d, 0x3893, 0x3698, 0x381e, 0x379d, 0x375b, 0x3845, 0x3689, 0x38af, 0x35ca, 0x390d, 0x351e, 0x395f, 0x3484, 0x39a8, 0x33f9, 0x39e6, 0x330a, 0x3a1c, 0x3239, 0x3a4b, 0x3183, 0x3a73, 0x30e5, 0x3a95, 0x305b, 0x3ab1, 0x2fc6, 0x3ac9, 0x2ef7, 0x3ade, 0x2e43, 0x3aee, 0x2da7, 0x3afc, 0x2d1f, 0x3b07, 0x2ca9, 0x3b10, 0x2c42, 0x3b17, 0x2bd1, 0x3b1c, 0x2b34, 0x3b1f, 0x2aaa, 0x3b22, 0x2a31, 0x3b23, 0x29c7, 0x3b23, 0x2968, | ||
| 0x32d4, 0x3a4b, 0x32dc, 0x3a45, 0x3308, 0x3a26, 0x3378, 0x39d0, 0x3425, 0x394a, 0x34c9, 0x38be, 0x359c, 0x383e, 0x3688, 0x3796, 0x3778, 0x36c4, 0x382f, 0x3603, 0x3898, 0x3553, 0x38f7, 0x34b3, 0x394b, 0x3424, 0x3994, 0x334c, 0x39d3, 0x326c, 0x3a08, 0x31a9, 0x3a35, 0x30fe, 0x3a5a, 0x306a, 0x3a78, 0x2fd1, 0x3a90, 0x2ef1, 0x3aa2, 0x2e2e, 0x3ab0, 0x2d86, 0x3aba, 0x2cf3, 0x3ac1, 0x2c74, 0x3ac4, 0x2c05, 0x3ac4, 0x2b49, 0x3ac2, 0x2aa1, 0x3abd, 0x2a0c, 0x3ab7, 0x298b, 0x3aaf, 0x2918, 0x3aa6, 0x28b3, 0x3a9b, 0x285a, | ||
| 0x3559, 0x3954, 0x355a, 0x3951, 0x3566, 0x3944, 0x3582, 0x391e, 0x35b6, 0x38d3, 0x360a, 0x386a, 0x3684, 0x37ed, 0x3720, 0x370d, 0x37d3, 0x3641, 0x3847, 0x3588, 0x38a3, 0x34e2, 0x38fa, 0x344d, 0x3948, 0x3391, 0x398d, 0x32a6, 0x39c8, 0x31d6, 0x39fa, 0x3121, 0x3a22, 0x3082, 0x3a43, 0x2ff0, 0x3a5c, 0x2f01, 0x3a6f, 0x2e32, 0x3a7c, 0x2d7e, 0x3a84, 0x2ce2, 0x3a87, 0x2c5b, 0x3a87, 0x2bcc, 0x3a83, 0x2b00, 0x3a7b, 0x2a4e, 0x3a71, 0x29b3, 0x3a66, 0x292c, 0x3a58, 0x28b4, 0x3a4b, 0x284b, 0x3a3d, 0x27dc, 0x3a2e, 0x2739, | ||
| 0x3709, 0x387c, 0x370a, 0x387b, 0x3710, 0x3874, 0x3720, 0x385f, 0x373d, 0x3834, 0x376a, 0x37e1, 0x37ac, 0x3732, 0x3805, 0x3675, 0x383f, 0x35bc, 0x3883, 0x3511, 0x38cb, 0x3476, 0x3912, 0x33d8, 0x3955, 0x32e2, 0x3991, 0x3208, 0x39c6, 0x3149, 0x39f1, 0x30a1, 0x3a15, 0x300f, 0x3a30, 0x2f21, 0x3a44, 0x2e45, 0x3a51, 0x2d87, 0x3a59, 0x2ce2, 0x3a5b, 0x2c53, 0x3a58, 0x2bb0, 0x3a52, 0x2ada, 0x3a49, 0x2a1f, 0x3a40, 0x297d, 0x3a34, 0x28f0, 0x3a25, 0x2874, 0x3a13, 0x2807, 0x3a00, 0x274e, 0x39eb, 0x26a6, 0x39d5, 0x2611, | ||
| 0x3840, 0x3780, 0x3840, 0x377e, 0x3842, 0x3776, 0x3846, 0x375e, 0x384f, 0x372a, 0x385b, 0x36d3, 0x386c, 0x3659, 0x3885, 0x35c7, 0x38a8, 0x352d, 0x38d4, 0x3497, 0x3906, 0x340c, 0x393b, 0x331a, 0x3970, 0x323a, 0x39a0, 0x3172, 0x39cb, 0x30c3, 0x39ef, 0x302a, 0x3a0c, 0x2f4a, 0x3a21, 0x2e63, 0x3a2f, 0x2d9b, 0x3a37, 0x2ced, 0x3a39, 0x2c57, 0x3a37, 0x2baa, 0x3a34, 0x2ac9, 0x3a2c, 0x2a05, 0x3a20, 0x295d, 0x3a11, 0x28ca, 0x39ff, 0x2849, 0x39eb, 0x27b2, 0x39d5, 0x26ed, 0x39be, 0x2640, 0x39a5, 0x25aa, 0x398b, 0x2523, | ||
| 0x38e2, 0x363b, 0x38e2, 0x363b, 0x38e3, 0x3635, 0x38e6, 0x3626, 0x38ea, 0x3606, 0x38f0, 0x35cd, 0x38f8, 0x3579, 0x3903, 0x350e, 0x3915, 0x3495, 0x392d, 0x3418, 0x394c, 0x3340, 0x3970, 0x3261, 0x3995, 0x3197, 0x39b8, 0x30e4, 0x39d8, 0x3046, 0x39f3, 0x2f76, 0x3a08, 0x2e86, 0x3a16, 0x2db5, 0x3a1e, 0x2cff, 0x3a22, 0x2c61, 0x3a24, 0x2bb3, 0x3a20, 0x2ac7, 0x3a17, 0x29fc, 0x3a0a, 0x294c, 0x39fa, 0x28b2, 0x39e7, 0x282e, 0x39d1, 0x2773, 0x39b9, 0x26a9, 0x399f, 0x25fa, 0x3985, 0x255f, 0x3968, 0x24d6, 0x394a, 0x245d, | ||
| 0x396e, 0x3524, 0x396e, 0x3524, 0x396e, 0x3520, 0x396f, 0x3517, 0x3971, 0x3502, 0x3973, 0x34dd, 0x3975, 0x34a5, 0x3978, 0x3458, 0x397e, 0x33f9, 0x3987, 0x3332, 0x3997, 0x326b, 0x39aa, 0x31ac, 0x39c0, 0x30fb, 0x39d7, 0x305c, 0x39eb, 0x2f9e, 0x39fc, 0x2ea7, 0x3a07, 0x2dcf, 0x3a0f, 0x2d13, 0x3a16, 0x2c70, 0x3a17, 0x2bc4, 0x3a14, 0x2ad0, 0x3a0a, 0x29fc, 0x39fd, 0x2945, 0x39ed, 0x28a6, 0x39d9, 0x281d, 0x39c2, 0x274a, 0x39a9, 0x267c, 0x398e, 0x25c7, 0x3971, 0x2528, 0x3952, 0x249e, 0x3931, 0x2425, 0x3910, 0x2374, | ||
| 0x39e5, 0x3436, 0x39e5, 0x3435, 0x39e5, 0x3434, 0x39e5, 0x342e, 0x39e5, 0x3420, 0x39e5, 0x3408, 0x39e3, 0x33c4, 0x39e1, 0x3359, 0x39df, 0x32d3, 0x39de, 0x323a, 0x39e1, 0x319a, 0x39e7, 0x30fb, 0x39f0, 0x3065, 0x39f9, 0x2fb6, 0x3a02, 0x2ec0, 0x3a08, 0x2de6, 0x3a0d, 0x2d26, 0x3a12, 0x2c7e, 0x3a13, 0x2bda, 0x3a0e, 0x2adc, 0x3a05, 0x2a02, 0x39f8, 0x2945, 0x39e7, 0x28a1, 0x39d3, 0x2813, 0x39bc, 0x2730, 0x39a2, 0x265c, 0x3985, 0x25a3, 0x3966, 0x2501, 0x3945, 0x2475, 0x3923, 0x23f3, 0x3901, 0x231c, 0x38dd, 0x225e, | ||
| 0x3a4b, 0x32d6, 0x3a4a, 0x32d6, 0x3a4a, 0x32d4, 0x3a4a, 0x32cc, 0x3a48, 0x32bb, 0x3a47, 0x329d, 0x3a43, 0x326b, 0x3a3d, 0x3222, 0x3a36, 0x31c2, 0x3a2e, 0x314f, 0x3a28, 0x30d2, 0x3a23, 0x3052, 0x3a20, 0x2fab, 0x3a1e, 0x2ec2, 0x3a1b, 0x2def, 0x3a19, 0x2d31, 0x3a1a, 0x2c89, 0x3a18, 0x2beb, 0x3a11, 0x2aea, 0x3a07, 0x2a0a, 0x39fa, 0x2948, 0x39e9, 0x28a1, 0x39d4, 0x280f, 0x39bd, 0x2721, 0x39a2, 0x2647, 0x3985, 0x258b, 0x3964, 0x24e5, 0x3942, 0x2455, 0x391f, 0x23b3, 0x38fb, 0x22d8, 0x38d4, 0x2219, 0x38ad, 0x2172, | ||
| 0x3aa0, 0x3180, 0x3aa0, 0x3180, 0x3aa0, 0x317f, 0x3a9f, 0x317b, 0x3a9d, 0x3170, 0x3a99, 0x315d, 0x3a95, 0x313d, 0x3a8d, 0x310c, 0x3a82, 0x30ca, 0x3a76, 0x3077, 0x3a69, 0x3019, 0x3a5c, 0x2f68, 0x3a4f, 0x2e9e, 0x3a42, 0x2dde, 0x3a37, 0x2d2b, 0x3a30, 0x2c89, 0x3a29, 0x2bef, 0x3a1f, 0x2af0, 0x3a12, 0x2a0f, 0x3a03, 0x294a, 0x39f1, 0x28a0, 0x39dc, 0x280c, 0x39c5, 0x2717, 0x39a9, 0x2638, 0x398b, 0x2578, 0x396a, 0x24d0, 0x3947, 0x243f, 0x3923, 0x2380, 0x38fc, 0x22a4, 0x38d4, 0x21e4, 0x38ac, 0x213c, 0x3883, 0x20a8, | ||
| 0x3ae8, 0x3062, 0x3ae8, 0x3062, 0x3ae7, 0x3061, 0x3ae6, 0x305f, 0x3ae4, 0x305a, 0x3ae0, 0x304f, 0x3ada, 0x303b, 0x3ad1, 0x301b, 0x3ac5, 0x2fdd, 0x3ab6, 0x2f6a, 0x3aa4, 0x2ede, 0x3a91, 0x2e45, 0x3a7c, 0x2da5, 0x3a67, 0x2d0a, 0x3a57, 0x2c77, 0x3a48, 0x2bdc, 0x3a38, 0x2ae5, 0x3a27, 0x2a0a, 0x3a16, 0x2947, 0x3a02, 0x289d, 0x39eb, 0x2808, 0x39d3, 0x270d, 0x39b6, 0x262b, 0x3997, 0x256a, 0x3976, 0x24bf, 0x3952, 0x242b, 0x392d, 0x2358, 0x3904, 0x227a, 0x38db, 0x21b8, 0x38b2, 0x2110, 0x3887, 0x207d, 0x385b, 0x1ff6, | ||
| 0x3b23, 0x2ee8, 0x3b23, 0x2ee8, 0x3b22, 0x2ee8, 0x3b21, 0x2ee7, 0x3b1f, 0x2ee3, 0x3b1a, 0x2ed6, 0x3b14, 0x2ec1, 0x3b0b, 0x2e99, 0x3afe, 0x2e60, 0x3aee, 0x2e12, 0x3ad8, 0x2dad, 0x3ac1, 0x2d3d, 0x3aa5, 0x2cc3, 0x3a8b, 0x2c48, 0x3a76, 0x2ba2, 0x3a60, 0x2ac0, 0x3a49, 0x29f2, 0x3a32, 0x2938, 0x3a1b, 0x2893, 0x3a02, 0x27ff, 0x39e8, 0x26ff, 0x39ca, 0x261e, 0x39aa, 0x255b, 0x3988, 0x24b0, 0x3964, 0x241c, 0x393d, 0x2336, 0x3913, 0x2257, 0x38e9, 0x2195, 0x38be, 0x20eb, 0x3891, 0x2059, 0x3864, 0x1fae, 0x3837, 0x1ecd, | ||
| 0x3b54, 0x2d61, 0x3b54, 0x2d61, 0x3b53, 0x2d61, 0x3b52, 0x2d62, 0x3b4f, 0x2d61, 0x3b4b, 0x2d5c, 0x3b45, 0x2d51, 0x3b3b, 0x2d3d, 0x3b2e, 0x2d1a, 0x3b1d, 0x2ce7, 0x3b06, 0x2ca3, 0x3aeb, 0x2c52, 0x3acb, 0x2bee, 0x3ab0, 0x2b31, 0x3a94, 0x2a74, 0x3a77, 0x29bf, 0x3a5a, 0x2915, 0x3a3f, 0x287a, 0x3a22, 0x27de, 0x3a05, 0x26e4, 0x39e5, 0x2609, 0x39c3, 0x2547, 0x39a0, 0x249f, 0x397b, 0x240c, 0x3953, 0x2314, 0x3928, 0x2238, 0x38fd, 0x2175, 0x38d0, 0x20cb, 0x38a2, 0x2038, 0x3873, 0x1f71, 0x3844, 0x1e90, 0x3815, 0x1dce, | ||
| 0x3b7c, 0x2c22, 0x3b7c, 0x2c22, 0x3b7b, 0x2c23, 0x3b7a, 0x2c25, 0x3b77, 0x2c27, 0x3b73, 0x2c26, 0x3b6d, 0x2c23, 0x3b64, 0x2c1a, 0x3b57, 0x2c07, 0x3b46, 0x2bd1, 0x3b2e, 0x2b79, 0x3b0f, 0x2b07, 0x3aef, 0x2a86, 0x3ad1, 0x29f8, 0x3ab0, 0x2967, 0x3a8e, 0x28d7, 0x3a6d, 0x284e, 0x3a4c, 0x279f, 0x3a2b, 0x26b7, 0x3a08, 0x25e5, 0x39e4, 0x252c, 0x39be, 0x2488, 0x3998, 0x23f0, 0x396f, 0x22f2, 0x3943, 0x2215, 0x3917, 0x2155, 0x38e8, 0x20ae, 0x38b9, 0x201c, 0x3888, 0x1f38, 0x3857, 0x1e5a, 0x3826, 0x1d9a, 0x37eb, 0x1cf0, | ||
| 0x3b9c, 0x2a43, 0x3b9c, 0x2a43, 0x3b9b, 0x2a46, 0x3b9a, 0x2a4a, 0x3b98, 0x2a50, 0x3b93, 0x2a54, 0x3b8e, 0x2a59, 0x3b85, 0x2a56, 0x3b79, 0x2a45, 0x3b67, 0x2a24, 0x3b4f, 0x29ee, 0x3b2f, 0x29a4, 0x3b10, 0x294b, 0x3aef, 0x28e5, 0x3ac9, 0x2877, 0x3aa4, 0x2809, 0x3a7e, 0x2739, 0x3a59, 0x266d, 0x3a34, 0x25af, 0x3a0c, 0x2503, 0x39e4, 0x2468, 0x39bb, 0x23bb, 0x3990, 0x22c6, 0x3963, 0x21f0, 0x3936, 0x2133, 0x3906, 0x208f, 0x38d5, 0x1ffd, 0x38a3, 0x1f04, 0x3870, 0x1e28, 0x383d, 0x1d69, 0x380b, 0x1cc3, 0x37b0, 0x1c32, | ||
| 0x3bb5, 0x28aa, 0x3bb5, 0x28ab, 0x3bb5, 0x28ad, 0x3bb4, 0x28b2, 0x3bb2, 0x28b9, 0x3bae, 0x28c2, 0x3ba8, 0x28ca, 0x3ba0, 0x28d1, 0x3b94, 0x28cd, 0x3b83, 0x28c1, 0x3b6a, 0x28a3, 0x3b4b, 0x2876, 0x3b2d, 0x283d, 0x3b09, 0x27ea, 0x3ae1, 0x274b, 0x3ab9, 0x26a6, 0x3a8f, 0x25fe, 0x3a67, 0x255d, 0x3a3d, 0x24c5, 0x3a11, 0x2439, 0x39e6, 0x2371, 0x39b9, 0x228d, 0x398a, 0x21c1, 0x395a, 0x210b, 0x3929, 0x206c, 0x38f7, 0x1fc1, 0x38c3, 0x1ecb, 0x388f, 0x1df6, 0x385a, 0x1d3a, 0x3825, 0x1c99, 0x37e1, 0x1c08, 0x3779, 0x1b1b, | ||
| 0x3bc9, 0x26d3, 0x3bc9, 0x26d4, 0x3bc9, 0x26d9, 0x3bc8, 0x26e3, 0x3bc6, 0x26ef, 0x3bc2, 0x2705, 0x3bbd, 0x271a, 0x3bb6, 0x2731, 0x3baa, 0x273c, 0x3b9a, 0x273d, 0x3b81, 0x2726, 0x3b65, 0x26f7, 0x3b46, 0x26af, 0x3b20, 0x2650, 0x3af7, 0x25e1, 0x3acd, 0x256a, 0x3aa1, 0x24eb, 0x3a75, 0x246f, 0x3a46, 0x23ee, 0x3a17, 0x230d, 0x39e9, 0x223e, 0x39b7, 0x2183, 0x3985, 0x20d8, 0x3953, 0x2043, 0x391e, 0x1f7a, 0x38e9, 0x1e8d, 0x38b3, 0x1dbf, 0x387c, 0x1d0b, 0x3845, 0x1c6c, 0x380e, 0x1bc4, 0x37b0, 0x1ad2, 0x3745, 0x19fd, | ||
| 0x3bd9, 0x24e4, 0x3bd9, 0x24e5, 0x3bd9, 0x24e8, 0x3bd8, 0x24f2, 0x3bd5, 0x24fe, 0x3bd2, 0x2512, 0x3bce, 0x252b, 0x3bc6, 0x2544, 0x3bbc, 0x255a, 0x3bac, 0x256b, 0x3b93, 0x2569, 0x3b7a, 0x2557, 0x3b5b, 0x252f, 0x3b34, 0x24f7, 0x3b0c, 0x24ad, 0x3adf, 0x2458, 0x3ab1, 0x23f8, 0x3a82, 0x233f, 0x3a4f, 0x2286, 0x3a1e, 0x21d5, 0x39eb, 0x2130, 0x39b6, 0x2098, 0x3982, 0x200e, 0x394b, 0x1f25, 0x3914, 0x1e45, 0x38dc, 0x1d83, 0x38a3, 0x1cd6, 0x386b, 0x1c3d, 0x3831, 0x1b71, 0x37f2, 0x1a87, 0x3782, 0x19bc, 0x3714, 0x1909, | ||
| 0x3be5, 0x22d8, 0x3be5, 0x22d9, 0x3be4, 0x22df, 0x3be4, 0x22ef, 0x3be1, 0x2305, 0x3bde, 0x232a, 0x3bda, 0x2358, 0x3bd4, 0x2392, 0x3bcb, 0x23ca, 0x3bbb, 0x23f4, 0x3ba3, 0x2405, 0x3b8c, 0x2405, 0x3b6c, 0x23ec, 0x3b47, 0x23ae, 0x3b1d, 0x2353, 0x3af0, 0x22e2, 0x3ac0, 0x2261, 0x3a8e, 0x21d9, 0x3a5a, 0x214e, 0x3a26, 0x20c7, 0x39ee, 0x2045, 0x39b7, 0x1f97, 0x397f, 0x1eba, 0x3945, 0x1df0, 0x390b, 0x1d3a, 0x38d0, 0x1c9a, 0x3895, 0x1c0a, 0x385a, 0x1b18, 0x381f, 0x1a39, 0x37c9, 0x1975, 0x3756, 0x18cc, 0x36e6, 0x1836, | ||
| 0x3bed, 0x20a8, 0x3bed, 0x20a9, 0x3bed, 0x20ae, 0x3bed, 0x20bb, 0x3beb, 0x20cf, 0x3be8, 0x20ef, 0x3be4, 0x2119, 0x3bde, 0x214f, 0x3bd6, 0x2189, 0x3bc6, 0x21b8, 0x3bb1, 0x21de, 0x3b9a, 0x21f2, 0x3b7b, 0x21f2, 0x3b57, 0x21d8, 0x3b2d, 0x21a4, 0x3b00, 0x215f, 0x3acf, 0x2108, 0x3a99, 0x20a8, 0x3a64, 0x2043, 0x3a2c, 0x1fba, 0x39f2, 0x1ef3, 0x39b8, 0x1e36, 0x397c, 0x1d86, 0x3940, 0x1ce5, 0x3903, 0x1c52, 0x38c6, 0x1b9e, 0x3888, 0x1ab3, 0x384a, 0x19e4, 0x380e, 0x192b, 0x37a3, 0x188b, 0x372d, 0x17f7, 0x36ba, 0x1701, | ||
| 0x3bf4, 0x1e23, 0x3bf4, 0x1e25, 0x3bf4, 0x1e2d, 0x3bf3, 0x1e41, 0x3bf1, 0x1e64, 0x3bef, 0x1e9c, 0x3beb, 0x1ee1, 0x3be6, 0x1f40, 0x3bde, 0x1fa7, 0x3bce, 0x2001, 0x3bbd, 0x202f, 0x3ba6, 0x204e, 0x3b88, 0x205f, 0x3b64, 0x205b, 0x3b3b, 0x2044, 0x3b0e, 0x201f, 0x3adb, 0x1fcf, 0x3aa6, 0x1f4e, 0x3a6e, 0x1ec1, 0x3a33, 0x1e2b, 0x39f7, 0x1d95, 0x39ba, 0x1d06, 0x397b, 0x1c7d, 0x393c, 0x1bfc, 0x38fc, 0x1b13, 0x38bc, 0x1a40, 0x387c, 0x1983, 0x383c, 0x18da, 0x37fa, 0x1842, 0x377f, 0x177f, 0x3706, 0x1695, 0x3691, 0x15c8, | ||
| 0x3bf8, 0x1bca, 0x3bf8, 0x1bcc, 0x3bf8, 0x1bd8, 0x3bf8, 0x1bf7, 0x3bf6, 0x1c1b, 0x3bf4, 0x1c45, 0x3bf1, 0x1c83, 0x3bec, 0x1cce, 0x3be4, 0x1d21, 0x3bd5, 0x1d78, 0x3bc5, 0x1dd1, 0x3bb0, 0x1e17, 0x3b93, 0x1e4a, 0x3b70, 0x1e5f, 0x3b48, 0x1e57, 0x3b1b, 0x1e35, 0x3ae7, 0x1df6, 0x3ab2, 0x1da4, 0x3a77, 0x1d44, 0x3a3a, 0x1cdb, 0x39fc, 0x1c6e, 0x39bb, 0x1c03, 0x397a, 0x1b35, 0x3938, 0x1a72, 0x38f5, 0x19bb, 0x38b3, 0x1914, 0x3870, 0x187d, 0x382e, 0x17eb, 0x37db, 0x16f9, 0x375c, 0x1621, 0x36e1, 0x1565, 0x3669, 0x14be, | ||
| 0x3bfb, 0x18b9, 0x3bfb, 0x18ba, 0x3bfb, 0x18c3, 0x3bfb, 0x18da, 0x3bf9, 0x190a, 0x3bf7, 0x1948, 0x3bf5, 0x19ac, 0x3bf0, 0x1a20, 0x3be9, 0x1ab3, 0x3bdb, 0x1b49, 0x3bcd, 0x1be6, 0x3bb7, 0x1c34, 0x3b9c, 0x1c6d, 0x3b7a, 0x1c8e, 0x3b54, 0x1c9e, 0x3b26, 0x1c96, 0x3af2, 0x1c75, 0x3abc, 0x1c47, 0x3a80, 0x1c09, 0x3a42, 0x1b85, 0x3a01, 0x1aec, 0x39be, 0x1a50, 0x397a, 0x19b5, 0x3935, 0x1921, 0x38f0, 0x1895, 0x38aa, 0x1814, 0x3866, 0x173a, 0x3821, 0x1665, 0x37be, 0x15a4, 0x373c, 0x14f9, 0x36be, 0x1460, 0x3644, 0x13b3, | ||
| 0x3bfd, 0x156b, 0x3bfd, 0x156c, 0x3bfd, 0x1578, 0x3bfd, 0x1598, 0x3bfc, 0x15dd, 0x3bfa, 0x163c, 0x3bf7, 0x16cb, 0x3bf3, 0x177b, 0x3beb, 0x1833, 0x3be0, 0x18ad, 0x3bd2, 0x192e, 0x3bbd, 0x19a6, 0x3ba4, 0x1a0c, 0x3b83, 0x1a5a, 0x3b5d, 0x1a8c, 0x3b30, 0x1a9b, 0x3afd, 0x1a86, 0x3ac6, 0x1a5c, 0x3a89, 0x1a11, 0x3a49, 0x19b7, 0x3a06, 0x194f, 0x39c1, 0x18e3, 0x397a, 0x1873, 0x3933, 0x1805, 0x38eb, 0x173a, 0x38a3, 0x1676, 0x385c, 0x15bf, 0x3816, 0x1519, 0x37a2, 0x1482, 0x371d, 0x13f7, 0x369c, 0x1306, 0x3620, 0x1231, | ||
| 0x3bff, 0x11cb, 0x3bff, 0x11cd, 0x3bfe, 0x11dd, 0x3bfe, 0x1219, 0x3bfd, 0x126b, 0x3bfb, 0x12e9, 0x3bf9, 0x13c5, 0x3bf5, 0x1460, 0x3bee, 0x150f, 0x3be3, 0x15c9, 0x3bd6, 0x168a, 0x3bc3, 0x174f, 0x3baa, 0x1806, 0x3b8b, 0x184f, 0x3b66, 0x1888, 0x3b39, 0x18a6, 0x3b07, 0x18ad, 0x3acf, 0x189c, 0x3a92, 0x1876, 0x3a50, 0x1840, 0x3a0c, 0x17fd, 0x39c4, 0x176a, 0x397b, 0x16ce, 0x3931, 0x1634, 0x38e6, 0x1599, 0x389c, 0x1508, 0x3852, 0x147f, 0x380a, 0x1401, 0x3788, 0x131c, 0x36ff, 0x124a, 0x367c, 0x1190, 0x35fe, 0x10ea, | ||
| 0x3bff, 0x0daa, 0x3bff, 0x0dad, 0x3bff, 0x0dc0, 0x3bff, 0x0e0e, 0x3bfe, 0x0e87, 0x3bfc, 0x0f14, 0x3bfb, 0x1029, 0x3bf7, 0x10d1, 0x3bf0, 0x11d3, 0x3be6, 0x12c9, 0x3bd9, 0x13fc, 0x3bc7, 0x1499, 0x3bb0, 0x152a, 0x3b92, 0x15ab, 0x3b6e, 0x1615, 0x3b42, 0x165a, 0x3b10, 0x1681, 0x3ad8, 0x1683, 0x3a9a, 0x1665, 0x3a57, 0x1629, 0x3a11, 0x15dd, 0x39c8, 0x1580, 0x397c, 0x1518, 0x3930, 0x14ae, 0x38e3, 0x1441, 0x3896, 0x13b1, 0x384a, 0x12e9, 0x37ff, 0x122f, 0x376f, 0x1182, 0x36e3, 0x10e5, 0x365e, 0x1057, 0x35de, 0x0fac, | ||
| 0x3c00, 0x08ea, 0x3c00, 0x08ed, 0x3c00, 0x0902, 0x3c00, 0x0961, 0x3bff, 0x09f3, 0x3bfd, 0x0abc, 0x3bfb, 0x0c1f, 0x3bf8, 0x0d15, 0x3bf1, 0x0e5b, 0x3be8, 0x0fb4, 0x3bdc, 0x10b0, 0x3bcb, 0x1190, 0x3bb5, 0x126c, 0x3b97, 0x132c, 0x3b74, 0x13de, 0x3b4a, 0x1432, 0x3b18, 0x145e, 0x3ae0, 0x1472, 0x3aa2, 0x146f, 0x3a5f, 0x1456, 0x3a17, 0x142e, 0x39cc, 0x13ee, 0x397e, 0x136b, 0x392f, 0x12e1, 0x38df, 0x124f, 0x3890, 0x11bd, 0x3842, 0x1131, 0x37eb, 0x10ac, 0x3757, 0x102e, 0x36c9, 0x0f76, 0x3640, 0x0ea3, 0x35bf, 0x0de4, | ||
| 0x3c00, 0x039b, 0x3c00, 0x039d, 0x3c00, 0x03b2, 0x3c00, 0x041c, 0x3bff, 0x04be, 0x3bfd, 0x05d6, 0x3bfc, 0x0764, 0x3bf8, 0x08e2, 0x3bf2, 0x0a67, 0x3bea, 0x0c1b, 0x3bde, 0x0d41, 0x3bcd, 0x0e5f, 0x3bb8, 0x0f8c, 0x3b9c, 0x1057, 0x3b7a, 0x10e5, 0x3b51, 0x1155, 0x3b20, 0x11a5, 0x3ae8, 0x11da, 0x3aaa, 0x11ef, 0x3a66, 0x11e5, 0x3a1d, 0x11c1, 0x39d0, 0x1185, 0x3980, 0x113b, 0x392e, 0x10e5, 0x38dc, 0x1087, 0x388b, 0x1028, 0x383b, 0x0f94, 0x37d9, 0x0edb, 0x3741, 0x0e2c, 0x36af, 0x0d89, 0x3625, 0x0cf2, 0x35a1, 0x0c69, | ||
| 0x3c00, 0x0107, 0x3c00, 0x0108, 0x3c00, 0x0110, 0x3c00, 0x0145, 0x3bff, 0x0197, 0x3bfe, 0x0224, 0x3bfc, 0x030c, 0x3bf8, 0x0478, 0x3bf3, 0x062c, 0x3beb, 0x0833, 0x3be0, 0x0979, 0x3bd0, 0x0aeb, 0x3bbc, 0x0c3d, 0x3ba0, 0x0d01, 0x3b80, 0x0dbd, 0x3b57, 0x0e69, 0x3b27, 0x0eeb, 0x3af0, 0x0f53, 0x3ab1, 0x0f8a, 0x3a6c, 0x0f9f, 0x3a22, 0x0f8b, 0x39d4, 0x0f5b, 0x3982, 0x0f0f, 0x392f, 0x0eac, 0x38da, 0x0e3d, 0x3886, 0x0dc9, 0x3834, 0x0d51, 0x37c7, 0x0cd9, 0x372c, 0x0c65, 0x3697, 0x0bef, 0x360a, 0x0b20, 0x3585, 0x0a62, | ||
| 0x3c00, 0x0031, 0x3c00, 0x0031, 0x3c00, 0x0034, 0x3c00, 0x004b, 0x3bff, 0x006f, 0x3bfe, 0x00c9, 0x3bfc, 0x011b, 0x3bf9, 0x0207, 0x3bf4, 0x02d6, 0x3bec, 0x0415, 0x3be1, 0x0587, 0x3bd2, 0x0703, 0x3bbf, 0x087d, 0x3ba5, 0x096a, 0x3b85, 0x0a59, 0x3b5d, 0x0b32, 0x3b2e, 0x0bee, 0x3af7, 0x0c44, 0x3ab8, 0x0c7c, 0x3a73, 0x0c9c, 0x3a28, 0x0ca4, 0x39d8, 0x0c98, 0x3985, 0x0c77, 0x392f, 0x0c4a, 0x38d9, 0x0c10, 0x3882, 0x0ba0, 0x382e, 0x0b14, 0x37b6, 0x0a84, 0x3717, 0x09f5, 0x3680, 0x0969, 0x35f0, 0x08e6, 0x356a, 0x086a, | ||
| 0x3c00, 0x0004, 0x3c00, 0x0004, 0x3c00, 0x0004, 0x3c00, 0x000d, 0x3bff, 0x0021, 0x3bfe, 0x003b, 0x3bfd, 0x0070, 0x3bf9, 0x00c7, 0x3bf4, 0x012e, 0x3bed, 0x01c8, 0x3be3, 0x0274, 0x3bd4, 0x033b, 0x3bc1, 0x043a, 0x3ba8, 0x0534, 0x3b89, 0x0641, 0x3b62, 0x073b, 0x3b34, 0x0815, 0x3afd, 0x087c, 0x3abf, 0x08d0, 0x3a7a, 0x090a, 0x3a2e, 0x092c, 0x39dd, 0x0936, 0x3988, 0x0928, 0x3930, 0x0907, 0x38d7, 0x08d7, 0x387f, 0x089b, 0x3828, 0x0855, 0x37a7, 0x080b, 0x3704, 0x077b, 0x366a, 0x06e1, 0x35d8, 0x0649, 0x3550, 0x05b8, | ||
| 0x3c00, 0x0000, 0x3c00, 0x0000, 0x3c00, 0x0000, 0x3c00, 0x0003, 0x3bff, 0x0012, 0x3bfe, 0x001a, 0x3bfd, 0x0035, 0x3bfa, 0x0050, 0x3bf4, 0x0061, 0x3bed, 0x00a5, 0x3be4, 0x00ee, 0x3bd6, 0x0146, 0x3bc3, 0x01ab, 0x3bab, 0x0211, 0x3b8d, 0x028e, 0x3b67, 0x0303, 0x3b39, 0x0375, 0x3b04, 0x03e2, 0x3ac6, 0x0441, 0x3a80, 0x0492, 0x3a34, 0x04cd, 0x39e1, 0x04f2, 0x398b, 0x0504, 0x3931, 0x0502, 0x38d6, 0x04ec, 0x387c, 0x04c7, 0x3822, 0x0496, 0x3798, 0x045c, 0x36f2, 0x041a, 0x3655, 0x03d5, 0x35c1, 0x038e, 0x3537, 0x0347 | ||
| ] ); | ||
| let lut = null; | ||
| export function getDFGLUT() { | ||
| if ( lut === null ) { | ||
| lut = new DataTexture( DATA, 32, 32, RGFormat, HalfFloatType ); | ||
| lut.minFilter = LinearFilter; | ||
| lut.magFilter = LinearFilter; | ||
| lut.wrapS = ClampToEdgeWrapping; | ||
| lut.wrapT = ClampToEdgeWrapping; | ||
| lut.generateMipmaps = false; | ||
| lut.needsUpdate = true; | ||
| } | ||
| return lut; | ||
| } |
@@ -32,2 +32,4 @@ /** | ||
| const PI2 = TSL.PI2; | ||
| const TWO_PI = TSL.TWO_PI; | ||
| const HALF_PI = TSL.HALF_PI; | ||
| const PointShadowFilter = TSL.PointShadowFilter; | ||
@@ -205,2 +207,3 @@ const Return = TSL.Return; | ||
| const getNormalFromDepth = TSL.getNormalFromDepth; | ||
| const interleavedGradientNoise = TSL.interleavedGradientNoise; | ||
| const getParallaxCorrectNormal = TSL.getParallaxCorrectNormal; | ||
@@ -406,2 +409,4 @@ const getRoughness = TSL.getRoughness; | ||
| const objectWorldMatrix = TSL.objectWorldMatrix; | ||
| const OnBeforeObjectUpdate = TSL.OnBeforeObjectUpdate; | ||
| const OnBeforeMaterialUpdate = TSL.OnBeforeMaterialUpdate; | ||
| const OnObjectUpdate = TSL.OnObjectUpdate; | ||
@@ -558,2 +563,3 @@ const OnMaterialUpdate = TSL.OnMaterialUpdate; | ||
| const textureSize = TSL.textureSize; | ||
| const textureLevel = TSL.textureLevel; | ||
| const textureStore = TSL.textureStore; | ||
@@ -635,5 +641,5 @@ const thickness = TSL.thickness; | ||
| console.log( code ); | ||
| log( code ); | ||
| //*/ | ||
| export { BRDF_GGX, BRDF_Lambert, BasicPointShadowFilter, BasicShadowFilter, Break, Const, Continue, DFGApprox, D_GGX, Discard, EPSILON, F_Schlick, Fn, INFINITY, If, Loop, NodeAccess, NodeShaderStage, NodeType, NodeUpdateType, OnMaterialUpdate, OnObjectUpdate, PCFShadowFilter, PCFSoftShadowFilter, PI, PI2, PointShadowFilter, Return, Schlick_to_F0, ScriptableNodeResources, ShaderNode, Stack, Switch, TBNViewMatrix, VSMShadowFilter, V_GGX_SmithCorrelated, Var, VarIntent, abs, acesFilmicToneMapping, acos, add, addMethodChaining, addNodeElement, agxToneMapping, all, alphaT, and, anisotropy, anisotropyB, anisotropyT, any, append, array, arrayBuffer, asin, assign, atan, atan2, atomicAdd, atomicAnd, atomicFunc, atomicLoad, atomicMax, atomicMin, atomicOr, atomicStore, atomicSub, atomicXor, attenuationColor, attenuationDistance, attribute, attributeArray, backgroundBlurriness, backgroundIntensity, backgroundRotation, batch, bentNormalView, billboarding, bitAnd, bitNot, bitOr, bitXor, bitangentGeometry, bitangentLocal, bitangentView, bitangentWorld, bitcast, blendBurn, blendColor, blendDodge, blendOverlay, blendScreen, blur, bool, buffer, bufferAttribute, builtin, bumpMap, burn, bvec2, bvec3, bvec4, bypass, cache, call, cameraFar, cameraIndex, cameraNear, cameraNormalMatrix, cameraPosition, cameraProjectionMatrix, cameraProjectionMatrixInverse, cameraViewMatrix, cameraViewport, cameraWorldMatrix, cbrt, cdl, ceil, checker, cineonToneMapping, clamp, clearcoat, clearcoatNormalView, clearcoatRoughness, code, color, colorSpaceToWorking, colorToDirection, compute, computeKernel, computeSkinning, context, convert, convertColorSpace, convertToTexture, cos, cross, cubeTexture, cubeTextureBase, cubeToUV, dFdx, dFdy, dashSize, debug, decrement, decrementBefore, defaultBuildStages, defaultShaderStages, defined, degrees, deltaTime, densityFog, densityFogFactor, depth, depthPass, determinant, difference, diffuseColor, directPointLight, directionToColor, directionToFaceDirection, dispersion, distance, div, dodge, dot, drawIndex, dynamicBufferAttribute, element, emissive, equal, equals, equirectUV, exp, exp2, expression, faceDirection, faceForward, faceforward, float, floatBitsToInt, floatBitsToUint, floor, fog, fract, frameGroup, frameId, frontFacing, fwidth, gain, gapSize, getConstNodeType, getCurrentStack, getDirection, getDistanceAttenuation, getGeometryRoughness, getNormalFromDepth, getParallaxCorrectNormal, getRoughness, getScreenPosition, getShIrradianceAt, getShadowMaterial, getShadowRenderObjectFunction, getTextureIndex, getViewPosition, globalId, glsl, glslFn, grayscale, greaterThan, greaterThanEqual, hash, highpModelNormalViewMatrix, highpModelViewMatrix, hue, increment, incrementBefore, instance, instanceIndex, instancedArray, instancedBufferAttribute, instancedDynamicBufferAttribute, instancedMesh, int, intBitsToFloat, inverse, inverseSqrt, inversesqrt, invocationLocalIndex, invocationSubgroupIndex, ior, iridescence, iridescenceIOR, iridescenceThickness, ivec2, ivec3, ivec4, js, label, length, lengthSq, lessThan, lessThanEqual, lightPosition, lightProjectionUV, lightShadowMatrix, lightTargetDirection, lightTargetPosition, lightViewPosition, lightingContext, lights, linearDepth, linearToneMapping, localId, log, log2, logarithmicDepthToViewZ, luminance, mat2, mat3, mat4, matcapUV, materialAO, materialAlphaTest, materialAnisotropy, materialAnisotropyVector, materialAttenuationColor, materialAttenuationDistance, materialClearcoat, materialClearcoatNormal, materialClearcoatRoughness, materialColor, materialDispersion, materialEmissive, materialEnvIntensity, materialEnvRotation, materialIOR, materialIridescence, materialIridescenceIOR, materialIridescenceThickness, materialLightMap, materialLineDashOffset, materialLineDashSize, materialLineGapSize, materialLineScale, materialLineWidth, materialMetalness, materialNormal, materialOpacity, materialPointSize, materialReference, materialReflectivity, materialRefractionRatio, materialRotation, materialRoughness, materialSheen, materialSheenRoughness, materialShininess, materialSpecular, materialSpecularColor, materialSpecularIntensity, materialSpecularStrength, materialThickness, materialTransmission, max, maxMipLevel, mediumpModelViewMatrix, metalness, min, mix, mixElement, mod, modInt, modelDirection, modelNormalMatrix, modelPosition, modelRadius, modelScale, modelViewMatrix, modelViewPosition, modelViewProjection, modelWorldMatrix, modelWorldMatrixInverse, morphReference, mrt, mul, mx_aastep, mx_add, mx_atan2, mx_cell_noise_float, mx_contrast, mx_divide, mx_fractal_noise_float, mx_fractal_noise_vec2, mx_fractal_noise_vec3, mx_fractal_noise_vec4, mx_frame, mx_heighttonormal, mx_hsvtorgb, mx_ifequal, mx_ifgreater, mx_ifgreatereq, mx_invert, mx_modulo, mx_multiply, mx_noise_float, mx_noise_vec3, mx_noise_vec4, mx_place2d, mx_power, mx_ramp4, mx_ramplr, mx_ramptb, mx_rgbtohsv, mx_rotate2d, mx_rotate3d, mx_safepower, mx_separate, mx_splitlr, mx_splittb, mx_srgb_texture_to_lin_rec709, mx_subtract, mx_timer, mx_transform_uv, mx_unifiednoise2d, mx_unifiednoise3d, mx_worley_noise_float, mx_worley_noise_vec2, mx_worley_noise_vec3, negate, neutralToneMapping, nodeArray, nodeImmutable, nodeObject, nodeObjectIntent, nodeObjects, nodeProxy, nodeProxyIntent, normalFlat, normalGeometry, normalLocal, normalMap, normalView, normalViewGeometry, normalWorld, normalWorldGeometry, normalize, not, notEqual, numWorkgroups, objectDirection, objectGroup, objectPosition, objectRadius, objectScale, objectViewPosition, objectWorldMatrix, oneMinus, or, orthographicDepthToViewZ, oscSawtooth, oscSine, oscSquare, oscTriangle, output, outputStruct, overlay, overloadingFn, parabola, parallaxDirection, parallaxUV, parameter, pass, passTexture, pcurve, perspectiveDepthToViewZ, pmremTexture, pointShadow, pointUV, pointWidth, positionGeometry, positionLocal, positionPrevious, positionView, positionViewDirection, positionWorld, positionWorldDirection, posterize, pow, pow2, pow3, pow4, premultiplyAlpha, property, radians, rand, range, rangeFog, rangeFogFactor, reciprocal, reference, referenceBuffer, reflect, reflectVector, reflectView, reflector, refract, refractVector, refractView, reinhardToneMapping, remap, remapClamp, renderGroup, renderOutput, rendererReference, rotate, rotateUV, roughness, round, rtt, sRGBTransferEOTF, sRGBTransferOETF, sample, sampler, samplerComparison, saturate, saturation, screen, screenCoordinate, screenDPR, screenSize, screenUV, scriptable, scriptableValue, select, setCurrentStack, setName, shaderStages, shadow, shadowPositionWorld, shapeCircle, sharedUniformGroup, sheen, sheenRoughness, shiftLeft, shiftRight, shininess, sign, sin, sinc, skinning, smoothstep, smoothstepElement, specularColor, specularF90, spherizeUV, split, spritesheetUV, sqrt, stack, step, stepElement, storage, storageBarrier, storageObject, storageTexture, string, struct, sub, subBuild, subgroupAdd, subgroupAll, subgroupAnd, subgroupAny, subgroupBallot, subgroupBroadcast, subgroupBroadcastFirst, subgroupElect, subgroupExclusiveAdd, subgroupExclusiveMul, subgroupInclusiveAdd, subgroupInclusiveMul, subgroupIndex, subgroupMax, subgroupMin, subgroupMul, subgroupOr, subgroupShuffle, subgroupShuffleDown, subgroupShuffleUp, subgroupShuffleXor, subgroupSize, subgroupXor, tan, tangentGeometry, tangentLocal, tangentView, tangentWorld, texture, texture3D, textureBarrier, textureBicubic, textureBicubicLevel, textureCubeUV, textureLoad, textureSize, textureStore, thickness, time, toneMapping, toneMappingExposure, toonOutlinePass, transformDirection, transformNormal, transformNormalToView, transformedClearcoatNormalView, transformedNormalView, transformedNormalWorld, transmission, transpose, triNoise3D, triplanarTexture, triplanarTextures, trunc, uint, uintBitsToFloat, uniform, uniformArray, uniformCubeTexture, uniformFlow, uniformGroup, uniformTexture, unpremultiplyAlpha, userData, uv, uvec2, uvec3, uvec4, varying, varyingProperty, vec2, vec3, vec4, vectorComponents, velocity, vertexColor, vertexIndex, vertexStage, vibrance, viewZToLogarithmicDepth, viewZToOrthographicDepth, viewZToPerspectiveDepth, viewport, viewportCoordinate, viewportDepthTexture, viewportLinearDepth, viewportMipTexture, viewportResolution, viewportSafeUV, viewportSharedTexture, viewportSize, viewportTexture, viewportUV, wgsl, wgslFn, workgroupArray, workgroupBarrier, workgroupId, workingToColorSpace, xor }; | ||
| export { BRDF_GGX, BRDF_Lambert, BasicPointShadowFilter, BasicShadowFilter, Break, Const, Continue, DFGApprox, D_GGX, Discard, EPSILON, F_Schlick, Fn, HALF_PI, INFINITY, If, Loop, NodeAccess, NodeShaderStage, NodeType, NodeUpdateType, OnBeforeMaterialUpdate, OnBeforeObjectUpdate, OnMaterialUpdate, OnObjectUpdate, PCFShadowFilter, PCFSoftShadowFilter, PI, PI2, PointShadowFilter, Return, Schlick_to_F0, ScriptableNodeResources, ShaderNode, Stack, Switch, TBNViewMatrix, TWO_PI, VSMShadowFilter, V_GGX_SmithCorrelated, Var, VarIntent, abs, acesFilmicToneMapping, acos, add, addMethodChaining, addNodeElement, agxToneMapping, all, alphaT, and, anisotropy, anisotropyB, anisotropyT, any, append, array, arrayBuffer, asin, assign, atan, atan2, atomicAdd, atomicAnd, atomicFunc, atomicLoad, atomicMax, atomicMin, atomicOr, atomicStore, atomicSub, atomicXor, attenuationColor, attenuationDistance, attribute, attributeArray, backgroundBlurriness, backgroundIntensity, backgroundRotation, batch, bentNormalView, billboarding, bitAnd, bitNot, bitOr, bitXor, bitangentGeometry, bitangentLocal, bitangentView, bitangentWorld, bitcast, blendBurn, blendColor, blendDodge, blendOverlay, blendScreen, blur, bool, buffer, bufferAttribute, builtin, bumpMap, burn, bvec2, bvec3, bvec4, bypass, cache, call, cameraFar, cameraIndex, cameraNear, cameraNormalMatrix, cameraPosition, cameraProjectionMatrix, cameraProjectionMatrixInverse, cameraViewMatrix, cameraViewport, cameraWorldMatrix, cbrt, cdl, ceil, checker, cineonToneMapping, clamp, clearcoat, clearcoatNormalView, clearcoatRoughness, code, color, colorSpaceToWorking, colorToDirection, compute, computeKernel, computeSkinning, context, convert, convertColorSpace, convertToTexture, cos, cross, cubeTexture, cubeTextureBase, cubeToUV, dFdx, dFdy, dashSize, debug, decrement, decrementBefore, defaultBuildStages, defaultShaderStages, defined, degrees, deltaTime, densityFog, densityFogFactor, depth, depthPass, determinant, difference, diffuseColor, directPointLight, directionToColor, directionToFaceDirection, dispersion, distance, div, dodge, dot, drawIndex, dynamicBufferAttribute, element, emissive, equal, equals, equirectUV, exp, exp2, expression, faceDirection, faceForward, faceforward, float, floatBitsToInt, floatBitsToUint, floor, fog, fract, frameGroup, frameId, frontFacing, fwidth, gain, gapSize, getConstNodeType, getCurrentStack, getDirection, getDistanceAttenuation, getGeometryRoughness, getNormalFromDepth, getParallaxCorrectNormal, getRoughness, getScreenPosition, getShIrradianceAt, getShadowMaterial, getShadowRenderObjectFunction, getTextureIndex, getViewPosition, globalId, glsl, glslFn, grayscale, greaterThan, greaterThanEqual, hash, highpModelNormalViewMatrix, highpModelViewMatrix, hue, increment, incrementBefore, instance, instanceIndex, instancedArray, instancedBufferAttribute, instancedDynamicBufferAttribute, instancedMesh, int, intBitsToFloat, interleavedGradientNoise, inverse, inverseSqrt, inversesqrt, invocationLocalIndex, invocationSubgroupIndex, ior, iridescence, iridescenceIOR, iridescenceThickness, ivec2, ivec3, ivec4, js, label, length, lengthSq, lessThan, lessThanEqual, lightPosition, lightProjectionUV, lightShadowMatrix, lightTargetDirection, lightTargetPosition, lightViewPosition, lightingContext, lights, linearDepth, linearToneMapping, localId, log, log2, logarithmicDepthToViewZ, luminance, mat2, mat3, mat4, matcapUV, materialAO, materialAlphaTest, materialAnisotropy, materialAnisotropyVector, materialAttenuationColor, materialAttenuationDistance, materialClearcoat, materialClearcoatNormal, materialClearcoatRoughness, materialColor, materialDispersion, materialEmissive, materialEnvIntensity, materialEnvRotation, materialIOR, materialIridescence, materialIridescenceIOR, materialIridescenceThickness, materialLightMap, materialLineDashOffset, materialLineDashSize, materialLineGapSize, materialLineScale, materialLineWidth, materialMetalness, materialNormal, materialOpacity, materialPointSize, materialReference, materialReflectivity, materialRefractionRatio, materialRotation, materialRoughness, materialSheen, materialSheenRoughness, materialShininess, materialSpecular, materialSpecularColor, materialSpecularIntensity, materialSpecularStrength, materialThickness, materialTransmission, max, maxMipLevel, mediumpModelViewMatrix, metalness, min, mix, mixElement, mod, modInt, modelDirection, modelNormalMatrix, modelPosition, modelRadius, modelScale, modelViewMatrix, modelViewPosition, modelViewProjection, modelWorldMatrix, modelWorldMatrixInverse, morphReference, mrt, mul, mx_aastep, mx_add, mx_atan2, mx_cell_noise_float, mx_contrast, mx_divide, mx_fractal_noise_float, mx_fractal_noise_vec2, mx_fractal_noise_vec3, mx_fractal_noise_vec4, mx_frame, mx_heighttonormal, mx_hsvtorgb, mx_ifequal, mx_ifgreater, mx_ifgreatereq, mx_invert, mx_modulo, mx_multiply, mx_noise_float, mx_noise_vec3, mx_noise_vec4, mx_place2d, mx_power, mx_ramp4, mx_ramplr, mx_ramptb, mx_rgbtohsv, mx_rotate2d, mx_rotate3d, mx_safepower, mx_separate, mx_splitlr, mx_splittb, mx_srgb_texture_to_lin_rec709, mx_subtract, mx_timer, mx_transform_uv, mx_unifiednoise2d, mx_unifiednoise3d, mx_worley_noise_float, mx_worley_noise_vec2, mx_worley_noise_vec3, negate, neutralToneMapping, nodeArray, nodeImmutable, nodeObject, nodeObjectIntent, nodeObjects, nodeProxy, nodeProxyIntent, normalFlat, normalGeometry, normalLocal, normalMap, normalView, normalViewGeometry, normalWorld, normalWorldGeometry, normalize, not, notEqual, numWorkgroups, objectDirection, objectGroup, objectPosition, objectRadius, objectScale, objectViewPosition, objectWorldMatrix, oneMinus, or, orthographicDepthToViewZ, oscSawtooth, oscSine, oscSquare, oscTriangle, output, outputStruct, overlay, overloadingFn, parabola, parallaxDirection, parallaxUV, parameter, pass, passTexture, pcurve, perspectiveDepthToViewZ, pmremTexture, pointShadow, pointUV, pointWidth, positionGeometry, positionLocal, positionPrevious, positionView, positionViewDirection, positionWorld, positionWorldDirection, posterize, pow, pow2, pow3, pow4, premultiplyAlpha, property, radians, rand, range, rangeFog, rangeFogFactor, reciprocal, reference, referenceBuffer, reflect, reflectVector, reflectView, reflector, refract, refractVector, refractView, reinhardToneMapping, remap, remapClamp, renderGroup, renderOutput, rendererReference, rotate, rotateUV, roughness, round, rtt, sRGBTransferEOTF, sRGBTransferOETF, sample, sampler, samplerComparison, saturate, saturation, screen, screenCoordinate, screenDPR, screenSize, screenUV, scriptable, scriptableValue, select, setCurrentStack, setName, shaderStages, shadow, shadowPositionWorld, shapeCircle, sharedUniformGroup, sheen, sheenRoughness, shiftLeft, shiftRight, shininess, sign, sin, sinc, skinning, smoothstep, smoothstepElement, specularColor, specularF90, spherizeUV, split, spritesheetUV, sqrt, stack, step, stepElement, storage, storageBarrier, storageObject, storageTexture, string, struct, sub, subBuild, subgroupAdd, subgroupAll, subgroupAnd, subgroupAny, subgroupBallot, subgroupBroadcast, subgroupBroadcastFirst, subgroupElect, subgroupExclusiveAdd, subgroupExclusiveMul, subgroupInclusiveAdd, subgroupInclusiveMul, subgroupIndex, subgroupMax, subgroupMin, subgroupMul, subgroupOr, subgroupShuffle, subgroupShuffleDown, subgroupShuffleUp, subgroupShuffleXor, subgroupSize, subgroupXor, tan, tangentGeometry, tangentLocal, tangentView, tangentWorld, texture, texture3D, textureBarrier, textureBicubic, textureBicubicLevel, textureCubeUV, textureLevel, textureLoad, textureSize, textureStore, thickness, time, toneMapping, toneMappingExposure, toonOutlinePass, transformDirection, transformNormal, transformNormalToView, transformedClearcoatNormalView, transformedNormalView, transformedNormalWorld, transmission, transpose, triNoise3D, triplanarTexture, triplanarTextures, trunc, uint, uintBitsToFloat, uniform, uniformArray, uniformCubeTexture, uniformFlow, uniformGroup, uniformTexture, unpremultiplyAlpha, userData, uv, uvec2, uvec3, uvec4, varying, varyingProperty, vec2, vec3, vec4, vectorComponents, velocity, vertexColor, vertexIndex, vertexStage, vibrance, viewZToLogarithmicDepth, viewZToOrthographicDepth, viewZToPerspectiveDepth, viewport, viewportCoordinate, viewportDepthTexture, viewportLinearDepth, viewportMipTexture, viewportResolution, viewportSafeUV, viewportSharedTexture, viewportSize, viewportTexture, viewportUV, wgsl, wgslFn, workgroupArray, workgroupBarrier, workgroupId, workingToColorSpace, xor }; |
@@ -6,2 +6,2 @@ /** | ||
| */ | ||
| import{TSL as e}from"three/webgpu";const t=e.BRDF_GGX,r=e.BRDF_Lambert,a=e.BasicPointShadowFilter,o=e.BasicShadowFilter,i=e.Break,n=e.Const,l=e.Continue,s=e.DFGApprox,c=e.D_GGX,m=e.Discard,u=e.EPSILON,p=e.F_Schlick,d=e.Fn,g=e.INFINITY,h=e.If,x=e.Loop,b=e.NodeAccess,f=e.NodeShaderStage,w=e.NodeType,v=e.NodeUpdateType,_=e.PCFShadowFilter,S=e.PCFSoftShadowFilter,T=e.PI,y=e.PI2,V=e.PointShadowFilter,M=e.Return,F=e.Schlick_to_F0,D=e.ScriptableNodeResources,I=e.ShaderNode,C=e.Stack,B=e.Switch,P=e.TBNViewMatrix,R=e.VSMShadowFilter,A=e.V_GGX_SmithCorrelated,N=e.Var,O=e.VarIntent,k=e.abs,G=e.acesFilmicToneMapping,L=e.acos,U=e.add,j=e.addMethodChaining,E=e.addNodeElement,W=e.agxToneMapping,q=e.all,z=e.alphaT,X=e.and,Z=e.anisotropy,K=e.anisotropyB,Y=e.anisotropyT,H=e.any,J=e.append,Q=e.array,$=e.arrayBuffer,ee=e.asin,te=e.assign,re=e.atan,ae=e.atan2,oe=e.atomicAdd,ie=e.atomicAnd,ne=e.atomicFunc,le=e.atomicLoad,se=e.atomicMax,ce=e.atomicMin,me=e.atomicOr,ue=e.atomicStore,pe=e.atomicSub,de=e.atomicXor,ge=e.attenuationColor,he=e.attenuationDistance,xe=e.attribute,be=e.attributeArray,fe=e.backgroundBlurriness,we=e.backgroundIntensity,ve=e.backgroundRotation,_e=e.batch,Se=e.bentNormalView,Te=e.billboarding,ye=e.bitAnd,Ve=e.bitNot,Me=e.bitOr,Fe=e.bitXor,De=e.bitangentGeometry,Ie=e.bitangentLocal,Ce=e.bitangentView,Be=e.bitangentWorld,Pe=e.bitcast,Re=e.blendBurn,Ae=e.blendColor,Ne=e.blendDodge,Oe=e.blendOverlay,ke=e.blendScreen,Ge=e.blur,Le=e.bool,Ue=e.buffer,je=e.bufferAttribute,Ee=e.bumpMap,We=e.burn,qe=e.builtin,ze=e.bvec2,Xe=e.bvec3,Ze=e.bvec4,Ke=e.bypass,Ye=e.cache,He=e.call,Je=e.cameraFar,Qe=e.cameraIndex,$e=e.cameraNear,et=e.cameraNormalMatrix,tt=e.cameraPosition,rt=e.cameraProjectionMatrix,at=e.cameraProjectionMatrixInverse,ot=e.cameraViewMatrix,it=e.cameraViewport,nt=e.cameraWorldMatrix,lt=e.cbrt,st=e.cdl,ct=e.ceil,mt=e.checker,ut=e.cineonToneMapping,pt=e.clamp,dt=e.clearcoat,gt=e.clearcoatNormalView,ht=e.clearcoatRoughness,xt=e.code,bt=e.color,ft=e.colorSpaceToWorking,wt=e.colorToDirection,vt=e.compute,_t=e.computeKernel,St=e.computeSkinning,Tt=e.context,yt=e.convert,Vt=e.convertColorSpace,Mt=e.convertToTexture,Ft=e.cos,Dt=e.cross,It=e.cubeTexture,Ct=e.cubeTextureBase,Bt=e.cubeToUV,Pt=e.dFdx,Rt=e.dFdy,At=e.dashSize,Nt=e.debug,Ot=e.decrement,kt=e.decrementBefore,Gt=e.defaultBuildStages,Lt=e.defaultShaderStages,Ut=e.defined,jt=e.degrees,Et=e.deltaTime,Wt=e.densityFog,qt=e.densityFogFactor,zt=e.depth,Xt=e.depthPass,Zt=e.determinant,Kt=e.difference,Yt=e.diffuseColor,Ht=e.directPointLight,Jt=e.directionToColor,Qt=e.directionToFaceDirection,$t=e.dispersion,er=e.distance,tr=e.div,rr=e.dodge,ar=e.dot,or=e.drawIndex,ir=e.dynamicBufferAttribute,nr=e.element,lr=e.emissive,sr=e.equal,cr=e.equals,mr=e.equirectUV,ur=e.exp,pr=e.exp2,dr=e.expression,gr=e.faceDirection,hr=e.faceForward,xr=e.faceforward,br=e.float,fr=e.floatBitsToInt,wr=e.floatBitsToUint,vr=e.floor,_r=e.fog,Sr=e.fract,Tr=e.frameGroup,yr=e.frameId,Vr=e.frontFacing,Mr=e.fwidth,Fr=e.gain,Dr=e.gapSize,Ir=e.getConstNodeType,Cr=e.getCurrentStack,Br=e.getDirection,Pr=e.getDistanceAttenuation,Rr=e.getGeometryRoughness,Ar=e.getNormalFromDepth,Nr=e.getParallaxCorrectNormal,Or=e.getRoughness,kr=e.getScreenPosition,Gr=e.getShIrradianceAt,Lr=e.getShadowMaterial,Ur=e.getShadowRenderObjectFunction,jr=e.getTextureIndex,Er=e.getViewPosition,Wr=e.globalId,qr=e.glsl,zr=e.glslFn,Xr=e.grayscale,Zr=e.greaterThan,Kr=e.greaterThanEqual,Yr=e.hash,Hr=e.highpModelNormalViewMatrix,Jr=e.highpModelViewMatrix,Qr=e.hue,$r=e.increment,ea=e.incrementBefore,ta=e.instance,ra=e.instanceIndex,aa=e.instancedArray,oa=e.instancedBufferAttribute,ia=e.instancedDynamicBufferAttribute,na=e.instancedMesh,la=e.int,sa=e.intBitsToFloat,ca=e.inverse,ma=e.inverseSqrt,ua=e.inversesqrt,pa=e.invocationLocalIndex,da=e.invocationSubgroupIndex,ga=e.ior,ha=e.iridescence,xa=e.iridescenceIOR,ba=e.iridescenceThickness,fa=e.ivec2,wa=e.ivec3,va=e.ivec4,_a=e.js,Sa=e.label,Ta=e.length,ya=e.lengthSq,Va=e.lessThan,Ma=e.lessThanEqual,Fa=e.lightPosition,Da=e.lightProjectionUV,Ia=e.lightShadowMatrix,Ca=e.lightTargetDirection,Ba=e.lightTargetPosition,Pa=e.lightViewPosition,Ra=e.lightingContext,Aa=e.lights,Na=e.linearDepth,Oa=e.linearToneMapping,ka=e.localId,Ga=e.log,La=e.log2,Ua=e.logarithmicDepthToViewZ,ja=e.luminance,Ea=e.mat2,Wa=e.mat3,qa=e.mat4,za=e.matcapUV,Xa=e.materialAO,Za=e.materialAlphaTest,Ka=e.materialAnisotropy,Ya=e.materialAnisotropyVector,Ha=e.materialAttenuationColor,Ja=e.materialAttenuationDistance,Qa=e.materialClearcoat,$a=e.materialClearcoatNormal,eo=e.materialClearcoatRoughness,to=e.materialColor,ro=e.materialDispersion,ao=e.materialEmissive,oo=e.materialEnvIntensity,io=e.materialEnvRotation,no=e.materialIOR,lo=e.materialIridescence,so=e.materialIridescenceIOR,co=e.materialIridescenceThickness,mo=e.materialLightMap,uo=e.materialLineDashOffset,po=e.materialLineDashSize,go=e.materialLineGapSize,ho=e.materialLineScale,xo=e.materialLineWidth,bo=e.materialMetalness,fo=e.materialNormal,wo=e.materialOpacity,vo=e.materialPointSize,_o=e.materialReference,So=e.materialReflectivity,To=e.materialRefractionRatio,yo=e.materialRotation,Vo=e.materialRoughness,Mo=e.materialSheen,Fo=e.materialSheenRoughness,Do=e.materialShininess,Io=e.materialSpecular,Co=e.materialSpecularColor,Bo=e.materialSpecularIntensity,Po=e.materialSpecularStrength,Ro=e.materialThickness,Ao=e.materialTransmission,No=e.max,Oo=e.maxMipLevel,ko=e.mediumpModelViewMatrix,Go=e.metalness,Lo=e.min,Uo=e.mix,jo=e.mixElement,Eo=e.mod,Wo=e.modInt,qo=e.modelDirection,zo=e.modelNormalMatrix,Xo=e.modelPosition,Zo=e.modelRadius,Ko=e.modelScale,Yo=e.modelViewMatrix,Ho=e.modelViewPosition,Jo=e.modelViewProjection,Qo=e.modelWorldMatrix,$o=e.modelWorldMatrixInverse,ei=e.morphReference,ti=e.mrt,ri=e.mul,ai=e.mx_aastep,oi=e.mx_add,ii=e.mx_atan2,ni=e.mx_cell_noise_float,li=e.mx_contrast,si=e.mx_divide,ci=e.mx_fractal_noise_float,mi=e.mx_fractal_noise_vec2,ui=e.mx_fractal_noise_vec3,pi=e.mx_fractal_noise_vec4,di=e.mx_frame,gi=e.mx_heighttonormal,hi=e.mx_hsvtorgb,xi=e.mx_ifequal,bi=e.mx_ifgreater,fi=e.mx_ifgreatereq,wi=e.mx_invert,vi=e.mx_modulo,_i=e.mx_multiply,Si=e.mx_noise_float,Ti=e.mx_noise_vec3,yi=e.mx_noise_vec4,Vi=e.mx_place2d,Mi=e.mx_power,Fi=e.mx_ramp4,Di=e.mx_ramplr,Ii=e.mx_ramptb,Ci=e.mx_rgbtohsv,Bi=e.mx_rotate2d,Pi=e.mx_rotate3d,Ri=e.mx_safepower,Ai=e.mx_separate,Ni=e.mx_splitlr,Oi=e.mx_splittb,ki=e.mx_srgb_texture_to_lin_rec709,Gi=e.mx_subtract,Li=e.mx_timer,Ui=e.mx_transform_uv,ji=e.mx_unifiednoise2d,Ei=e.mx_unifiednoise3d,Wi=e.mx_worley_noise_float,qi=e.mx_worley_noise_vec2,zi=e.mx_worley_noise_vec3,Xi=e.negate,Zi=e.neutralToneMapping,Ki=e.nodeArray,Yi=e.nodeImmutable,Hi=e.nodeObject,Ji=e.nodeObjectIntent,Qi=e.nodeObjects,$i=e.nodeProxy,en=e.nodeProxyIntent,tn=e.normalFlat,rn=e.normalGeometry,an=e.normalLocal,on=e.normalMap,nn=e.normalView,ln=e.normalViewGeometry,sn=e.normalWorld,cn=e.normalWorldGeometry,mn=e.normalize,un=e.not,pn=e.notEqual,dn=e.numWorkgroups,gn=e.objectDirection,hn=e.objectGroup,xn=e.objectPosition,bn=e.objectRadius,fn=e.objectScale,wn=e.objectViewPosition,vn=e.objectWorldMatrix,_n=e.OnObjectUpdate,Sn=e.OnMaterialUpdate,Tn=e.oneMinus,yn=e.or,Vn=e.orthographicDepthToViewZ,Mn=e.oscSawtooth,Fn=e.oscSine,Dn=e.oscSquare,In=e.oscTriangle,Cn=e.output,Bn=e.outputStruct,Pn=e.overlay,Rn=e.overloadingFn,An=e.parabola,Nn=e.parallaxDirection,On=e.parallaxUV,kn=e.parameter,Gn=e.pass,Ln=e.passTexture,Un=e.pcurve,jn=e.perspectiveDepthToViewZ,En=e.pmremTexture,Wn=e.pointShadow,qn=e.pointUV,zn=e.pointWidth,Xn=e.positionGeometry,Zn=e.positionLocal,Kn=e.positionPrevious,Yn=e.positionView,Hn=e.positionViewDirection,Jn=e.positionWorld,Qn=e.positionWorldDirection,$n=e.posterize,el=e.pow,tl=e.pow2,rl=e.pow3,al=e.pow4,ol=e.premultiplyAlpha,il=e.property,nl=e.radians,ll=e.rand,sl=e.range,cl=e.rangeFog,ml=e.rangeFogFactor,ul=e.reciprocal,pl=e.reference,dl=e.referenceBuffer,gl=e.reflect,hl=e.reflectVector,xl=e.reflectView,bl=e.reflector,fl=e.refract,wl=e.refractVector,vl=e.refractView,_l=e.reinhardToneMapping,Sl=e.remap,Tl=e.remapClamp,yl=e.renderGroup,Vl=e.renderOutput,Ml=e.rendererReference,Fl=e.rotate,Dl=e.rotateUV,Il=e.roughness,Cl=e.round,Bl=e.rtt,Pl=e.sRGBTransferEOTF,Rl=e.sRGBTransferOETF,Al=e.sample,Nl=e.sampler,Ol=e.samplerComparison,kl=e.saturate,Gl=e.saturation,Ll=e.screen,Ul=e.screenCoordinate,jl=e.screenDPR,El=e.screenSize,Wl=e.screenUV,ql=e.scriptable,zl=e.scriptableValue,Xl=e.select,Zl=e.setCurrentStack,Kl=e.setName,Yl=e.shaderStages,Hl=e.shadow,Jl=e.shadowPositionWorld,Ql=e.shapeCircle,$l=e.sharedUniformGroup,es=e.sheen,ts=e.sheenRoughness,rs=e.shiftLeft,as=e.shiftRight,os=e.shininess,is=e.sign,ns=e.sin,ls=e.sinc,ss=e.skinning,cs=e.smoothstep,ms=e.smoothstepElement,us=e.specularColor,ps=e.specularF90,ds=e.spherizeUV,gs=e.split,hs=e.spritesheetUV,xs=e.sqrt,bs=e.stack,fs=e.step,ws=e.stepElement,vs=e.storage,_s=e.storageBarrier,Ss=e.storageObject,Ts=e.storageTexture,ys=e.string,Vs=e.struct,Ms=e.sub,Fs=e.subgroupAdd,Ds=e.subgroupAll,Is=e.subgroupAnd,Cs=e.subgroupAny,Bs=e.subgroupBallot,Ps=e.subgroupBroadcast,Rs=e.subgroupBroadcastFirst,As=e.subBuild,Ns=e.subgroupElect,Os=e.subgroupExclusiveAdd,ks=e.subgroupExclusiveMul,Gs=e.subgroupInclusiveAdd,Ls=e.subgroupInclusiveMul,Us=e.subgroupIndex,js=e.subgroupMax,Es=e.subgroupMin,Ws=e.subgroupMul,qs=e.subgroupOr,zs=e.subgroupShuffle,Xs=e.subgroupShuffleDown,Zs=e.subgroupShuffleUp,Ks=e.subgroupShuffleXor,Ys=e.subgroupSize,Hs=e.subgroupXor,Js=e.tan,Qs=e.tangentGeometry,$s=e.tangentLocal,ec=e.tangentView,tc=e.tangentWorld,rc=e.texture,ac=e.texture3D,oc=e.textureBarrier,ic=e.textureBicubic,nc=e.textureBicubicLevel,lc=e.textureCubeUV,sc=e.textureLoad,cc=e.textureSize,mc=e.textureStore,uc=e.thickness,pc=e.time,dc=e.toneMapping,gc=e.toneMappingExposure,hc=e.toonOutlinePass,xc=e.transformDirection,bc=e.transformNormal,fc=e.transformNormalToView,wc=e.transformedClearcoatNormalView,vc=e.transformedNormalView,_c=e.transformedNormalWorld,Sc=e.transmission,Tc=e.transpose,yc=e.triNoise3D,Vc=e.triplanarTexture,Mc=e.triplanarTextures,Fc=e.trunc,Dc=e.uint,Ic=e.uintBitsToFloat,Cc=e.uniform,Bc=e.uniformArray,Pc=e.uniformCubeTexture,Rc=e.uniformGroup,Ac=e.uniformFlow,Nc=e.uniformTexture,Oc=e.unpremultiplyAlpha,kc=e.userData,Gc=e.uv,Lc=e.uvec2,Uc=e.uvec3,jc=e.uvec4,Ec=e.varying,Wc=e.varyingProperty,qc=e.vec2,zc=e.vec3,Xc=e.vec4,Zc=e.vectorComponents,Kc=e.velocity,Yc=e.vertexColor,Hc=e.vertexIndex,Jc=e.vertexStage,Qc=e.vibrance,$c=e.viewZToLogarithmicDepth,em=e.viewZToOrthographicDepth,tm=e.viewZToPerspectiveDepth,rm=e.viewport,am=e.viewportCoordinate,om=e.viewportDepthTexture,im=e.viewportLinearDepth,nm=e.viewportMipTexture,lm=e.viewportResolution,sm=e.viewportSafeUV,cm=e.viewportSharedTexture,mm=e.viewportSize,um=e.viewportTexture,pm=e.viewportUV,dm=e.wgsl,gm=e.wgslFn,hm=e.workgroupArray,xm=e.workgroupBarrier,bm=e.workgroupId,fm=e.workingToColorSpace,wm=e.xor;export{t as BRDF_GGX,r as BRDF_Lambert,a as BasicPointShadowFilter,o as BasicShadowFilter,i as Break,n as Const,l as Continue,s as DFGApprox,c as D_GGX,m as Discard,u as EPSILON,p as F_Schlick,d as Fn,g as INFINITY,h as If,x as Loop,b as NodeAccess,f as NodeShaderStage,w as NodeType,v as NodeUpdateType,Sn as OnMaterialUpdate,_n as OnObjectUpdate,_ as PCFShadowFilter,S as PCFSoftShadowFilter,T as PI,y as PI2,V as PointShadowFilter,M as Return,F as Schlick_to_F0,D as ScriptableNodeResources,I as ShaderNode,C as Stack,B as Switch,P as TBNViewMatrix,R as VSMShadowFilter,A as V_GGX_SmithCorrelated,N as Var,O as VarIntent,k as abs,G as acesFilmicToneMapping,L as acos,U as add,j as addMethodChaining,E as addNodeElement,W as agxToneMapping,q as all,z as alphaT,X as and,Z as anisotropy,K as anisotropyB,Y as anisotropyT,H as any,J as append,Q as array,$ as arrayBuffer,ee as asin,te as assign,re as atan,ae as atan2,oe as atomicAdd,ie as atomicAnd,ne as atomicFunc,le as atomicLoad,se as atomicMax,ce as atomicMin,me as atomicOr,ue as atomicStore,pe as atomicSub,de as atomicXor,ge as attenuationColor,he as attenuationDistance,xe as attribute,be as attributeArray,fe as backgroundBlurriness,we as backgroundIntensity,ve as backgroundRotation,_e as batch,Se as bentNormalView,Te as billboarding,ye as bitAnd,Ve as bitNot,Me as bitOr,Fe as bitXor,De as bitangentGeometry,Ie as bitangentLocal,Ce as bitangentView,Be as bitangentWorld,Pe as bitcast,Re as blendBurn,Ae as blendColor,Ne as blendDodge,Oe as blendOverlay,ke as blendScreen,Ge as blur,Le as bool,Ue as buffer,je as bufferAttribute,qe as builtin,Ee as bumpMap,We as burn,ze as bvec2,Xe as bvec3,Ze as bvec4,Ke as bypass,Ye as cache,He as call,Je as cameraFar,Qe as cameraIndex,$e as cameraNear,et as cameraNormalMatrix,tt as cameraPosition,rt as cameraProjectionMatrix,at as cameraProjectionMatrixInverse,ot as cameraViewMatrix,it as cameraViewport,nt as cameraWorldMatrix,lt as cbrt,st as cdl,ct as ceil,mt as checker,ut as cineonToneMapping,pt as clamp,dt as clearcoat,gt as clearcoatNormalView,ht as clearcoatRoughness,xt as code,bt as color,ft as colorSpaceToWorking,wt as colorToDirection,vt as compute,_t as computeKernel,St as computeSkinning,Tt as context,yt as convert,Vt as convertColorSpace,Mt as convertToTexture,Ft as cos,Dt as cross,It as cubeTexture,Ct as cubeTextureBase,Bt as cubeToUV,Pt as dFdx,Rt as dFdy,At as dashSize,Nt as debug,Ot as decrement,kt as decrementBefore,Gt as defaultBuildStages,Lt as defaultShaderStages,Ut as defined,jt as degrees,Et as deltaTime,Wt as densityFog,qt as densityFogFactor,zt as depth,Xt as depthPass,Zt as determinant,Kt as difference,Yt as diffuseColor,Ht as directPointLight,Jt as directionToColor,Qt as directionToFaceDirection,$t as dispersion,er as distance,tr as div,rr as dodge,ar as dot,or as drawIndex,ir as dynamicBufferAttribute,nr as element,lr as emissive,sr as equal,cr as equals,mr as equirectUV,ur as exp,pr as exp2,dr as expression,gr as faceDirection,hr as faceForward,xr as faceforward,br as float,fr as floatBitsToInt,wr as floatBitsToUint,vr as floor,_r as fog,Sr as fract,Tr as frameGroup,yr as frameId,Vr as frontFacing,Mr as fwidth,Fr as gain,Dr as gapSize,Ir as getConstNodeType,Cr as getCurrentStack,Br as getDirection,Pr as getDistanceAttenuation,Rr as getGeometryRoughness,Ar as getNormalFromDepth,Nr as getParallaxCorrectNormal,Or as getRoughness,kr as getScreenPosition,Gr as getShIrradianceAt,Lr as getShadowMaterial,Ur as getShadowRenderObjectFunction,jr as getTextureIndex,Er as getViewPosition,Wr as globalId,qr as glsl,zr as glslFn,Xr as grayscale,Zr as greaterThan,Kr as greaterThanEqual,Yr as hash,Hr as highpModelNormalViewMatrix,Jr as highpModelViewMatrix,Qr as hue,$r as increment,ea as incrementBefore,ta as instance,ra as instanceIndex,aa as instancedArray,oa as instancedBufferAttribute,ia as instancedDynamicBufferAttribute,na as instancedMesh,la as int,sa as intBitsToFloat,ca as inverse,ma as inverseSqrt,ua as inversesqrt,pa as invocationLocalIndex,da as invocationSubgroupIndex,ga as ior,ha as iridescence,xa as iridescenceIOR,ba as iridescenceThickness,fa as ivec2,wa as ivec3,va as ivec4,_a as js,Sa as label,Ta as length,ya as lengthSq,Va as lessThan,Ma as lessThanEqual,Fa as lightPosition,Da as lightProjectionUV,Ia as lightShadowMatrix,Ca as lightTargetDirection,Ba as lightTargetPosition,Pa as lightViewPosition,Ra as lightingContext,Aa as lights,Na as linearDepth,Oa as linearToneMapping,ka as localId,Ga as log,La as log2,Ua as logarithmicDepthToViewZ,ja as luminance,Ea as mat2,Wa as mat3,qa as mat4,za as matcapUV,Xa as materialAO,Za as materialAlphaTest,Ka as materialAnisotropy,Ya as materialAnisotropyVector,Ha as materialAttenuationColor,Ja as materialAttenuationDistance,Qa as materialClearcoat,$a as materialClearcoatNormal,eo as materialClearcoatRoughness,to as materialColor,ro as materialDispersion,ao as materialEmissive,oo as materialEnvIntensity,io as materialEnvRotation,no as materialIOR,lo as materialIridescence,so as materialIridescenceIOR,co as materialIridescenceThickness,mo as materialLightMap,uo as materialLineDashOffset,po as materialLineDashSize,go as materialLineGapSize,ho as materialLineScale,xo as materialLineWidth,bo as materialMetalness,fo as materialNormal,wo as materialOpacity,vo as materialPointSize,_o as materialReference,So as materialReflectivity,To as materialRefractionRatio,yo as materialRotation,Vo as materialRoughness,Mo as materialSheen,Fo as materialSheenRoughness,Do as materialShininess,Io as materialSpecular,Co as materialSpecularColor,Bo as materialSpecularIntensity,Po as materialSpecularStrength,Ro as materialThickness,Ao as materialTransmission,No as max,Oo as maxMipLevel,ko as mediumpModelViewMatrix,Go as metalness,Lo as min,Uo as mix,jo as mixElement,Eo as mod,Wo as modInt,qo as modelDirection,zo as modelNormalMatrix,Xo as modelPosition,Zo as modelRadius,Ko as modelScale,Yo as modelViewMatrix,Ho as modelViewPosition,Jo as modelViewProjection,Qo as modelWorldMatrix,$o as modelWorldMatrixInverse,ei as morphReference,ti as mrt,ri as mul,ai as mx_aastep,oi as mx_add,ii as mx_atan2,ni as mx_cell_noise_float,li as mx_contrast,si as mx_divide,ci as mx_fractal_noise_float,mi as mx_fractal_noise_vec2,ui as mx_fractal_noise_vec3,pi as mx_fractal_noise_vec4,di as mx_frame,gi as mx_heighttonormal,hi as mx_hsvtorgb,xi as mx_ifequal,bi as mx_ifgreater,fi as mx_ifgreatereq,wi as mx_invert,vi as mx_modulo,_i as mx_multiply,Si as mx_noise_float,Ti as mx_noise_vec3,yi as mx_noise_vec4,Vi as mx_place2d,Mi as mx_power,Fi as mx_ramp4,Di as mx_ramplr,Ii as mx_ramptb,Ci as mx_rgbtohsv,Bi as mx_rotate2d,Pi as mx_rotate3d,Ri as mx_safepower,Ai as mx_separate,Ni as mx_splitlr,Oi as mx_splittb,ki as mx_srgb_texture_to_lin_rec709,Gi as mx_subtract,Li as mx_timer,Ui as mx_transform_uv,ji as mx_unifiednoise2d,Ei as mx_unifiednoise3d,Wi as mx_worley_noise_float,qi as mx_worley_noise_vec2,zi as mx_worley_noise_vec3,Xi as negate,Zi as neutralToneMapping,Ki as nodeArray,Yi as nodeImmutable,Hi as nodeObject,Ji as nodeObjectIntent,Qi as nodeObjects,$i as nodeProxy,en as nodeProxyIntent,tn as normalFlat,rn as normalGeometry,an as normalLocal,on as normalMap,nn as normalView,ln as normalViewGeometry,sn as normalWorld,cn as normalWorldGeometry,mn as normalize,un as not,pn as notEqual,dn as numWorkgroups,gn as objectDirection,hn as objectGroup,xn as objectPosition,bn as objectRadius,fn as objectScale,wn as objectViewPosition,vn as objectWorldMatrix,Tn as oneMinus,yn as or,Vn as orthographicDepthToViewZ,Mn as oscSawtooth,Fn as oscSine,Dn as oscSquare,In as oscTriangle,Cn as output,Bn as outputStruct,Pn as overlay,Rn as overloadingFn,An as parabola,Nn as parallaxDirection,On as parallaxUV,kn as parameter,Gn as pass,Ln as passTexture,Un as pcurve,jn as perspectiveDepthToViewZ,En as pmremTexture,Wn as pointShadow,qn as pointUV,zn as pointWidth,Xn as positionGeometry,Zn as positionLocal,Kn as positionPrevious,Yn as positionView,Hn as positionViewDirection,Jn as positionWorld,Qn as positionWorldDirection,$n as posterize,el as pow,tl as pow2,rl as pow3,al as pow4,ol as premultiplyAlpha,il as property,nl as radians,ll as rand,sl as range,cl as rangeFog,ml as rangeFogFactor,ul as reciprocal,pl as reference,dl as referenceBuffer,gl as reflect,hl as reflectVector,xl as reflectView,bl as reflector,fl as refract,wl as refractVector,vl as refractView,_l as reinhardToneMapping,Sl as remap,Tl as remapClamp,yl as renderGroup,Vl as renderOutput,Ml as rendererReference,Fl as rotate,Dl as rotateUV,Il as roughness,Cl as round,Bl as rtt,Pl as sRGBTransferEOTF,Rl as sRGBTransferOETF,Al as sample,Nl as sampler,Ol as samplerComparison,kl as saturate,Gl as saturation,Ll as screen,Ul as screenCoordinate,jl as screenDPR,El as screenSize,Wl as screenUV,ql as scriptable,zl as scriptableValue,Xl as select,Zl as setCurrentStack,Kl as setName,Yl as shaderStages,Hl as shadow,Jl as shadowPositionWorld,Ql as shapeCircle,$l as sharedUniformGroup,es as sheen,ts as sheenRoughness,rs as shiftLeft,as as shiftRight,os as shininess,is as sign,ns as sin,ls as sinc,ss as skinning,cs as smoothstep,ms as smoothstepElement,us as specularColor,ps as specularF90,ds as spherizeUV,gs as split,hs as spritesheetUV,xs as sqrt,bs as stack,fs as step,ws as stepElement,vs as storage,_s as storageBarrier,Ss as storageObject,Ts as storageTexture,ys as string,Vs as struct,Ms as sub,As as subBuild,Fs as subgroupAdd,Ds as subgroupAll,Is as subgroupAnd,Cs as subgroupAny,Bs as subgroupBallot,Ps as subgroupBroadcast,Rs as subgroupBroadcastFirst,Ns as subgroupElect,Os as subgroupExclusiveAdd,ks as subgroupExclusiveMul,Gs as subgroupInclusiveAdd,Ls as subgroupInclusiveMul,Us as subgroupIndex,js as subgroupMax,Es as subgroupMin,Ws as subgroupMul,qs as subgroupOr,zs as subgroupShuffle,Xs as subgroupShuffleDown,Zs as subgroupShuffleUp,Ks as subgroupShuffleXor,Ys as subgroupSize,Hs as subgroupXor,Js as tan,Qs as tangentGeometry,$s as tangentLocal,ec as tangentView,tc as tangentWorld,rc as texture,ac as texture3D,oc as textureBarrier,ic as textureBicubic,nc as textureBicubicLevel,lc as textureCubeUV,sc as textureLoad,cc as textureSize,mc as textureStore,uc as thickness,pc as time,dc as toneMapping,gc as toneMappingExposure,hc as toonOutlinePass,xc as transformDirection,bc as transformNormal,fc as transformNormalToView,wc as transformedClearcoatNormalView,vc as transformedNormalView,_c as transformedNormalWorld,Sc as transmission,Tc as transpose,yc as triNoise3D,Vc as triplanarTexture,Mc as triplanarTextures,Fc as trunc,Dc as uint,Ic as uintBitsToFloat,Cc as uniform,Bc as uniformArray,Pc as uniformCubeTexture,Ac as uniformFlow,Rc as uniformGroup,Nc as uniformTexture,Oc as unpremultiplyAlpha,kc as userData,Gc as uv,Lc as uvec2,Uc as uvec3,jc as uvec4,Ec as varying,Wc as varyingProperty,qc as vec2,zc as vec3,Xc as vec4,Zc as vectorComponents,Kc as velocity,Yc as vertexColor,Hc as vertexIndex,Jc as vertexStage,Qc as vibrance,$c as viewZToLogarithmicDepth,em as viewZToOrthographicDepth,tm as viewZToPerspectiveDepth,rm as viewport,am as viewportCoordinate,om as viewportDepthTexture,im as viewportLinearDepth,nm as viewportMipTexture,lm as viewportResolution,sm as viewportSafeUV,cm as viewportSharedTexture,mm as viewportSize,um as viewportTexture,pm as viewportUV,dm as wgsl,gm as wgslFn,hm as workgroupArray,xm as workgroupBarrier,bm as workgroupId,fm as workingToColorSpace,wm as xor}; | ||
| import{TSL as e}from"three/webgpu";const t=e.BRDF_GGX,r=e.BRDF_Lambert,a=e.BasicPointShadowFilter,o=e.BasicShadowFilter,i=e.Break,n=e.Const,l=e.Continue,s=e.DFGApprox,c=e.D_GGX,m=e.Discard,u=e.EPSILON,p=e.F_Schlick,d=e.Fn,g=e.INFINITY,h=e.If,x=e.Loop,b=e.NodeAccess,f=e.NodeShaderStage,v=e.NodeType,w=e.NodeUpdateType,_=e.PCFShadowFilter,S=e.PCFSoftShadowFilter,T=e.PI,y=e.PI2,V=e.TWO_PI,M=e.HALF_PI,F=e.PointShadowFilter,I=e.Return,D=e.Schlick_to_F0,B=e.ScriptableNodeResources,P=e.ShaderNode,C=e.Stack,A=e.Switch,N=e.TBNViewMatrix,R=e.VSMShadowFilter,O=e.V_GGX_SmithCorrelated,L=e.Var,k=e.VarIntent,G=e.abs,U=e.acesFilmicToneMapping,j=e.acos,E=e.add,W=e.addMethodChaining,q=e.addNodeElement,z=e.agxToneMapping,X=e.all,Z=e.alphaT,H=e.and,K=e.anisotropy,Y=e.anisotropyB,J=e.anisotropyT,Q=e.any,$=e.append,ee=e.array,te=e.arrayBuffer,re=e.asin,ae=e.assign,oe=e.atan,ie=e.atan2,ne=e.atomicAdd,le=e.atomicAnd,se=e.atomicFunc,ce=e.atomicLoad,me=e.atomicMax,ue=e.atomicMin,pe=e.atomicOr,de=e.atomicStore,ge=e.atomicSub,he=e.atomicXor,xe=e.attenuationColor,be=e.attenuationDistance,fe=e.attribute,ve=e.attributeArray,we=e.backgroundBlurriness,_e=e.backgroundIntensity,Se=e.backgroundRotation,Te=e.batch,ye=e.bentNormalView,Ve=e.billboarding,Me=e.bitAnd,Fe=e.bitNot,Ie=e.bitOr,De=e.bitXor,Be=e.bitangentGeometry,Pe=e.bitangentLocal,Ce=e.bitangentView,Ae=e.bitangentWorld,Ne=e.bitcast,Re=e.blendBurn,Oe=e.blendColor,Le=e.blendDodge,ke=e.blendOverlay,Ge=e.blendScreen,Ue=e.blur,je=e.bool,Ee=e.buffer,We=e.bufferAttribute,qe=e.bumpMap,ze=e.burn,Xe=e.builtin,Ze=e.bvec2,He=e.bvec3,Ke=e.bvec4,Ye=e.bypass,Je=e.cache,Qe=e.call,$e=e.cameraFar,et=e.cameraIndex,tt=e.cameraNear,rt=e.cameraNormalMatrix,at=e.cameraPosition,ot=e.cameraProjectionMatrix,it=e.cameraProjectionMatrixInverse,nt=e.cameraViewMatrix,lt=e.cameraViewport,st=e.cameraWorldMatrix,ct=e.cbrt,mt=e.cdl,ut=e.ceil,pt=e.checker,dt=e.cineonToneMapping,gt=e.clamp,ht=e.clearcoat,xt=e.clearcoatNormalView,bt=e.clearcoatRoughness,ft=e.code,vt=e.color,wt=e.colorSpaceToWorking,_t=e.colorToDirection,St=e.compute,Tt=e.computeKernel,yt=e.computeSkinning,Vt=e.context,Mt=e.convert,Ft=e.convertColorSpace,It=e.convertToTexture,Dt=e.cos,Bt=e.cross,Pt=e.cubeTexture,Ct=e.cubeTextureBase,At=e.cubeToUV,Nt=e.dFdx,Rt=e.dFdy,Ot=e.dashSize,Lt=e.debug,kt=e.decrement,Gt=e.decrementBefore,Ut=e.defaultBuildStages,jt=e.defaultShaderStages,Et=e.defined,Wt=e.degrees,qt=e.deltaTime,zt=e.densityFog,Xt=e.densityFogFactor,Zt=e.depth,Ht=e.depthPass,Kt=e.determinant,Yt=e.difference,Jt=e.diffuseColor,Qt=e.directPointLight,$t=e.directionToColor,er=e.directionToFaceDirection,tr=e.dispersion,rr=e.distance,ar=e.div,or=e.dodge,ir=e.dot,nr=e.drawIndex,lr=e.dynamicBufferAttribute,sr=e.element,cr=e.emissive,mr=e.equal,ur=e.equals,pr=e.equirectUV,dr=e.exp,gr=e.exp2,hr=e.expression,xr=e.faceDirection,br=e.faceForward,fr=e.faceforward,vr=e.float,wr=e.floatBitsToInt,_r=e.floatBitsToUint,Sr=e.floor,Tr=e.fog,yr=e.fract,Vr=e.frameGroup,Mr=e.frameId,Fr=e.frontFacing,Ir=e.fwidth,Dr=e.gain,Br=e.gapSize,Pr=e.getConstNodeType,Cr=e.getCurrentStack,Ar=e.getDirection,Nr=e.getDistanceAttenuation,Rr=e.getGeometryRoughness,Or=e.getNormalFromDepth,Lr=e.interleavedGradientNoise,kr=e.getParallaxCorrectNormal,Gr=e.getRoughness,Ur=e.getScreenPosition,jr=e.getShIrradianceAt,Er=e.getShadowMaterial,Wr=e.getShadowRenderObjectFunction,qr=e.getTextureIndex,zr=e.getViewPosition,Xr=e.globalId,Zr=e.glsl,Hr=e.glslFn,Kr=e.grayscale,Yr=e.greaterThan,Jr=e.greaterThanEqual,Qr=e.hash,$r=e.highpModelNormalViewMatrix,ea=e.highpModelViewMatrix,ta=e.hue,ra=e.increment,aa=e.incrementBefore,oa=e.instance,ia=e.instanceIndex,na=e.instancedArray,la=e.instancedBufferAttribute,sa=e.instancedDynamicBufferAttribute,ca=e.instancedMesh,ma=e.int,ua=e.intBitsToFloat,pa=e.inverse,da=e.inverseSqrt,ga=e.inversesqrt,ha=e.invocationLocalIndex,xa=e.invocationSubgroupIndex,ba=e.ior,fa=e.iridescence,va=e.iridescenceIOR,wa=e.iridescenceThickness,_a=e.ivec2,Sa=e.ivec3,Ta=e.ivec4,ya=e.js,Va=e.label,Ma=e.length,Fa=e.lengthSq,Ia=e.lessThan,Da=e.lessThanEqual,Ba=e.lightPosition,Pa=e.lightProjectionUV,Ca=e.lightShadowMatrix,Aa=e.lightTargetDirection,Na=e.lightTargetPosition,Ra=e.lightViewPosition,Oa=e.lightingContext,La=e.lights,ka=e.linearDepth,Ga=e.linearToneMapping,Ua=e.localId,ja=e.log,Ea=e.log2,Wa=e.logarithmicDepthToViewZ,qa=e.luminance,za=e.mat2,Xa=e.mat3,Za=e.mat4,Ha=e.matcapUV,Ka=e.materialAO,Ya=e.materialAlphaTest,Ja=e.materialAnisotropy,Qa=e.materialAnisotropyVector,$a=e.materialAttenuationColor,eo=e.materialAttenuationDistance,to=e.materialClearcoat,ro=e.materialClearcoatNormal,ao=e.materialClearcoatRoughness,oo=e.materialColor,io=e.materialDispersion,no=e.materialEmissive,lo=e.materialEnvIntensity,so=e.materialEnvRotation,co=e.materialIOR,mo=e.materialIridescence,uo=e.materialIridescenceIOR,po=e.materialIridescenceThickness,go=e.materialLightMap,ho=e.materialLineDashOffset,xo=e.materialLineDashSize,bo=e.materialLineGapSize,fo=e.materialLineScale,vo=e.materialLineWidth,wo=e.materialMetalness,_o=e.materialNormal,So=e.materialOpacity,To=e.materialPointSize,yo=e.materialReference,Vo=e.materialReflectivity,Mo=e.materialRefractionRatio,Fo=e.materialRotation,Io=e.materialRoughness,Do=e.materialSheen,Bo=e.materialSheenRoughness,Po=e.materialShininess,Co=e.materialSpecular,Ao=e.materialSpecularColor,No=e.materialSpecularIntensity,Ro=e.materialSpecularStrength,Oo=e.materialThickness,Lo=e.materialTransmission,ko=e.max,Go=e.maxMipLevel,Uo=e.mediumpModelViewMatrix,jo=e.metalness,Eo=e.min,Wo=e.mix,qo=e.mixElement,zo=e.mod,Xo=e.modInt,Zo=e.modelDirection,Ho=e.modelNormalMatrix,Ko=e.modelPosition,Yo=e.modelRadius,Jo=e.modelScale,Qo=e.modelViewMatrix,$o=e.modelViewPosition,ei=e.modelViewProjection,ti=e.modelWorldMatrix,ri=e.modelWorldMatrixInverse,ai=e.morphReference,oi=e.mrt,ii=e.mul,ni=e.mx_aastep,li=e.mx_add,si=e.mx_atan2,ci=e.mx_cell_noise_float,mi=e.mx_contrast,ui=e.mx_divide,pi=e.mx_fractal_noise_float,di=e.mx_fractal_noise_vec2,gi=e.mx_fractal_noise_vec3,hi=e.mx_fractal_noise_vec4,xi=e.mx_frame,bi=e.mx_heighttonormal,fi=e.mx_hsvtorgb,vi=e.mx_ifequal,wi=e.mx_ifgreater,_i=e.mx_ifgreatereq,Si=e.mx_invert,Ti=e.mx_modulo,yi=e.mx_multiply,Vi=e.mx_noise_float,Mi=e.mx_noise_vec3,Fi=e.mx_noise_vec4,Ii=e.mx_place2d,Di=e.mx_power,Bi=e.mx_ramp4,Pi=e.mx_ramplr,Ci=e.mx_ramptb,Ai=e.mx_rgbtohsv,Ni=e.mx_rotate2d,Ri=e.mx_rotate3d,Oi=e.mx_safepower,Li=e.mx_separate,ki=e.mx_splitlr,Gi=e.mx_splittb,Ui=e.mx_srgb_texture_to_lin_rec709,ji=e.mx_subtract,Ei=e.mx_timer,Wi=e.mx_transform_uv,qi=e.mx_unifiednoise2d,zi=e.mx_unifiednoise3d,Xi=e.mx_worley_noise_float,Zi=e.mx_worley_noise_vec2,Hi=e.mx_worley_noise_vec3,Ki=e.negate,Yi=e.neutralToneMapping,Ji=e.nodeArray,Qi=e.nodeImmutable,$i=e.nodeObject,en=e.nodeObjectIntent,tn=e.nodeObjects,rn=e.nodeProxy,an=e.nodeProxyIntent,on=e.normalFlat,nn=e.normalGeometry,ln=e.normalLocal,sn=e.normalMap,cn=e.normalView,mn=e.normalViewGeometry,un=e.normalWorld,pn=e.normalWorldGeometry,dn=e.normalize,gn=e.not,hn=e.notEqual,xn=e.numWorkgroups,bn=e.objectDirection,fn=e.objectGroup,vn=e.objectPosition,wn=e.objectRadius,_n=e.objectScale,Sn=e.objectViewPosition,Tn=e.objectWorldMatrix,yn=e.OnBeforeObjectUpdate,Vn=e.OnBeforeMaterialUpdate,Mn=e.OnObjectUpdate,Fn=e.OnMaterialUpdate,In=e.oneMinus,Dn=e.or,Bn=e.orthographicDepthToViewZ,Pn=e.oscSawtooth,Cn=e.oscSine,An=e.oscSquare,Nn=e.oscTriangle,Rn=e.output,On=e.outputStruct,Ln=e.overlay,kn=e.overloadingFn,Gn=e.parabola,Un=e.parallaxDirection,jn=e.parallaxUV,En=e.parameter,Wn=e.pass,qn=e.passTexture,zn=e.pcurve,Xn=e.perspectiveDepthToViewZ,Zn=e.pmremTexture,Hn=e.pointShadow,Kn=e.pointUV,Yn=e.pointWidth,Jn=e.positionGeometry,Qn=e.positionLocal,$n=e.positionPrevious,el=e.positionView,tl=e.positionViewDirection,rl=e.positionWorld,al=e.positionWorldDirection,ol=e.posterize,il=e.pow,nl=e.pow2,ll=e.pow3,sl=e.pow4,cl=e.premultiplyAlpha,ml=e.property,ul=e.radians,pl=e.rand,dl=e.range,gl=e.rangeFog,hl=e.rangeFogFactor,xl=e.reciprocal,bl=e.reference,fl=e.referenceBuffer,vl=e.reflect,wl=e.reflectVector,_l=e.reflectView,Sl=e.reflector,Tl=e.refract,yl=e.refractVector,Vl=e.refractView,Ml=e.reinhardToneMapping,Fl=e.remap,Il=e.remapClamp,Dl=e.renderGroup,Bl=e.renderOutput,Pl=e.rendererReference,Cl=e.rotate,Al=e.rotateUV,Nl=e.roughness,Rl=e.round,Ol=e.rtt,Ll=e.sRGBTransferEOTF,kl=e.sRGBTransferOETF,Gl=e.sample,Ul=e.sampler,jl=e.samplerComparison,El=e.saturate,Wl=e.saturation,ql=e.screen,zl=e.screenCoordinate,Xl=e.screenDPR,Zl=e.screenSize,Hl=e.screenUV,Kl=e.scriptable,Yl=e.scriptableValue,Jl=e.select,Ql=e.setCurrentStack,$l=e.setName,es=e.shaderStages,ts=e.shadow,rs=e.shadowPositionWorld,as=e.shapeCircle,os=e.sharedUniformGroup,is=e.sheen,ns=e.sheenRoughness,ls=e.shiftLeft,ss=e.shiftRight,cs=e.shininess,ms=e.sign,us=e.sin,ps=e.sinc,ds=e.skinning,gs=e.smoothstep,hs=e.smoothstepElement,xs=e.specularColor,bs=e.specularF90,fs=e.spherizeUV,vs=e.split,ws=e.spritesheetUV,_s=e.sqrt,Ss=e.stack,Ts=e.step,ys=e.stepElement,Vs=e.storage,Ms=e.storageBarrier,Fs=e.storageObject,Is=e.storageTexture,Ds=e.string,Bs=e.struct,Ps=e.sub,Cs=e.subgroupAdd,As=e.subgroupAll,Ns=e.subgroupAnd,Rs=e.subgroupAny,Os=e.subgroupBallot,Ls=e.subgroupBroadcast,ks=e.subgroupBroadcastFirst,Gs=e.subBuild,Us=e.subgroupElect,js=e.subgroupExclusiveAdd,Es=e.subgroupExclusiveMul,Ws=e.subgroupInclusiveAdd,qs=e.subgroupInclusiveMul,zs=e.subgroupIndex,Xs=e.subgroupMax,Zs=e.subgroupMin,Hs=e.subgroupMul,Ks=e.subgroupOr,Ys=e.subgroupShuffle,Js=e.subgroupShuffleDown,Qs=e.subgroupShuffleUp,$s=e.subgroupShuffleXor,ec=e.subgroupSize,tc=e.subgroupXor,rc=e.tan,ac=e.tangentGeometry,oc=e.tangentLocal,ic=e.tangentView,nc=e.tangentWorld,lc=e.texture,sc=e.texture3D,cc=e.textureBarrier,mc=e.textureBicubic,uc=e.textureBicubicLevel,pc=e.textureCubeUV,dc=e.textureLoad,gc=e.textureSize,hc=e.textureLevel,xc=e.textureStore,bc=e.thickness,fc=e.time,vc=e.toneMapping,wc=e.toneMappingExposure,_c=e.toonOutlinePass,Sc=e.transformDirection,Tc=e.transformNormal,yc=e.transformNormalToView,Vc=e.transformedClearcoatNormalView,Mc=e.transformedNormalView,Fc=e.transformedNormalWorld,Ic=e.transmission,Dc=e.transpose,Bc=e.triNoise3D,Pc=e.triplanarTexture,Cc=e.triplanarTextures,Ac=e.trunc,Nc=e.uint,Rc=e.uintBitsToFloat,Oc=e.uniform,Lc=e.uniformArray,kc=e.uniformCubeTexture,Gc=e.uniformGroup,Uc=e.uniformFlow,jc=e.uniformTexture,Ec=e.unpremultiplyAlpha,Wc=e.userData,qc=e.uv,zc=e.uvec2,Xc=e.uvec3,Zc=e.uvec4,Hc=e.varying,Kc=e.varyingProperty,Yc=e.vec2,Jc=e.vec3,Qc=e.vec4,$c=e.vectorComponents,em=e.velocity,tm=e.vertexColor,rm=e.vertexIndex,am=e.vertexStage,om=e.vibrance,im=e.viewZToLogarithmicDepth,nm=e.viewZToOrthographicDepth,lm=e.viewZToPerspectiveDepth,sm=e.viewport,cm=e.viewportCoordinate,mm=e.viewportDepthTexture,um=e.viewportLinearDepth,pm=e.viewportMipTexture,dm=e.viewportResolution,gm=e.viewportSafeUV,hm=e.viewportSharedTexture,xm=e.viewportSize,bm=e.viewportTexture,fm=e.viewportUV,vm=e.wgsl,wm=e.wgslFn,_m=e.workgroupArray,Sm=e.workgroupBarrier,Tm=e.workgroupId,ym=e.workingToColorSpace,Vm=e.xor;export{t as BRDF_GGX,r as BRDF_Lambert,a as BasicPointShadowFilter,o as BasicShadowFilter,i as Break,n as Const,l as Continue,s as DFGApprox,c as D_GGX,m as Discard,u as EPSILON,p as F_Schlick,d as Fn,M as HALF_PI,g as INFINITY,h as If,x as Loop,b as NodeAccess,f as NodeShaderStage,v as NodeType,w as NodeUpdateType,Vn as OnBeforeMaterialUpdate,yn as OnBeforeObjectUpdate,Fn as OnMaterialUpdate,Mn as OnObjectUpdate,_ as PCFShadowFilter,S as PCFSoftShadowFilter,T as PI,y as PI2,F as PointShadowFilter,I as Return,D as Schlick_to_F0,B as ScriptableNodeResources,P as ShaderNode,C as Stack,A as Switch,N as TBNViewMatrix,V as TWO_PI,R as VSMShadowFilter,O as V_GGX_SmithCorrelated,L as Var,k as VarIntent,G as abs,U as acesFilmicToneMapping,j as acos,E as add,W as addMethodChaining,q as addNodeElement,z as agxToneMapping,X as all,Z as alphaT,H as and,K as anisotropy,Y as anisotropyB,J as anisotropyT,Q as any,$ as append,ee as array,te as arrayBuffer,re as asin,ae as assign,oe as atan,ie as atan2,ne as atomicAdd,le as atomicAnd,se as atomicFunc,ce as atomicLoad,me as atomicMax,ue as atomicMin,pe as atomicOr,de as atomicStore,ge as atomicSub,he as atomicXor,xe as attenuationColor,be as attenuationDistance,fe as attribute,ve as attributeArray,we as backgroundBlurriness,_e as backgroundIntensity,Se as backgroundRotation,Te as batch,ye as bentNormalView,Ve as billboarding,Me as bitAnd,Fe as bitNot,Ie as bitOr,De as bitXor,Be as bitangentGeometry,Pe as bitangentLocal,Ce as bitangentView,Ae as bitangentWorld,Ne as bitcast,Re as blendBurn,Oe as blendColor,Le as blendDodge,ke as blendOverlay,Ge as blendScreen,Ue as blur,je as bool,Ee as buffer,We as bufferAttribute,Xe as builtin,qe as bumpMap,ze as burn,Ze as bvec2,He as bvec3,Ke as bvec4,Ye as bypass,Je as cache,Qe as call,$e as cameraFar,et as cameraIndex,tt as cameraNear,rt as cameraNormalMatrix,at as cameraPosition,ot as cameraProjectionMatrix,it as cameraProjectionMatrixInverse,nt as cameraViewMatrix,lt as cameraViewport,st as cameraWorldMatrix,ct as cbrt,mt as cdl,ut as ceil,pt as checker,dt as cineonToneMapping,gt as clamp,ht as clearcoat,xt as clearcoatNormalView,bt as clearcoatRoughness,ft as code,vt as color,wt as colorSpaceToWorking,_t as colorToDirection,St as compute,Tt as computeKernel,yt as computeSkinning,Vt as context,Mt as convert,Ft as convertColorSpace,It as convertToTexture,Dt as cos,Bt as cross,Pt as cubeTexture,Ct as cubeTextureBase,At as cubeToUV,Nt as dFdx,Rt as dFdy,Ot as dashSize,Lt as debug,kt as decrement,Gt as decrementBefore,Ut as defaultBuildStages,jt as defaultShaderStages,Et as defined,Wt as degrees,qt as deltaTime,zt as densityFog,Xt as densityFogFactor,Zt as depth,Ht as depthPass,Kt as determinant,Yt as difference,Jt as diffuseColor,Qt as directPointLight,$t as directionToColor,er as directionToFaceDirection,tr as dispersion,rr as distance,ar as div,or as dodge,ir as dot,nr as drawIndex,lr as dynamicBufferAttribute,sr as element,cr as emissive,mr as equal,ur as equals,pr as equirectUV,dr as exp,gr as exp2,hr as expression,xr as faceDirection,br as faceForward,fr as faceforward,vr as float,wr as floatBitsToInt,_r as floatBitsToUint,Sr as floor,Tr as fog,yr as fract,Vr as frameGroup,Mr as frameId,Fr as frontFacing,Ir as fwidth,Dr as gain,Br as gapSize,Pr as getConstNodeType,Cr as getCurrentStack,Ar as getDirection,Nr as getDistanceAttenuation,Rr as getGeometryRoughness,Or as getNormalFromDepth,kr as getParallaxCorrectNormal,Gr as getRoughness,Ur as getScreenPosition,jr as getShIrradianceAt,Er as getShadowMaterial,Wr as getShadowRenderObjectFunction,qr as getTextureIndex,zr as getViewPosition,Xr as globalId,Zr as glsl,Hr as glslFn,Kr as grayscale,Yr as greaterThan,Jr as greaterThanEqual,Qr as hash,$r as highpModelNormalViewMatrix,ea as highpModelViewMatrix,ta as hue,ra as increment,aa as incrementBefore,oa as instance,ia as instanceIndex,na as instancedArray,la as instancedBufferAttribute,sa as instancedDynamicBufferAttribute,ca as instancedMesh,ma as int,ua as intBitsToFloat,Lr as interleavedGradientNoise,pa as inverse,da as inverseSqrt,ga as inversesqrt,ha as invocationLocalIndex,xa as invocationSubgroupIndex,ba as ior,fa as iridescence,va as iridescenceIOR,wa as iridescenceThickness,_a as ivec2,Sa as ivec3,Ta as ivec4,ya as js,Va as label,Ma as length,Fa as lengthSq,Ia as lessThan,Da as lessThanEqual,Ba as lightPosition,Pa as lightProjectionUV,Ca as lightShadowMatrix,Aa as lightTargetDirection,Na as lightTargetPosition,Ra as lightViewPosition,Oa as lightingContext,La as lights,ka as linearDepth,Ga as linearToneMapping,Ua as localId,ja as log,Ea as log2,Wa as logarithmicDepthToViewZ,qa as luminance,za as mat2,Xa as mat3,Za as mat4,Ha as matcapUV,Ka as materialAO,Ya as materialAlphaTest,Ja as materialAnisotropy,Qa as materialAnisotropyVector,$a as materialAttenuationColor,eo as materialAttenuationDistance,to as materialClearcoat,ro as materialClearcoatNormal,ao as materialClearcoatRoughness,oo as materialColor,io as materialDispersion,no as materialEmissive,lo as materialEnvIntensity,so as materialEnvRotation,co as materialIOR,mo as materialIridescence,uo as materialIridescenceIOR,po as materialIridescenceThickness,go as materialLightMap,ho as materialLineDashOffset,xo as materialLineDashSize,bo as materialLineGapSize,fo as materialLineScale,vo as materialLineWidth,wo as materialMetalness,_o as materialNormal,So as materialOpacity,To as materialPointSize,yo as materialReference,Vo as materialReflectivity,Mo as materialRefractionRatio,Fo as materialRotation,Io as materialRoughness,Do as materialSheen,Bo as materialSheenRoughness,Po as materialShininess,Co as materialSpecular,Ao as materialSpecularColor,No as materialSpecularIntensity,Ro as materialSpecularStrength,Oo as materialThickness,Lo as materialTransmission,ko as max,Go as maxMipLevel,Uo as mediumpModelViewMatrix,jo as metalness,Eo as min,Wo as mix,qo as mixElement,zo as mod,Xo as modInt,Zo as modelDirection,Ho as modelNormalMatrix,Ko as modelPosition,Yo as modelRadius,Jo as modelScale,Qo as modelViewMatrix,$o as modelViewPosition,ei as modelViewProjection,ti as modelWorldMatrix,ri as modelWorldMatrixInverse,ai as morphReference,oi as mrt,ii as mul,ni as mx_aastep,li as mx_add,si as mx_atan2,ci as mx_cell_noise_float,mi as mx_contrast,ui as mx_divide,pi as mx_fractal_noise_float,di as mx_fractal_noise_vec2,gi as mx_fractal_noise_vec3,hi as mx_fractal_noise_vec4,xi as mx_frame,bi as mx_heighttonormal,fi as mx_hsvtorgb,vi as mx_ifequal,wi as mx_ifgreater,_i as mx_ifgreatereq,Si as mx_invert,Ti as mx_modulo,yi as mx_multiply,Vi as mx_noise_float,Mi as mx_noise_vec3,Fi as mx_noise_vec4,Ii as mx_place2d,Di as mx_power,Bi as mx_ramp4,Pi as mx_ramplr,Ci as mx_ramptb,Ai as mx_rgbtohsv,Ni as mx_rotate2d,Ri as mx_rotate3d,Oi as mx_safepower,Li as mx_separate,ki as mx_splitlr,Gi as mx_splittb,Ui as mx_srgb_texture_to_lin_rec709,ji as mx_subtract,Ei as mx_timer,Wi as mx_transform_uv,qi as mx_unifiednoise2d,zi as mx_unifiednoise3d,Xi as mx_worley_noise_float,Zi as mx_worley_noise_vec2,Hi as mx_worley_noise_vec3,Ki as negate,Yi as neutralToneMapping,Ji as nodeArray,Qi as nodeImmutable,$i as nodeObject,en as nodeObjectIntent,tn as nodeObjects,rn as nodeProxy,an as nodeProxyIntent,on as normalFlat,nn as normalGeometry,ln as normalLocal,sn as normalMap,cn as normalView,mn as normalViewGeometry,un as normalWorld,pn as normalWorldGeometry,dn as normalize,gn as not,hn as notEqual,xn as numWorkgroups,bn as objectDirection,fn as objectGroup,vn as objectPosition,wn as objectRadius,_n as objectScale,Sn as objectViewPosition,Tn as objectWorldMatrix,In as oneMinus,Dn as or,Bn as orthographicDepthToViewZ,Pn as oscSawtooth,Cn as oscSine,An as oscSquare,Nn as oscTriangle,Rn as output,On as outputStruct,Ln as overlay,kn as overloadingFn,Gn as parabola,Un as parallaxDirection,jn as parallaxUV,En as parameter,Wn as pass,qn as passTexture,zn as pcurve,Xn as perspectiveDepthToViewZ,Zn as pmremTexture,Hn as pointShadow,Kn as pointUV,Yn as pointWidth,Jn as positionGeometry,Qn as positionLocal,$n as positionPrevious,el as positionView,tl as positionViewDirection,rl as positionWorld,al as positionWorldDirection,ol as posterize,il as pow,nl as pow2,ll as pow3,sl as pow4,cl as premultiplyAlpha,ml as property,ul as radians,pl as rand,dl as range,gl as rangeFog,hl as rangeFogFactor,xl as reciprocal,bl as reference,fl as referenceBuffer,vl as reflect,wl as reflectVector,_l as reflectView,Sl as reflector,Tl as refract,yl as refractVector,Vl as refractView,Ml as reinhardToneMapping,Fl as remap,Il as remapClamp,Dl as renderGroup,Bl as renderOutput,Pl as rendererReference,Cl as rotate,Al as rotateUV,Nl as roughness,Rl as round,Ol as rtt,Ll as sRGBTransferEOTF,kl as sRGBTransferOETF,Gl as sample,Ul as sampler,jl as samplerComparison,El as saturate,Wl as saturation,ql as screen,zl as screenCoordinate,Xl as screenDPR,Zl as screenSize,Hl as screenUV,Kl as scriptable,Yl as scriptableValue,Jl as select,Ql as setCurrentStack,$l as setName,es as shaderStages,ts as shadow,rs as shadowPositionWorld,as as shapeCircle,os as sharedUniformGroup,is as sheen,ns as sheenRoughness,ls as shiftLeft,ss as shiftRight,cs as shininess,ms as sign,us as sin,ps as sinc,ds as skinning,gs as smoothstep,hs as smoothstepElement,xs as specularColor,bs as specularF90,fs as spherizeUV,vs as split,ws as spritesheetUV,_s as sqrt,Ss as stack,Ts as step,ys as stepElement,Vs as storage,Ms as storageBarrier,Fs as storageObject,Is as storageTexture,Ds as string,Bs as struct,Ps as sub,Gs as subBuild,Cs as subgroupAdd,As as subgroupAll,Ns as subgroupAnd,Rs as subgroupAny,Os as subgroupBallot,Ls as subgroupBroadcast,ks as subgroupBroadcastFirst,Us as subgroupElect,js as subgroupExclusiveAdd,Es as subgroupExclusiveMul,Ws as subgroupInclusiveAdd,qs as subgroupInclusiveMul,zs as subgroupIndex,Xs as subgroupMax,Zs as subgroupMin,Hs as subgroupMul,Ks as subgroupOr,Ys as subgroupShuffle,Js as subgroupShuffleDown,Qs as subgroupShuffleUp,$s as subgroupShuffleXor,ec as subgroupSize,tc as subgroupXor,rc as tan,ac as tangentGeometry,oc as tangentLocal,ic as tangentView,nc as tangentWorld,lc as texture,sc as texture3D,cc as textureBarrier,mc as textureBicubic,uc as textureBicubicLevel,pc as textureCubeUV,hc as textureLevel,dc as textureLoad,gc as textureSize,xc as textureStore,bc as thickness,fc as time,vc as toneMapping,wc as toneMappingExposure,_c as toonOutlinePass,Sc as transformDirection,Tc as transformNormal,yc as transformNormalToView,Vc as transformedClearcoatNormalView,Mc as transformedNormalView,Fc as transformedNormalWorld,Ic as transmission,Dc as transpose,Bc as triNoise3D,Pc as triplanarTexture,Cc as triplanarTextures,Ac as trunc,Nc as uint,Rc as uintBitsToFloat,Oc as uniform,Lc as uniformArray,kc as uniformCubeTexture,Uc as uniformFlow,Gc as uniformGroup,jc as uniformTexture,Ec as unpremultiplyAlpha,Wc as userData,qc as uv,zc as uvec2,Xc as uvec3,Zc as uvec4,Hc as varying,Kc as varyingProperty,Yc as vec2,Jc as vec3,Qc as vec4,$c as vectorComponents,em as velocity,tm as vertexColor,rm as vertexIndex,am as vertexStage,om as vibrance,im as viewZToLogarithmicDepth,nm as viewZToOrthographicDepth,lm as viewZToPerspectiveDepth,sm as viewport,cm as viewportCoordinate,mm as viewportDepthTexture,um as viewportLinearDepth,pm as viewportMipTexture,dm as viewportResolution,gm as viewportSafeUV,hm as viewportSharedTexture,xm as viewportSize,bm as viewportTexture,fm as viewportUV,vm as wgsl,wm as wgslFn,_m as workgroupArray,Sm as workgroupBarrier,Tm as workgroupId,ym as workingToColorSpace,Vm as xor}; |
@@ -29,3 +29,3 @@ import { | ||
| /** | ||
| * This class solves the Inverse Kinematics Problem with a [CCD Algorithm]{@link https://web.archive.org/web/20221206080850/https://sites.google.com/site/auraliusproject/ccd-algorithm}. | ||
| * This class solves the Inverse Kinematics Problem with a [CCD Algorithm](https://web.archive.org/web/20221206080850/https://sites.google.com/site/auraliusproject/ccd-algorithm). | ||
| * | ||
@@ -32,0 +32,0 @@ * `CCDIKSolver` is designed to work with instances of {@link SkinnedMesh}. |
@@ -64,3 +64,3 @@ import { | ||
| * @param {Camera} camera - The camera of the rendered scene. | ||
| * @param {?HTMLDOMElement} [domElement=null] - The HTML DOM element used for event listeners. | ||
| * @param {?HTMLElement} [domElement=null] - The HTML DOM element used for event listeners. | ||
| */ | ||
@@ -67,0 +67,0 @@ constructor( objects, camera, domElement = null ) { |
@@ -25,3 +25,3 @@ import { | ||
| * @param {Object3D} object - The object that is managed by the controls. | ||
| * @param {?HTMLDOMElement} domElement - The HTML element used for event listeners. | ||
| * @param {?HTMLElement} domElement - The HTML element used for event listeners. | ||
| */ | ||
@@ -28,0 +28,0 @@ constructor( object, domElement = null ) { |
@@ -32,3 +32,3 @@ import { | ||
| * @param {Object3D} object - The object that is managed by the controls. | ||
| * @param {?HTMLDOMElement} domElement - The HTML element used for event listeners. | ||
| * @param {?HTMLElement} domElement - The HTML element used for event listeners. | ||
| */ | ||
@@ -35,0 +35,0 @@ constructor( object, domElement = null ) { |
@@ -94,3 +94,3 @@ import { | ||
| * @param {Object3D} object - The object that is managed by the controls. | ||
| * @param {?HTMLDOMElement} domElement - The HTML element used for event listeners. | ||
| * @param {?HTMLElement} domElement - The HTML element used for event listeners. | ||
| */ | ||
@@ -545,3 +545,3 @@ constructor( object, domElement = null ) { | ||
| * | ||
| * @param {HTMLDOMElement} domElement - The DOM element | ||
| * @param {HTMLElement} domElement - The DOM element | ||
| */ | ||
@@ -548,0 +548,0 @@ listenToKeyEvents( domElement ) { |
@@ -38,3 +38,3 @@ import { | ||
| /** | ||
| * The implementation of this class is based on the [Pointer Lock API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API}. | ||
| * The implementation of this class is based on the [Pointer Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API). | ||
| * `PointerLockControls` is a perfect choice for first person 3D games. | ||
@@ -68,3 +68,3 @@ * | ||
| * @param {Camera} camera - The camera that is managed by the controls. | ||
| * @param {?HTMLDOMElement} domElement - The HTML element used for event listeners. | ||
| * @param {?HTMLElement} domElement - The HTML element used for event listeners. | ||
| */ | ||
@@ -71,0 +71,0 @@ constructor( camera, domElement = null ) { |
@@ -62,3 +62,3 @@ import { | ||
| * @param {Object3D} object - The object that is managed by the controls. | ||
| * @param {?HTMLDOMElement} domElement - The HTML element used for event listeners. | ||
| * @param {?HTMLElement} domElement - The HTML element used for event listeners. | ||
| */ | ||
@@ -65,0 +65,0 @@ constructor( object, domElement = null ) { |
@@ -83,3 +83,3 @@ import { | ||
| * @param {Camera} camera - The camera of the rendered scene. | ||
| * @param {?HTMLDOMElement} domElement - The HTML element used for event listeners. | ||
| * @param {?HTMLElement} domElement - The HTML element used for event listeners. | ||
| */ | ||
@@ -86,0 +86,0 @@ constructor( camera, domElement = null ) { |
| /** | ||
| * A class that creates an ASCII effect. | ||
| * | ||
| * The ASCII generation is based on [jsascii]{@link https://github.com/hassadee/jsascii/blob/master/jsascii.js}. | ||
| * The ASCII generation is based on [jsascii](https://github.com/hassadee/jsascii/blob/master/jsascii.js). | ||
| * | ||
@@ -21,3 +21,3 @@ * @three_import import { AsciiEffect } from 'three/addons/effects/AsciiEffect.js'; | ||
| // darker bolder character set from https://github.com/saw/Canvas-ASCII-Art/ | ||
| // ' .\'`^",:;Il!i~+_-?][}{1)(|/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$'.split(''); | ||
| // ' .\'`^",:;Il!i~+_-?][}{1)(|/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$' | ||
@@ -222,2 +222,4 @@ // Some ASCII settings | ||
| const maxIdx = aCharList.length - 1; | ||
| // console.time('rendering'); | ||
@@ -235,9 +237,7 @@ | ||
| const iAlpha = oImgData[ iOffset + 3 ]; | ||
| let iCharIdx; | ||
| let fBrightness; | ||
| fBrightness = ( 0.3 * iRed + 0.59 * iGreen + 0.11 * iBlue ) / 255; | ||
| let fBrightness = ( 0.3 * iRed + 0.59 * iGreen + 0.11 * iBlue ) / 255; | ||
| // fBrightness = (0.3*iRed + 0.5*iGreen + 0.3*iBlue) / 255; | ||
| if ( iAlpha == 0 ) { | ||
@@ -251,7 +251,7 @@ | ||
| iCharIdx = Math.floor( ( 1 - fBrightness ) * ( aCharList.length - 1 ) ); | ||
| let iCharIdx = Math.round( ( 1 - fBrightness ) * maxIdx ); | ||
| if ( bInvert ) { | ||
| iCharIdx = aCharList.length - iCharIdx - 1; | ||
| iCharIdx = maxIdx - iCharIdx; | ||
@@ -258,0 +258,0 @@ } |
@@ -8,3 +8,3 @@ import { Color, ColorManagement, SRGBColorSpace } from 'three'; | ||
| * | ||
| * [Draco]{@link https://google.github.io/draco/} is an open source library for compressing and | ||
| * [Draco](https://google.github.io/draco/) is an open source library for compressing and | ||
| * decompressing 3D meshes and point clouds. Compressed geometry can be significantly smaller, | ||
@@ -17,3 +17,3 @@ * at the cost of additional decoding time on the client device. | ||
| * inside of a glTF file. A normal glTF file can be converted to a Draco-compressed glTF file | ||
| * using [glTF-Pipeline]{@link https://github.com/AnalyticalGraphicsInc/gltf-pipeline}. | ||
| * using [glTF-Pipeline](https://github.com/AnalyticalGraphicsInc/gltf-pipeline). | ||
| * | ||
@@ -20,0 +20,0 @@ * ```js |
@@ -18,3 +18,3 @@ import { | ||
| * | ||
| * EXR ( Extended Dynamic Range) is an [open format specification]{@link https://github.com/AcademySoftwareFoundation/openexr} | ||
| * EXR ( Extended Dynamic Range) is an [open format specification](https://github.com/AcademySoftwareFoundation/openexr) | ||
| * for professional-grade image storage format of the motion picture industry. The purpose of | ||
@@ -21,0 +21,0 @@ * format is to accurately and efficiently represent high-dynamic-range scene-linear image data |
@@ -797,3 +797,3 @@ import { | ||
| primvarReaderNode.addProperty( 'float2 inputs:fallback = (0.0, 0.0)' ); | ||
| primvarReaderNode.addProperty( `token inputs:varname = "${uv}"` ); | ||
| primvarReaderNode.addProperty( `string inputs:varname = "${uv}"` ); | ||
| primvarReaderNode.addProperty( 'float2 outputs:result' ); | ||
@@ -804,3 +804,3 @@ | ||
| transform2dNode.addProperty( | ||
| `token inputs:in.connect = </Materials/Material_${material.id}/PrimvarReader_${mapType}.outputs:result>` | ||
| `float2 inputs:in.connect = </Materials/Material_${material.id}/PrimvarReader_${mapType}.outputs:result>` | ||
| ); | ||
@@ -836,2 +836,9 @@ transform2dNode.addProperty( | ||
| if ( mapType === 'normal' ) { | ||
| textureNode.addProperty( 'float4 inputs:scale = (2, 2, 2, 1)' ); | ||
| textureNode.addProperty( 'float4 inputs:bias = (-1, -1, -1, 0)' ); | ||
| } | ||
| textureNode.addProperty( | ||
@@ -838,0 +845,0 @@ `token inputs:sourceColorSpace = "${ |
@@ -16,5 +16,5 @@ import { | ||
| * Please not that decal projections can be distorted when used around corners. More information at | ||
| * this GitHub issue: [Decal projections without distortions]{@link https://github.com/mrdoob/three.js/issues/21187}. | ||
| * this GitHub issue: [Decal projections without distortions](https://github.com/mrdoob/three.js/issues/21187). | ||
| * | ||
| * Reference: [How to project decals]{@link http://blog.wolfire.com/2009/06/how-to-project-decals/} | ||
| * Reference: [How to project decals](http://blog.wolfire.com/2009/06/how-to-project-decals/) | ||
| * | ||
@@ -21,0 +21,0 @@ * ```js |
@@ -10,3 +10,3 @@ import { | ||
| * | ||
| * Reference: [Mesh Generation with Python]{@link https://prideout.net/blog/old/blog/index.html@p=44.html} | ||
| * Reference: [Mesh Generation with Python](https://prideout.net/blog/old/blog/index.html@p=44.html) | ||
| * | ||
@@ -13,0 +13,0 @@ * ```js |
@@ -18,4 +18,4 @@ import { | ||
| * | ||
| * Code based on [SPD software]{@link http://tog.acm.org/resources/SPD/} | ||
| * Created for the Udacity course [Interactive Rendering]{@link http://bit.ly/ericity} | ||
| * Code based on [SPD software](http://tog.acm.org/resources/SPD/) | ||
| * Created for the Udacity course [Interactive Rendering](http://bit.ly/ericity) | ||
| * | ||
@@ -22,0 +22,0 @@ * ```js |
@@ -11,3 +11,3 @@ import { | ||
| * | ||
| * `TextGeometry` uses [typeface.json]{@link http://gero3.github.io/facetype.js/} generated fonts. | ||
| * `TextGeometry` uses [typeface.json](http://gero3.github.io/facetype.js/) generated fonts. | ||
| * Some existing fonts can be found located in `/examples/fonts`. | ||
@@ -47,3 +47,3 @@ * | ||
| const shapes = font.generateShapes( text, parameters.size ); | ||
| const shapes = font.generateShapes( text, parameters.size, parameters.direction ); | ||
@@ -81,2 +81,3 @@ // defaults | ||
| * @property {number} [bevelSegments=3] - Number of bevel layers. | ||
| * @property {string} [direction='ltr'] - Char direction: ltr(left to right), rtl(right to left) & tb(top bottom). | ||
| * @property {?Curve} [extrudePath=null] - A 3D spline path along which the shape should be extruded. Bevels not supported for path extrusion. | ||
@@ -83,0 +84,0 @@ * @property {Object} [UVGenerator] - An object that provides UV generator functions for custom UV generation. |
@@ -23,3 +23,3 @@ import { | ||
| * in a small viewport area as an axes helper. Such a helper is often wanted | ||
| * in 3D modeling tools or scene editors like the [three.js editor]{@link https://threejs.org/editor}. | ||
| * in 3D modeling tools or scene editors like the [three.js editor](https://threejs.org/editor). | ||
| * | ||
@@ -38,3 +38,3 @@ * The helper allows to click on the X, Y and Z axes which animates the camera | ||
| * @param {Camera} camera - The camera whose transformation should be visualized. | ||
| * @param {HTMLDOMElement} [domElement] - The DOM element that is used to render the view. | ||
| * @param {HTMLElement} [domElement] - The DOM element that is used to render the view. | ||
| */ | ||
@@ -373,2 +373,42 @@ constructor( camera, domElement ) { | ||
| function useOffscreenCanvas() { | ||
| let result = false; | ||
| try { | ||
| // this check has been adapted from WebGLTextures | ||
| result = typeof OffscreenCanvas !== 'undefined' && ( new OffscreenCanvas( 1, 1 ).getContext( '2d' ) ) !== null; | ||
| } catch ( err ) { | ||
| // Ignore any errors | ||
| } | ||
| return result; | ||
| } | ||
| function createCanvas( width, height ) { | ||
| let canvas; | ||
| if ( useOffscreenCanvas() ) { | ||
| canvas = new OffscreenCanvas( width, height ); | ||
| } else { | ||
| canvas = document.createElement( 'canvas' ); | ||
| canvas.width = width; | ||
| canvas.height = height; | ||
| } | ||
| return canvas; | ||
| } | ||
| function getSpriteMaterial( color, text ) { | ||
@@ -378,5 +418,3 @@ | ||
| const canvas = document.createElement( 'canvas' ); | ||
| canvas.width = 64; | ||
| canvas.height = 64; | ||
| const canvas = createCanvas( 64, 64 ); | ||
@@ -383,0 +421,0 @@ const context = canvas.getContext( '2d' ); |
@@ -298,14 +298,9 @@ import { | ||
| // Canvas element | ||
| const rect = element.getBoundingClientRect(); | ||
| x = rect.left - offset.left - 0.5; | ||
| y = rect.top - offset.top - 0.5; | ||
| const width = rect.width; | ||
| const height = rect.height; | ||
| context.drawImage( element, x, y, width, height ); | ||
| context.save(); | ||
| const dpr = window.devicePixelRatio; | ||
| context.scale( 1 / dpr, 1 / dpr ); | ||
| context.drawImage( element, x, y ); | ||
| context.restore(); | ||
| } else if ( element instanceof HTMLImageElement ) { | ||
@@ -525,4 +520,2 @@ | ||
| canvas = document.createElement( 'canvas' ); | ||
| canvas.width = offset.width; | ||
| canvas.height = offset.height; | ||
| canvases.set( element, canvas ); | ||
@@ -532,2 +525,5 @@ | ||
| canvas.width = offset.width; | ||
| canvas.height = offset.height; | ||
| const context = canvas.getContext( '2d'/*, { alpha: false }*/ ); | ||
@@ -534,0 +530,0 @@ |
@@ -55,3 +55,3 @@ import { | ||
| * | ||
| * @type {?HTMLDOMElement} | ||
| * @type {?HTMLElement} | ||
| * @default null | ||
@@ -58,0 +58,0 @@ */ |
@@ -95,2 +95,8 @@ import { | ||
| this.instances = {}; | ||
| /** | ||
| * The selected batches of batched meshes. | ||
| * | ||
| * @type {Object} | ||
| */ | ||
| this.batches = {}; | ||
@@ -263,2 +269,26 @@ /** | ||
| } else if ( object.isBatchedMesh ) { | ||
| this.batches[ object.uuid ] = []; | ||
| for ( let instanceId = 0, count = 0; count < object.instanceCount; instanceId ++ ) { | ||
| // skip invalid instances in the batchedMesh | ||
| if ( object.validateInstanceId( instanceId ) === false ) continue; | ||
| count ++; | ||
| object.getMatrixAt( instanceId, _matrix ); | ||
| _matrix.decompose( _center, _quaternion, _scale ); | ||
| _center.applyMatrix4( object.matrixWorld ); | ||
| if ( frustum.containsPoint( _center ) ) { | ||
| this.batches[ object.uuid ].push( instanceId ); | ||
| } | ||
| } | ||
| } else { | ||
@@ -265,0 +295,0 @@ |
@@ -27,3 +27,3 @@ import { | ||
| /** | ||
| * A loader for the [3D Manufacturing Format (3MF)]{@link https://3mf.io/specification/} format. | ||
| * A loader for the [3D Manufacturing Format (3MF)](https://3mf.io/specification/) format. | ||
| * | ||
@@ -30,0 +30,0 @@ * The following features from the core specification are supported: |
@@ -47,3 +47,3 @@ import { | ||
| const dds = { mipmaps: [], width: 0, height: 0, format: null, mipmapCount: 1 }; | ||
| const dds = { mipmaps: [], width: 0, height: 0, format: null, mipmapCount: 1, isCubemap: false }; | ||
@@ -50,0 +50,0 @@ // Adapted from @toji's DDS utils |
@@ -9,3 +9,5 @@ import { | ||
| LinearSRGBColorSpace, | ||
| SRGBColorSpace | ||
| SRGBColorSpace, | ||
| InterleavedBuffer, | ||
| InterleavedBufferAttribute | ||
| } from 'three'; | ||
@@ -18,3 +20,3 @@ | ||
| * | ||
| * [Draco]{@link https://google.github.io/draco/} is an open source library for compressing | ||
| * [Draco](https://google.github.io/draco/) is an open source library for compressing | ||
| * and decompressing 3D meshes and point clouds. Compressed geometry can be significantly smaller, | ||
@@ -26,3 +28,3 @@ * at the cost of additional decoding time on the client device. | ||
| * to use these features, embed Draco geometry inside of a glTF file. A normal glTF file can be converted | ||
| * to a Draco-compressed glTF file using [glTF-Pipeline]{@link https://github.com/CesiumGS/gltf-pipeline}. | ||
| * to a Draco-compressed glTF file using [glTF-Pipeline](https://github.com/CesiumGS/gltf-pipeline). | ||
| * When using Draco with glTF, an instance of `DRACOLoader` will be used internally by {@link GLTFLoader}. | ||
@@ -279,12 +281,21 @@ * | ||
| const result = geometryData.attributes[ i ]; | ||
| const name = result.name; | ||
| const array = result.array; | ||
| const itemSize = result.itemSize; | ||
| const { name, array, itemSize, stride, vertexColorSpace } = geometryData.attributes[ i ]; | ||
| const attribute = new BufferAttribute( array, itemSize ); | ||
| let attribute; | ||
| if ( itemSize === stride ) { | ||
| attribute = new BufferAttribute( array, itemSize ); | ||
| } else { | ||
| const buffer = new InterleavedBuffer( array, stride ); | ||
| attribute = new InterleavedBufferAttribute( buffer, itemSize, 0 ); | ||
| } | ||
| if ( name === 'color' ) { | ||
| this._assignVertexColorSpace( attribute, result.vertexColorSpace ); | ||
| this._assignVertexColorSpace( attribute, vertexColorSpace ); | ||
@@ -653,13 +664,51 @@ attribute.normalized = ( array instanceof Float32Array ) === false; | ||
| function decodeAttribute( draco, decoder, dracoGeometry, attributeName, attributeType, attribute ) { | ||
| function decodeAttribute( draco, decoder, dracoGeometry, attributeName, TypedArray, attribute ) { | ||
| const numComponents = attribute.num_components(); | ||
| const numPoints = dracoGeometry.num_points(); | ||
| const numValues = numPoints * numComponents; | ||
| const byteLength = numValues * attributeType.BYTES_PER_ELEMENT; | ||
| const dataType = getDracoDataType( draco, attributeType ); | ||
| const count = dracoGeometry.num_points(); | ||
| const itemSize = attribute.num_components(); | ||
| const dracoDataType = getDracoDataType( draco, TypedArray ); | ||
| const ptr = draco._malloc( byteLength ); | ||
| decoder.GetAttributeDataArrayForAllPoints( dracoGeometry, attribute, dataType, byteLength, ptr ); | ||
| const array = new attributeType( draco.HEAPF32.buffer, ptr, numValues ).slice(); | ||
| // Reference: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#data-alignment | ||
| const srcByteStride = itemSize * TypedArray.BYTES_PER_ELEMENT; | ||
| const dstByteStride = Math.ceil( srcByteStride / 4 ) * 4; | ||
| const dstStride = dstByteStride / TypedArray.BYTES_PER_ELEMENT | ||
| const srcByteLength = count * srcByteStride; | ||
| const dstByteLength = count * dstByteStride; | ||
| const ptr = draco._malloc( srcByteLength ); | ||
| decoder.GetAttributeDataArrayForAllPoints( dracoGeometry, attribute, dracoDataType, srcByteLength, ptr ); | ||
| const srcArray = new TypedArray( draco.HEAPF32.buffer, ptr, srcByteLength / TypedArray.BYTES_PER_ELEMENT ); | ||
| let dstArray; | ||
| if ( srcByteStride === dstByteStride ) { | ||
| // THREE.BufferAttribute | ||
| dstArray = srcArray.slice(); | ||
| } else { | ||
| // THREE.InterleavedBufferAttribute | ||
| dstArray = new TypedArray( dstByteLength / TypedArray.BYTES_PER_ELEMENT ); | ||
| let dstOffset = 0 | ||
| for ( let i = 0, il = srcArray.length; i < il; i++ ) { | ||
| for ( let j = 0; j < itemSize; j++ ) { | ||
| dstArray[ dstOffset + j ] = srcArray[ i * itemSize + j ] | ||
| } | ||
| dstOffset += dstStride; | ||
| } | ||
| } | ||
| draco._free( ptr ); | ||
@@ -669,4 +718,6 @@ | ||
| name: attributeName, | ||
| array: array, | ||
| itemSize: numComponents | ||
| count: count, | ||
| itemSize: itemSize, | ||
| array: dstArray, | ||
| stride: dstStride | ||
| }; | ||
@@ -676,5 +727,5 @@ | ||
| function getDracoDataType( draco, attributeType ) { | ||
| function getDracoDataType( draco, TypedArray ) { | ||
| switch ( attributeType ) { | ||
| switch ( TypedArray ) { | ||
@@ -681,0 +732,0 @@ case Float32Array: return draco.DT_FLOAT32; |
@@ -10,3 +10,3 @@ import { | ||
| * | ||
| * You can convert fonts online using [facetype.js]{@link https://gero3.github.io/facetype.js/}. | ||
| * You can convert fonts online using [facetype.js](https://gero3.github.io/facetype.js/). | ||
| * | ||
@@ -113,8 +113,9 @@ * ```js | ||
| * @param {number} [size=100] - The text size. | ||
| * @param {string} [direction='ltr'] - Char direction: ltr(left to right), rtl(right to left) & tb(top bottom). | ||
| * @return {Array<Shape>} An array of shapes representing the text. | ||
| */ | ||
| generateShapes( text, size = 100 ) { | ||
| generateShapes( text, size = 100, direction = 'ltr' ) { | ||
| const shapes = []; | ||
| const paths = createPaths( text, size, this.data ); | ||
| const paths = createPaths( text, size, this.data, direction ); | ||
@@ -133,3 +134,3 @@ for ( let p = 0, pl = paths.length; p < pl; p ++ ) { | ||
| function createPaths( text, size, data ) { | ||
| function createPaths( text, size, data, direction ) { | ||
@@ -144,2 +145,8 @@ const chars = Array.from( text ); | ||
| if ( direction == 'rtl' || direction == 'tb' ) { | ||
| chars.reverse(); | ||
| } | ||
| for ( let i = 0; i < chars.length; i ++ ) { | ||
@@ -157,3 +164,14 @@ | ||
| const ret = createPath( char, scale, offsetX, offsetY, data ); | ||
| offsetX += ret.offsetX; | ||
| if ( direction == 'tb' ) { | ||
| offsetX = 0; | ||
| offsetY += data.ascender * scale; | ||
| } else { | ||
| offsetX += ret.offsetX; | ||
| } | ||
| paths.push( ret.path ); | ||
@@ -160,0 +178,0 @@ |
@@ -116,5 +116,5 @@ import { | ||
| * References: | ||
| * - [KTX specification]{@link http://github.khronos.org/KTX-Specification/} | ||
| * - [DFD]{@link https://www.khronos.org/registry/DataFormat/specs/1.3/dataformat.1.3.html#basicdescriptor} | ||
| * - [BasisU HDR]{@link https://github.com/BinomialLLC/basis_universal/wiki/UASTC-HDR-Texture-Specification-v1.0} | ||
| * - [KTX specification](http://github.khronos.org/KTX-Specification/) | ||
| * - [DFD](https://www.khronos.org/registry/DataFormat/specs/1.3/dataformat.1.3.html#basicdescriptor) | ||
| * - [BasisU HDR](https://github.com/BinomialLLC/basis_universal/wiki/UASTC-HDR-Texture-Specification-v1.0) | ||
| * | ||
@@ -198,3 +198,4 @@ * ```js | ||
| * @async | ||
| * @param {WebGPURenderer|WebGLRenderer} renderer - The renderer. | ||
| * @deprecated | ||
| * @param {WebGPURenderer} renderer - The renderer. | ||
| * @return {Promise} A Promise that resolves when the support has been detected. | ||
@@ -204,14 +205,8 @@ */ | ||
| this.workerConfig = { | ||
| astcSupported: await renderer.hasFeatureAsync( 'texture-compression-astc' ), | ||
| astcHDRSupported: false, // https://github.com/gpuweb/gpuweb/issues/3856 | ||
| etc1Supported: await renderer.hasFeatureAsync( 'texture-compression-etc2' ), | ||
| etc2Supported: await renderer.hasFeatureAsync( 'texture-compression-etc2' ), | ||
| dxtSupported: await renderer.hasFeatureAsync( 'texture-compression-bc' ), | ||
| bptcSupported: await renderer.hasFeatureAsync( 'texture-compression-bc' ), | ||
| pvrtcSupported: await renderer.hasFeatureAsync( 'texture-compression-pvrtc' ) | ||
| }; | ||
| console.warn( 'KTX2Loader: "detectSupportAsync()" has been deprecated. Use "detectSupport()" and "await renderer.init();" when creating the renderer.' ); // @deprecated r181 | ||
| return this; | ||
| await renderer.init(); | ||
| return this.detectSupport( renderer ); | ||
| } | ||
@@ -233,5 +228,5 @@ | ||
| astcHDRSupported: false, // https://github.com/gpuweb/gpuweb/issues/3856 | ||
| etc1Supported: renderer.hasFeature( 'texture-compression-etc2' ), | ||
| etc1Supported: renderer.hasFeature( 'texture-compression-etc1' ), | ||
| etc2Supported: renderer.hasFeature( 'texture-compression-etc2' ), | ||
| dxtSupported: renderer.hasFeature( 'texture-compression-bc' ), | ||
| dxtSupported: renderer.hasFeature( 'texture-compression-s3tc' ), | ||
| bptcSupported: renderer.hasFeature( 'texture-compression-bc' ), | ||
@@ -255,2 +250,17 @@ pvrtcSupported: renderer.hasFeature( 'texture-compression-pvrtc' ) | ||
| if ( typeof navigator !== 'undefined' && | ||
| navigator.platform.indexOf( 'Linux' ) >= 0 && navigator.userAgent.indexOf( 'Firefox' ) >= 0 && | ||
| this.workerConfig.astcSupported && this.workerConfig.etc2Supported && | ||
| this.workerConfig.bptcSupported && this.workerConfig.dxtSupported ) { | ||
| // On Linux, Mesa drivers for AMD and Intel GPUs expose ETC2 and ASTC even though the hardware doesn't support these. | ||
| // Using these extensions will result in expensive software decompression on the main thread inside the driver, causing performance issues. | ||
| // When using ANGLE (e.g. via Chrome), these extensions are not exposed except for some specific Intel GPU models - however, Firefox doesn't perform this filtering. | ||
| // Since a granular filter is a little too fragile and we can transcode into other GPU formats, disable formats that are likely to be emulated. | ||
| this.workerConfig.astcSupported = false; | ||
| this.workerConfig.etc2Supported = false; | ||
| } | ||
| } | ||
@@ -357,2 +367,3 @@ | ||
| loader.setWithCredentials( this.withCredentials ); | ||
| loader.setRequestHeader( this.requestHeader ); | ||
| loader.setResponseType( 'arraybuffer' ); | ||
@@ -855,9 +866,5 @@ | ||
| const OPTIONS = { | ||
| // TODO: For ETC1S we intentionally sort by _UASTC_ priority, preserving | ||
| // a historical accident shown to avoid performance pitfalls for Linux with | ||
| // Firefox & AMD GPU (RadeonSI). Further work needed. | ||
| // See https://github.com/mrdoob/three.js/pull/29730. | ||
| [ BasisFormat.ETC1S ]: FORMAT_OPTIONS | ||
| .filter( ( opt ) => opt.basisFormat.includes( BasisFormat.ETC1S ) ) | ||
| .sort( ( a, b ) => a.priorityUASTC - b.priorityUASTC ), | ||
| .sort( ( a, b ) => a.priorityETC1S - b.priorityETC1S ), | ||
@@ -864,0 +871,0 @@ [ BasisFormat.UASTC ]: FORMAT_OPTIONS |
@@ -9,4 +9,4 @@ import { | ||
| * References: | ||
| * - [The KTX File Format and Tools]{@link https://www.khronos.org/opengles/sdk/tools/KTX/} | ||
| * - [Babylon.JS khronosTextureContainer.ts]{@link https://github.com/BabylonJS/Babylon.js/blob/master/src/Misc/khronosTextureContainer.ts} | ||
| * - [The KTX File Format and Tools](https://www.khronos.org/opengles/sdk/tools/KTX/) | ||
| * - [Babylon.JS khronosTextureContainer.ts](https://github.com/BabylonJS/Babylon.js/blob/master/src/Misc/khronosTextureContainer.ts) | ||
| * | ||
@@ -13,0 +13,0 @@ * ```js |
@@ -1752,3 +1752,3 @@ import { | ||
| * | ||
| * [LDraw]{@link https://ldraw.org/} (LEGO Draw) is an [open format specification]{@link https://ldraw.org/article/218.html} | ||
| * [LDraw](https://ldraw.org/} (LEGO Draw) is an [open format specification]{@link https://ldraw.org/article/218.html) | ||
| * for describing LEGO and other construction set 3D models. | ||
@@ -1755,0 +1755,0 @@ * |
@@ -15,4 +15,4 @@ import { | ||
| * References: | ||
| * - [3D LUTs]{@link http://download.autodesk.com/us/systemdocs/help/2011/lustre/index.html?url=./files/WSc4e151a45a3b785a24c3d9a411df9298473-7ffd.htm,topicNumber=d0e9492} | ||
| * - [Format Spec for .3dl]{@link https://community.foundry.com/discuss/topic/103636/format-spec-for-3dl?mode=Post&postID=895258} | ||
| * - [3D LUTs](http://download.autodesk.com/us/systemdocs/help/2011/lustre/index.html?url=./files/WSc4e151a45a3b785a24c3d9a411df9298473-7ffd.htm,topicNumber=d0e9492) | ||
| * - [Format Spec for .3dl](https://community.foundry.com/discuss/topic/103636/format-spec-for-3dl?mode=Post&postID=895258) | ||
| * | ||
@@ -19,0 +19,0 @@ * ```js |
@@ -15,3 +15,3 @@ import { | ||
| * References: | ||
| * - [Cube LUT Specification]{@link https://web.archive.org/web/20220220033515/https://wwwimages2.adobe.com/content/dam/acom/en/products/speedgrade/cc/pdfs/cube-lut-specification-1.0.pdf} | ||
| * - [Cube LUT Specification](https://web.archive.org/web/20220220033515/https://wwwimages2.adobe.com/content/dam/acom/en/products/speedgrade/cc/pdfs/cube-lut-specification-1.0.pdf) | ||
| * | ||
@@ -18,0 +18,0 @@ * ```js |
@@ -39,4 +39,4 @@ import { | ||
| * References: | ||
| * - [LWO3 format specification]{@link https://static.lightwave3d.com/sdk/2019/html/filefmts/lwo3.html} | ||
| * - [LWO2 format specification]{@link https://static.lightwave3d.com/sdk/2019/html/filefmts/lwo2.html} | ||
| * - [LWO3 format specification](https://static.lightwave3d.com/sdk/2019/html/filefmts/lwo3.html) | ||
| * - [LWO2 format specification](https://static.lightwave3d.com/sdk/2019/html/filefmts/lwo2.html) | ||
| * | ||
@@ -43,0 +43,0 @@ * ```js |
| import { | ||
| FileLoader, Loader, TextureLoader, RepeatWrapping, MeshBasicNodeMaterial, | ||
| FileLoader, Loader, ImageBitmapLoader, Texture, RepeatWrapping, MeshBasicNodeMaterial, | ||
| MeshPhysicalNodeMaterial, DoubleSide, | ||
@@ -413,5 +413,11 @@ } from 'three/webgpu'; | ||
| const filePrefix = this.getRecursiveAttribute( 'fileprefix' ) || ''; | ||
| const uri = filePrefix + this.value; | ||
| if ( this.materialX.textureCache.has( uri ) ) { | ||
| return this.materialX.textureCache.get( uri ); | ||
| } | ||
| let loader = this.materialX.textureLoader; | ||
| const uri = filePrefix + this.value; | ||
@@ -425,6 +431,14 @@ if ( uri ) { | ||
| const texture = loader.load( uri ); | ||
| const texture = new Texture(); | ||
| texture.wrapS = texture.wrapT = RepeatWrapping; | ||
| texture.flipY = false; | ||
| this.materialX.textureCache.set( uri, texture ); | ||
| loader.load( uri, function ( imageBitmap ) { | ||
| texture.image = imageBitmap; | ||
| texture.needsUpdate = true; | ||
| } ); | ||
| return texture; | ||
@@ -1035,4 +1049,7 @@ | ||
| this.textureLoader = new TextureLoader( manager ); | ||
| this.textureLoader = new ImageBitmapLoader( manager ); | ||
| this.textureLoader.setOptions( { imageOrientation: 'flipY' } ); | ||
| this.textureCache = new Map(); | ||
| } | ||
@@ -1039,0 +1056,0 @@ |
@@ -439,3 +439,3 @@ import { | ||
| * | ||
| * The [OBJ format]{@link https://en.wikipedia.org/wiki/Wavefront_.obj_file} is a simple data-format that | ||
| * The [OBJ format](https://en.wikipedia.org/wiki/Wavefront_.obj_file) is a simple data-format that | ||
| * represents 3D geometry in a human readable format as the position of each vertex, the UV position of | ||
@@ -442,0 +442,0 @@ * each texture coordinate vertex, vertex normals, and the faces that make each polygon defined as a list |
@@ -13,3 +13,3 @@ import { | ||
| * | ||
| * The [Protein Data Bank]{@link https://en.wikipedia.org/wiki/Protein_Data_Bank_(file_format)} | ||
| * The [Protein Data Bank](https://en.wikipedia.org/wiki/Protein_Data_Bank_(file_format)) | ||
| * file format is a textual file describing the three-dimensional structures of molecules. | ||
@@ -16,0 +16,0 @@ * |
@@ -42,3 +42,3 @@ import { | ||
| * | ||
| * Existing HDR or EXR textures can be converted to Ultra HDR with this [tool]{@link https://gainmap-creator.monogrid.com/}. | ||
| * Existing HDR or EXR textures can be converted to Ultra HDR with this [tool](https://gainmap-creator.monogrid.com/). | ||
| * | ||
@@ -45,0 +45,0 @@ * Current feature set: |
@@ -21,3 +21,3 @@ import { | ||
| * | ||
| * This Quickhull 3D implementation is a port of [quickhull3d]{@link https://github.com/maurizzzio/quickhull3d/} | ||
| * This Quickhull 3D implementation is a port of [quickhull3d](https://github.com/maurizzzio/quickhull3d/) | ||
| * by Mauricio Poppe. | ||
@@ -24,0 +24,0 @@ * |
@@ -39,3 +39,3 @@ import { MathUtils } from 'three'; | ||
| * | ||
| * The code is based on [IMPROVED NOISE]{@link https://cs.nyu.edu/~perlin/noise/} | ||
| * The code is based on [IMPROVED NOISE](https://cs.nyu.edu/~perlin/noise/) | ||
| * by Ken Perlin, 2002. | ||
@@ -42,0 +42,0 @@ * |
| /** | ||
| * A utility class providing noise functions. | ||
| * | ||
| * The code is based on [Simplex noise demystified]{@link https://web.archive.org/web/20210210162332/http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf} | ||
| * The code is based on [Simplex noise demystified](https://web.archive.org/web/20210210162332/http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf) | ||
| * by Stefan Gustavson, 2005. | ||
@@ -6,0 +6,0 @@ * |
@@ -5,3 +5,3 @@ import { DoubleSide, FloatType, HalfFloatType, Mesh, MeshBasicMaterial, MeshPhongMaterial, PlaneGeometry, Scene, WebGLRenderTarget } from 'three'; | ||
| /** | ||
| * Progressive Light Map Accumulator, by [zalo]{@link https://github.com/zalo/}. | ||
| * Progressive Light Map Accumulator, by [zalo](https://github.com/zalo/). | ||
| * | ||
@@ -127,2 +127,8 @@ * To use, simply construct a `ProgressiveLightMap` object, | ||
| if ( object.geometry.hasAttribute( 'normal' ) === false ) { | ||
| console.warn( 'THREE.ProgressiveLightMap: All lightmap objects need normals.' ); continue; | ||
| } | ||
| if ( this.blurringPlane === null ) { | ||
@@ -285,5 +291,5 @@ | ||
| * @param {number} res - The square resolution of this object's lightMap. | ||
| * @param {?WebGLRenderTarget} [lightMap] - The lightmap to initialize the plane with. | ||
| * @param {WebGLRenderTarget} lightMap - The lightmap to initialize the plane with. | ||
| */ | ||
| _initializeBlurPlane( res, lightMap = null ) { | ||
| _initializeBlurPlane( res, lightMap ) { | ||
@@ -290,0 +296,0 @@ const blurMaterial = new MeshBasicMaterial(); |
@@ -7,3 +7,3 @@ import { DoubleSide, FloatType, HalfFloatType, PlaneGeometry, Mesh, RenderTarget, Scene, MeshPhongNodeMaterial, NodeMaterial } from 'three/webgpu'; | ||
| /** | ||
| * Progressive Light Map Accumulator, by [zalo]{@link https://github.com/zalo/}. | ||
| * Progressive Light Map Accumulator, by [zalo](https://github.com/zalo/). | ||
| * | ||
@@ -105,2 +105,8 @@ * To use, simply construct a `ProgressiveLightMap` object, | ||
| if ( object.geometry.hasAttribute( 'normal' ) === false ) { | ||
| console.warn( 'THREE.ProgressiveLightMap: All lightmap objects need normals.' ); continue; | ||
| } | ||
| if ( this._blurringPlane === null ) { | ||
@@ -107,0 +113,0 @@ |
@@ -45,5 +45,3 @@ import { | ||
| const material = new MeshStandardMaterial( { | ||
| vertexColors: true | ||
| } ); | ||
| const material = new MeshStandardMaterial( { vertexColors: true } ); | ||
@@ -59,3 +57,3 @@ const mesh = new Mesh( geometry, material ); | ||
| const sides = 10; | ||
| const sides = 15; | ||
| const array = []; | ||
@@ -77,2 +75,4 @@ const radius = 0.01 * size; | ||
| const vector = new Vector3(); | ||
| const vector1 = new Vector3(); | ||
@@ -83,7 +83,234 @@ const vector2 = new Vector3(); | ||
| const color = new Color( 0xffffff ); | ||
| let size = 1; | ||
| const color1 = new Color( 0xffffff ); | ||
| const color2 = new Color( 0xffffff ); | ||
| function stroke( position1, position2, matrix1, matrix2 ) { | ||
| let size1 = 1; | ||
| let size2 = 1; | ||
| function addCap( position, matrix, isEndCap, capSize ) { | ||
| let count = geometry.drawRange.count; | ||
| const points = getPoints( capSize ); | ||
| const sides = points.length; | ||
| const radius = 0.01 * capSize; | ||
| const latSegments = 4; | ||
| const directionSign = isEndCap ? - 1 : 1; | ||
| for ( let lat = 0; lat < latSegments; lat ++ ) { | ||
| const phi1 = ( lat / latSegments ) * Math.PI * 0.5; | ||
| const phi2 = ( ( lat + 1 ) / latSegments ) * Math.PI * 0.5; | ||
| const z1 = Math.sin( phi1 ) * radius * directionSign; | ||
| const r1 = Math.cos( phi1 ) * radius; | ||
| const z2 = Math.sin( phi2 ) * radius * directionSign; | ||
| const r2 = Math.cos( phi2 ) * radius; | ||
| for ( let i = 0; i < sides; i ++ ) { | ||
| const theta1 = ( i / sides ) * Math.PI * 2; | ||
| const theta2 = ( ( i + 1 ) / sides ) * Math.PI * 2; | ||
| // First ring | ||
| const x1 = Math.sin( theta1 ) * r1; | ||
| const y1 = Math.cos( theta1 ) * r1; | ||
| const x2 = Math.sin( theta2 ) * r1; | ||
| const y2 = Math.cos( theta2 ) * r1; | ||
| // Second ring | ||
| const x3 = Math.sin( theta1 ) * r2; | ||
| const y3 = Math.cos( theta1 ) * r2; | ||
| const x4 = Math.sin( theta2 ) * r2; | ||
| const y4 = Math.cos( theta2 ) * r2; | ||
| // Transform to world space | ||
| vector1.set( x1, y1, z1 ).applyMatrix4( matrix ).add( position ); | ||
| vector2.set( x2, y2, z1 ).applyMatrix4( matrix ).add( position ); | ||
| vector3.set( x3, y3, z2 ).applyMatrix4( matrix ).add( position ); | ||
| vector4.set( x4, y4, z2 ).applyMatrix4( matrix ).add( position ); | ||
| // First triangle | ||
| normal.set( x1, y1, z1 ).normalize().transformDirection( matrix ); | ||
| vector.set( x2, y2, z1 ).normalize().transformDirection( matrix ); | ||
| side.set( x3, y3, z2 ).normalize().transformDirection( matrix ); | ||
| if ( isEndCap ) { | ||
| vector1.toArray( positions.array, count * 3 ); | ||
| vector2.toArray( positions.array, ( count + 1 ) * 3 ); | ||
| vector3.toArray( positions.array, ( count + 2 ) * 3 ); | ||
| normal.toArray( normals.array, count * 3 ); | ||
| vector.toArray( normals.array, ( count + 1 ) * 3 ); | ||
| side.toArray( normals.array, ( count + 2 ) * 3 ); | ||
| } else { | ||
| vector1.toArray( positions.array, count * 3 ); | ||
| vector3.toArray( positions.array, ( count + 1 ) * 3 ); | ||
| vector2.toArray( positions.array, ( count + 2 ) * 3 ); | ||
| normal.toArray( normals.array, count * 3 ); | ||
| side.toArray( normals.array, ( count + 1 ) * 3 ); | ||
| vector.toArray( normals.array, ( count + 2 ) * 3 ); | ||
| } | ||
| color1.toArray( colors.array, count * 3 ); | ||
| color1.toArray( colors.array, ( count + 1 ) * 3 ); | ||
| color1.toArray( colors.array, ( count + 2 ) * 3 ); | ||
| count += 3; | ||
| // Second triangle | ||
| if ( r2 > 0.001 ) { | ||
| normal.set( x2, y2, z1 ).normalize().transformDirection( matrix ); | ||
| vector.set( x4, y4, z2 ).normalize().transformDirection( matrix ); | ||
| side.set( x3, y3, z2 ).normalize().transformDirection( matrix ); | ||
| if ( isEndCap ) { | ||
| vector2.toArray( positions.array, count * 3 ); | ||
| vector4.toArray( positions.array, ( count + 1 ) * 3 ); | ||
| vector3.toArray( positions.array, ( count + 2 ) * 3 ); | ||
| normal.toArray( normals.array, count * 3 ); | ||
| vector.toArray( normals.array, ( count + 1 ) * 3 ); | ||
| side.toArray( normals.array, ( count + 2 ) * 3 ); | ||
| } else { | ||
| vector3.toArray( positions.array, count * 3 ); | ||
| vector4.toArray( positions.array, ( count + 1 ) * 3 ); | ||
| vector2.toArray( positions.array, ( count + 2 ) * 3 ); | ||
| side.toArray( normals.array, count * 3 ); | ||
| vector.toArray( normals.array, ( count + 1 ) * 3 ); | ||
| normal.toArray( normals.array, ( count + 2 ) * 3 ); | ||
| } | ||
| color1.toArray( colors.array, count * 3 ); | ||
| color1.toArray( colors.array, ( count + 1 ) * 3 ); | ||
| color1.toArray( colors.array, ( count + 2 ) * 3 ); | ||
| count += 3; | ||
| } | ||
| } | ||
| } | ||
| geometry.drawRange.count = count; | ||
| } | ||
| function updateEndCap( position, matrix, capSize ) { | ||
| if ( endCapStartIndex === null ) return; | ||
| const points = getPoints( capSize ); | ||
| const sides = points.length; | ||
| const radius = 0.01 * capSize; | ||
| const latSegments = 4; | ||
| let count = endCapStartIndex; | ||
| for ( let lat = 0; lat < latSegments; lat ++ ) { | ||
| const phi1 = ( lat / latSegments ) * Math.PI * 0.5; | ||
| const phi2 = ( ( lat + 1 ) / latSegments ) * Math.PI * 0.5; | ||
| const z1 = - Math.sin( phi1 ) * radius; | ||
| const r1 = Math.cos( phi1 ) * radius; | ||
| const z2 = - Math.sin( phi2 ) * radius; | ||
| const r2 = Math.cos( phi2 ) * radius; | ||
| for ( let i = 0; i < sides; i ++ ) { | ||
| const theta1 = ( i / sides ) * Math.PI * 2; | ||
| const theta2 = ( ( i + 1 ) / sides ) * Math.PI * 2; | ||
| // First ring | ||
| const x1 = Math.sin( theta1 ) * r1; | ||
| const y1 = Math.cos( theta1 ) * r1; | ||
| const x2 = Math.sin( theta2 ) * r1; | ||
| const y2 = Math.cos( theta2 ) * r1; | ||
| // Second ring | ||
| const x3 = Math.sin( theta1 ) * r2; | ||
| const y3 = Math.cos( theta1 ) * r2; | ||
| const x4 = Math.sin( theta2 ) * r2; | ||
| const y4 = Math.cos( theta2 ) * r2; | ||
| // Transform positions to world space | ||
| vector1.set( x1, y1, z1 ).applyMatrix4( matrix ).add( position ); | ||
| vector2.set( x2, y2, z1 ).applyMatrix4( matrix ).add( position ); | ||
| vector3.set( x3, y3, z2 ).applyMatrix4( matrix ).add( position ); | ||
| vector4.set( x4, y4, z2 ).applyMatrix4( matrix ).add( position ); | ||
| // Transform normals to world space | ||
| normal.set( x1, y1, z1 ).normalize().transformDirection( matrix ); | ||
| vector.set( x2, y2, z1 ).normalize().transformDirection( matrix ); | ||
| side.set( x3, y3, z2 ).normalize().transformDirection( matrix ); | ||
| // First triangle | ||
| vector1.toArray( positions.array, count * 3 ); | ||
| vector2.toArray( positions.array, ( count + 1 ) * 3 ); | ||
| vector3.toArray( positions.array, ( count + 2 ) * 3 ); | ||
| normal.toArray( normals.array, count * 3 ); | ||
| vector.toArray( normals.array, ( count + 1 ) * 3 ); | ||
| side.toArray( normals.array, ( count + 2 ) * 3 ); | ||
| color1.toArray( colors.array, count * 3 ); | ||
| color1.toArray( colors.array, ( count + 1 ) * 3 ); | ||
| color1.toArray( colors.array, ( count + 2 ) * 3 ); | ||
| count += 3; | ||
| // Second triangle | ||
| if ( r2 > 0.001 ) { | ||
| normal.set( x2, y2, z1 ).normalize().transformDirection( matrix ); | ||
| vector.set( x4, y4, z2 ).normalize().transformDirection( matrix ); | ||
| side.set( x3, y3, z2 ).normalize().transformDirection( matrix ); | ||
| vector2.toArray( positions.array, count * 3 ); | ||
| vector4.toArray( positions.array, ( count + 1 ) * 3 ); | ||
| vector3.toArray( positions.array, ( count + 2 ) * 3 ); | ||
| normal.toArray( normals.array, count * 3 ); | ||
| vector.toArray( normals.array, ( count + 1 ) * 3 ); | ||
| side.toArray( normals.array, ( count + 2 ) * 3 ); | ||
| color1.toArray( colors.array, count * 3 ); | ||
| color1.toArray( colors.array, ( count + 1 ) * 3 ); | ||
| color1.toArray( colors.array, ( count + 2 ) * 3 ); | ||
| count += 3; | ||
| } | ||
| } | ||
| } | ||
| positions.addUpdateRange( endCapStartIndex * 3, endCapVertexCount * 3 ); | ||
| normals.addUpdateRange( endCapStartIndex * 3, endCapVertexCount * 3 ); | ||
| colors.addUpdateRange( endCapStartIndex * 3, endCapVertexCount * 3 ); | ||
| } | ||
| function stroke( position1, position2, matrix1, matrix2, size1, size2 ) { | ||
| if ( position1.distanceToSquared( position2 ) === 0 ) return; | ||
@@ -93,16 +320,17 @@ | ||
| const points = getPoints( size ); | ||
| const points1 = getPoints( size1 ); | ||
| const points2 = getPoints( size2 ); | ||
| for ( let i = 0, il = points.length; i < il; i ++ ) { | ||
| for ( let i = 0, il = points2.length; i < il; i ++ ) { | ||
| const vertex1 = points[ i ]; | ||
| const vertex2 = points[ ( i + 1 ) % il ]; | ||
| const vertex1_2 = points2[ i ]; | ||
| const vertex2_2 = points2[ ( i + 1 ) % il ]; | ||
| const vertex1_1 = points1[ i ]; | ||
| const vertex2_1 = points1[ ( i + 1 ) % il ]; | ||
| // positions | ||
| vector1.copy( vertex1_2 ).applyMatrix4( matrix2 ).add( position2 ); | ||
| vector2.copy( vertex2_2 ).applyMatrix4( matrix2 ).add( position2 ); | ||
| vector3.copy( vertex2_1 ).applyMatrix4( matrix1 ).add( position1 ); | ||
| vector4.copy( vertex1_1 ).applyMatrix4( matrix1 ).add( position1 ); | ||
| vector1.copy( vertex1 ).applyMatrix4( matrix2 ).add( position2 ); | ||
| vector2.copy( vertex2 ).applyMatrix4( matrix2 ).add( position2 ); | ||
| vector3.copy( vertex2 ).applyMatrix4( matrix1 ).add( position1 ); | ||
| vector4.copy( vertex1 ).applyMatrix4( matrix1 ).add( position1 ); | ||
| vector1.toArray( positions.array, ( count + 0 ) * 3 ); | ||
@@ -116,9 +344,7 @@ vector2.toArray( positions.array, ( count + 1 ) * 3 ); | ||
| // normals | ||
| vector1.copy( vertex1_2 ).applyMatrix4( matrix2 ).normalize(); | ||
| vector2.copy( vertex2_2 ).applyMatrix4( matrix2 ).normalize(); | ||
| vector3.copy( vertex2_1 ).applyMatrix4( matrix1 ).normalize(); | ||
| vector4.copy( vertex1_1 ).applyMatrix4( matrix1 ).normalize(); | ||
| vector1.copy( vertex1 ).applyMatrix4( matrix2 ).normalize(); | ||
| vector2.copy( vertex2 ).applyMatrix4( matrix2 ).normalize(); | ||
| vector3.copy( vertex2 ).applyMatrix4( matrix1 ).normalize(); | ||
| vector4.copy( vertex1 ).applyMatrix4( matrix1 ).normalize(); | ||
| vector1.toArray( normals.array, ( count + 0 ) * 3 ); | ||
@@ -132,12 +358,10 @@ vector2.toArray( normals.array, ( count + 1 ) * 3 ); | ||
| // colors | ||
| color2.toArray( colors.array, ( count + 0 ) * 3 ); | ||
| color2.toArray( colors.array, ( count + 1 ) * 3 ); | ||
| color1.toArray( colors.array, ( count + 2 ) * 3 ); | ||
| color.toArray( colors.array, ( count + 0 ) * 3 ); | ||
| color.toArray( colors.array, ( count + 1 ) * 3 ); | ||
| color.toArray( colors.array, ( count + 2 ) * 3 ); | ||
| color2.toArray( colors.array, ( count + 3 ) * 3 ); | ||
| color1.toArray( colors.array, ( count + 4 ) * 3 ); | ||
| color1.toArray( colors.array, ( count + 5 ) * 3 ); | ||
| color.toArray( colors.array, ( count + 3 ) * 3 ); | ||
| color.toArray( colors.array, ( count + 4 ) * 3 ); | ||
| color.toArray( colors.array, ( count + 5 ) * 3 ); | ||
| count += 6; | ||
@@ -153,3 +377,5 @@ | ||
| const up = new Vector3( 0, 1, 0 ); | ||
| const direction = new Vector3(); | ||
| const normal = new Vector3(); | ||
| const side = new Vector3(); | ||
@@ -162,10 +388,80 @@ const point1 = new Vector3(); | ||
| const lastNormal = new Vector3(); | ||
| const prevDirection = new Vector3(); | ||
| const rotationAxis = new Vector3(); | ||
| let isFirstSegment = true; | ||
| let endCapStartIndex = null; | ||
| let endCapVertexCount = 0; | ||
| function calculateRMF() { | ||
| if ( isFirstSegment === true ) { | ||
| if ( Math.abs( direction.y ) < 0.99 ) { | ||
| vector.copy( direction ).multiplyScalar( direction.y ); | ||
| normal.set( 0, 1, 0 ).sub( vector ).normalize(); | ||
| } else { | ||
| vector.copy( direction ).multiplyScalar( direction.x ); | ||
| normal.set( 1, 0, 0 ).sub( vector ).normalize(); | ||
| } | ||
| } else { | ||
| rotationAxis.crossVectors( prevDirection, direction ); | ||
| const rotAxisLength = rotationAxis.length(); | ||
| if ( rotAxisLength > 0.0001 ) { | ||
| rotationAxis.divideScalar( rotAxisLength ); | ||
| vector.addVectors( prevDirection, direction ); | ||
| const c1 = - 2.0 / ( 1.0 + prevDirection.dot( direction ) ); | ||
| const dot = lastNormal.dot( vector ); | ||
| normal.copy( lastNormal ).addScaledVector( vector, c1 * dot ); | ||
| } else { | ||
| normal.copy( lastNormal ); | ||
| } | ||
| } | ||
| side.crossVectors( direction, normal ).normalize(); | ||
| normal.crossVectors( side, direction ).normalize(); | ||
| if ( isFirstSegment === false ) { | ||
| const smoothFactor = 0.3; | ||
| normal.lerp( lastNormal, smoothFactor ).normalize(); | ||
| side.crossVectors( direction, normal ).normalize(); | ||
| normal.crossVectors( side, direction ).normalize(); | ||
| } | ||
| lastNormal.copy( normal ); | ||
| prevDirection.copy( direction ); | ||
| matrix1.makeBasis( side, normal, vector.copy( direction ).negate() ); | ||
| } | ||
| function moveTo( position ) { | ||
| point1.copy( position ); | ||
| matrix1.lookAt( point2, point1, up ); | ||
| point2.copy( position ); | ||
| matrix2.copy( matrix1 ); | ||
| lastNormal.set( 0, 1, 0 ); | ||
| isFirstSegment = true; | ||
| endCapStartIndex = null; | ||
| endCapVertexCount = 0; | ||
| } | ||
@@ -176,9 +472,41 @@ | ||
| point1.copy( position ); | ||
| matrix1.lookAt( point2, point1, up ); | ||
| stroke( point1, point2, matrix1, matrix2 ); | ||
| direction.subVectors( point1, point2 ); | ||
| const length = direction.length(); | ||
| if ( length === 0 ) return; | ||
| direction.normalize(); | ||
| calculateRMF(); | ||
| if ( isFirstSegment === true ) { | ||
| color2.copy( color1 ); | ||
| size2 = size1; | ||
| matrix2.copy( matrix1 ); | ||
| addCap( point2, matrix2, false, size2 ); | ||
| // End cap is added immediately after start cap and updated in-place | ||
| endCapStartIndex = geometry.drawRange.count; | ||
| addCap( point1, matrix1, true, size1 ); | ||
| endCapVertexCount = geometry.drawRange.count - endCapStartIndex; | ||
| } | ||
| stroke( point1, point2, matrix1, matrix2, size1, size2 ); | ||
| updateEndCap( point1, matrix1, size1 ); | ||
| point2.copy( point1 ); | ||
| matrix2.copy( matrix1 ); | ||
| color2.copy( color1 ); | ||
| size2 = size1; | ||
| isFirstSegment = false; | ||
| } | ||
@@ -188,6 +516,12 @@ | ||
| size = value; | ||
| size1 = value; | ||
| } | ||
| function setColor( value ) { | ||
| color1.copy( value ); | ||
| } | ||
| // | ||
@@ -213,3 +547,3 @@ | ||
| count = geometry.drawRange.count; | ||
| count = end; | ||
@@ -257,2 +591,11 @@ } | ||
| /** | ||
| * Sets the color of newly rendered tube segments. | ||
| * | ||
| * @method | ||
| * @name TubePainter#setColor | ||
| * @param {Color} color The color. | ||
| */ | ||
| setColor: setColor, | ||
| /** | ||
| * Updates the internal geometry buffers so the new painted | ||
@@ -259,0 +602,0 @@ * segments are rendered. |
@@ -17,3 +17,3 @@ import { | ||
| * | ||
| * The implementation is based on [Progressive Mesh type Polygon Reduction Algorithm]{@link https://web.archive.org/web/20230610044040/http://www.melax.com/polychop/} | ||
| * The implementation is based on [Progressive Mesh type Polygon Reduction Algorithm](https://web.archive.org/web/20230610044040/http://www.melax.com/polychop/) | ||
| * by Stan Melax in 1998. | ||
@@ -20,0 +20,0 @@ * |
@@ -390,4 +390,5 @@ import { | ||
| * @property {boolean} [useDepthTexture=true] - Whether to store depth values in a texture or not. | ||
| * @property {Vector2} [resolution] - Resolution for the Reflector Pass. | ||
| **/ | ||
| export { ReflectorForSSRPass }; |
@@ -11,3 +11,3 @@ import { | ||
| /** | ||
| * Represents a skydome for scene backgrounds. Based on [A Practical Analytic Model for Daylight]{@link https://www.researchgate.net/publication/220720443_A_Practical_Analytic_Model_for_Daylight} | ||
| * Represents a skydome for scene backgrounds. Based on [A Practical Analytic Model for Daylight](https://www.researchgate.net/publication/220720443_A_Practical_Analytic_Model_for_Daylight) | ||
| * aka The Preetham Model, the de facto standard for analytical skydomes. | ||
@@ -14,0 +14,0 @@ * |
@@ -12,3 +12,3 @@ import { | ||
| /** | ||
| * Represents a skydome for scene backgrounds. Based on [A Practical Analytic Model for Daylight]{@link https://www.researchgate.net/publication/220720443_A_Practical_Analytic_Model_for_Daylight} | ||
| * Represents a skydome for scene backgrounds. Based on [A Practical Analytic Model for Daylight](https://www.researchgate.net/publication/220720443_A_Practical_Analytic_Model_for_Daylight) | ||
| * aka The Preetham Model, the de facto standard for analytical skydomes. | ||
@@ -15,0 +15,0 @@ * |
@@ -24,5 +24,5 @@ import { | ||
| * | ||
| * - [Flat mirror for three.js]{@link https://github.com/Slayvin} | ||
| * - [An implementation of water shader based on the flat mirror]{@link https://home.adelphi.edu/~stemkoski/} | ||
| * - [Water shader explanations in WebGL]{@link http://29a.ch/slides/2012/webglwater/ } | ||
| * - [Flat mirror for three.js](https://github.com/Slayvin) | ||
| * - [An implementation of water shader based on the flat mirror](https://home.adelphi.edu/~stemkoski/) | ||
| * - [Water shader explanations in WebGL](http://29a.ch/slides/2012/webglwater/ ) | ||
| * | ||
@@ -29,0 +29,0 @@ * @augments Mesh |
@@ -18,5 +18,5 @@ import { | ||
| * | ||
| * - [Flat mirror for three.js]{@link https://github.com/Slayvin} | ||
| * - [An implementation of water shader based on the flat mirror]{@link https://home.adelphi.edu/~stemkoski/} | ||
| * - [Water shader explanations in WebGL]{@link http://29a.ch/slides/2012/webglwater/ } | ||
| * - [Flat mirror for three.js](https://github.com/Slayvin) | ||
| * - [An implementation of water shader based on the flat mirror](https://home.adelphi.edu/~stemkoski/) | ||
| * - [Water shader explanations in WebGL](http://29a.ch/slides/2012/webglwater/ ) | ||
| * | ||
@@ -55,3 +55,3 @@ * @augments Mesh | ||
| */ | ||
| this.resolution = options.resolution !== undefined ? options.resolution : 0.5; | ||
| this.resolutionScale = options.resolutionScale !== undefined ? options.resolutionScale : 0.5; | ||
@@ -166,3 +166,3 @@ // Uniforms | ||
| mirrorSampler.uvNode = mirrorSampler.uvNode.add( distortion ); | ||
| mirrorSampler.resolution = this.resolution; | ||
| mirrorSampler.reflector.resolutionScale = this.resolutionScale; | ||
@@ -189,3 +189,3 @@ this.add( mirrorSampler.target ); | ||
| * @typedef {Object} WaterMesh~Options | ||
| * @property {number} [resolution=0.5] - The resolution scale. | ||
| * @property {number} [resolutionScale=0.5] - The resolution scale. | ||
| * @property {?Texture} [waterNormals=null] - The water's normal map. | ||
@@ -192,0 +192,0 @@ * @property {number} [alpha=1] - The alpha value. |
@@ -64,3 +64,3 @@ import { | ||
| this._heightMap = this._generateHeightmap( dt_size ); | ||
| this.uniforms[ 'tDisp' ].value = this.heightMap; | ||
| this.uniforms[ 'tDisp' ].value = this._heightMap; | ||
@@ -144,3 +144,3 @@ this._fsQuad = new FullScreenQuad( this.material ); | ||
| this.heightMap.dispose(); | ||
| this._heightMap.dispose(); | ||
@@ -147,0 +147,0 @@ this._fsQuad.dispose(); |
@@ -25,3 +25,3 @@ import { | ||
| * Reference: | ||
| * - [Bloom in Unreal Engine]{@link https://docs.unrealengine.com/latest/INT/Engine/Rendering/PostProcessEffects/Bloom/} | ||
| * - [Bloom in Unreal Engine](https://docs.unrealengine.com/latest/INT/Engine/Rendering/PostProcessEffects/Bloom/) | ||
| * | ||
@@ -149,3 +149,5 @@ * ```js | ||
| this.separableBlurMaterials = []; | ||
| const kernelSizeArray = [ 3, 5, 7, 9, 11 ]; | ||
| // These sizes have been changed to account for the altered coefficients-calculation to avoid blockiness, | ||
| // while retaining the same blur-strength. For details see https://github.com/mrdoob/three.js/pull/31528 | ||
| const kernelSizeArray = [ 6, 10, 14, 18, 22 ]; | ||
| resx = Math.round( this.resolution.x / 2 ); | ||
@@ -381,6 +383,7 @@ resy = Math.round( this.resolution.y / 2 ); | ||
| const coefficients = []; | ||
| const sigma = kernelRadius / 3; | ||
| for ( let i = 0; i < kernelRadius; i ++ ) { | ||
| coefficients.push( 0.39894 * Math.exp( - 0.5 * i * i / ( kernelRadius * kernelRadius ) ) / kernelRadius ); | ||
| coefficients.push( 0.39894 * Math.exp( - 0.5 * i * i / ( sigma * sigma ) ) / sigma ); | ||
@@ -426,6 +429,5 @@ } | ||
| vec3 sample2 = texture2D( colorTexture, vUv - uvOffset ).rgb; | ||
| diffuseSum += (sample1 + sample2) * w; | ||
| weightSum += 2.0 * w; | ||
| diffuseSum += ( sample1 + sample2 ) * w; | ||
| } | ||
| gl_FragColor = vec4(diffuseSum/weightSum, 1.0); | ||
| gl_FragColor = vec4( diffuseSum, 1.0 ); | ||
| }` | ||
@@ -432,0 +434,0 @@ } ); |
@@ -19,3 +19,3 @@ import { | ||
| * | ||
| * @param {DOMElement} [element] - The DOM element. | ||
| * @param {HTMLElement} [element] - The DOM element. | ||
| */ | ||
@@ -38,3 +38,3 @@ constructor( element = document.createElement( 'div' ) ) { | ||
| * | ||
| * @type {DOMElement} | ||
| * @type {HTMLElement} | ||
| * @readonly | ||
@@ -64,2 +64,3 @@ * @default true | ||
| if ( | ||
| object.element && | ||
| object.element instanceof object.element.ownerDocument.defaultView.Element && | ||
@@ -138,3 +139,3 @@ object.element.parentNode !== null | ||
| * | ||
| * @type {DOMElement} | ||
| * @type {HTMLElement} | ||
| */ | ||
@@ -144,2 +145,12 @@ this.domElement = domElement; | ||
| /** | ||
| * Controls whether the renderer assigns `z-index` values to CSS2DObject DOM elements. | ||
| * If set to `true`, z-index values are assigned first based on the `renderOrder` | ||
| * and secondly - the distance to the camera. If set to `false`, no z-index values are assigned. | ||
| * | ||
| * @type {boolean} | ||
| * @default true | ||
| */ | ||
| this.sortObjects = true; | ||
| /** | ||
| * Returns an object containing the width and height of the renderer. | ||
@@ -173,3 +184,3 @@ * | ||
| renderObject( scene, scene, camera ); | ||
| zOrder( scene ); | ||
| if ( this.sortObjects ) zOrder( scene ); | ||
@@ -319,3 +330,3 @@ }; | ||
| * @typedef {Object} CSS2DRenderer~Parameters | ||
| * @property {DOMElement} [element] - A DOM element where the renderer appends its child-elements. | ||
| * @property {HTMLElement} [element] - A DOM element where the renderer appends its child-elements. | ||
| * If not passed in here, a new div element will be created. | ||
@@ -322,0 +333,0 @@ **/ |
@@ -25,3 +25,3 @@ import { | ||
| * | ||
| * @param {DOMElement} [element] - The DOM element. | ||
| * @param {HTMLElement} [element] - The DOM element. | ||
| */ | ||
@@ -44,3 +44,3 @@ constructor( element = document.createElement( 'div' ) ) { | ||
| * | ||
| * @type {DOMElement} | ||
| * @type {HTMLElement} | ||
| * @readonly | ||
@@ -61,2 +61,3 @@ * @default true | ||
| if ( | ||
| object.element && | ||
| object.element instanceof object.element.ownerDocument.defaultView.Element && | ||
@@ -100,3 +101,3 @@ object.element.parentNode !== null | ||
| * | ||
| * @param {DOMElement} [element] - The DOM element. | ||
| * @param {HTMLElement} [element] - The DOM element. | ||
| */ | ||
@@ -145,3 +146,3 @@ constructor( element ) { | ||
| * This renderer can be used to apply hierarchical 3D transformations to DOM elements | ||
| * via the CSS3 [transform]{@link https://www.w3schools.com/cssref/css3_pr_transform.asp} property. | ||
| * via the CSS3 [transform](https://www.w3schools.com/cssref/css3_pr_transform.asp) property. | ||
| * `CSS3DRenderer` is particularly interesting if you want to apply 3D effects to a website without | ||
@@ -187,3 +188,3 @@ * canvas based rendering. It can also be used in order to combine DOM elements with WebGLcontent. | ||
| * | ||
| * @type {DOMElement} | ||
| * @type {HTMLElement} | ||
| */ | ||
@@ -455,3 +456,3 @@ this.domElement = domElement; | ||
| * @typedef {Object} CSS3DRenderer~Parameters | ||
| * @property {DOMElement} [element] - A DOM element where the renderer appends its child-elements. | ||
| * @property {HTMLElement} [element] - A DOM element where the renderer appends its child-elements. | ||
| * If not passed in here, a new div element will be created. | ||
@@ -458,0 +459,0 @@ **/ |
@@ -123,3 +123,3 @@ import { | ||
| * | ||
| * @type {DOMElement} | ||
| * @type {SVGSVGElement} | ||
| */ | ||
@@ -126,0 +126,0 @@ this.domElement = _svg; |
@@ -8,3 +8,3 @@ /** | ||
| * ACES Filmic Tone Mapping Shader by Stephen Hill. | ||
| * Reference: [ltc_blit.fs]{@link https://github.com/selfshadow/ltc_code/blob/master/webgl/shaders/ltc/ltc_blit.fs} | ||
| * Reference: [ltc_blit.fs](https://github.com/selfshadow/ltc_code/blob/master/webgl/shaders/ltc/ltc_blit.fs) | ||
| * | ||
@@ -11,0 +11,0 @@ * This implementation of ACES is modified to accommodate a brighter viewing environment. |
@@ -7,3 +7,3 @@ /** | ||
| /** | ||
| * Inspired by [Three.js FBO motion trails]{@link https://codepen.io/brunoimbrizi/pen/MoRJaN?page=1&}. | ||
| * Inspired by [Three.js FBO motion trails](https://codepen.io/brunoimbrizi/pen/MoRJaN?page=1&). | ||
| * | ||
@@ -10,0 +10,0 @@ * @constant |
@@ -9,3 +9,3 @@ | ||
| * Bleach bypass shader [http://en.wikipedia.org/wiki/Bleach_bypass] based on | ||
| * [Nvidia Shader library]{@link http://developer.download.nvidia.com/shaderlibrary/webpages/shader_library.html#post_bleach_bypass}. | ||
| * [Nvidia Shader library](http://developer.download.nvidia.com/shaderlibrary/webpages/shader_library.html#post_bleach_bypass). | ||
| * | ||
@@ -12,0 +12,0 @@ * @constant |
@@ -8,3 +8,3 @@ /** | ||
| * Depth-of-field shader with bokeh ported from | ||
| * [GLSL shader by Martins Upitis]{@link http://artmartinsh.blogspot.com/2010/02/glsl-lens-blur-filter-with-bokeh.html}. | ||
| * [GLSL shader by Martins Upitis](http://artmartinsh.blogspot.com/2010/02/glsl-lens-blur-filter-with-bokeh.html). | ||
| * | ||
@@ -11,0 +11,0 @@ * @constant |
@@ -12,3 +12,3 @@ import { | ||
| * Depth-of-field shader with bokeh ported from | ||
| * [GLSL shader by Martins Upitis]{@link http://blenderartists.org/forum/showthread.php?237488-GLSL-depth-of-field-with-bokeh-v2-4-(update)}. | ||
| * [GLSL shader by Martins Upitis](http://blenderartists.org/forum/showthread.php?237488-GLSL-depth-of-field-with-bokeh-v2-4-(update)). | ||
| * | ||
@@ -15,0 +15,0 @@ * Requires #define RINGS and SAMPLES integers |
@@ -11,3 +11,3 @@ import { | ||
| /** | ||
| * Dot screen shader based on [glfx.js sepia shader]{@link https://github.com/evanw/glfx.js}. | ||
| * Dot screen shader based on [glfx.js sepia shader](https://github.com/evanw/glfx.js). | ||
| * | ||
@@ -14,0 +14,0 @@ * @constant |
@@ -7,3 +7,3 @@ /** | ||
| /** | ||
| * Focus shader based on [PaintEffect postprocess from ro.me]{@link http://code.google.com/p/3-dreams-of-black/source/browse/deploy/js/effects/PaintEffect.js}. | ||
| * Focus shader based on [PaintEffect postprocess from ro.me](http://code.google.com/p/3-dreams-of-black/source/browse/deploy/js/effects/PaintEffect.js). | ||
| * | ||
@@ -10,0 +10,0 @@ * @constant |
@@ -25,3 +25,3 @@ import { | ||
| * References: | ||
| * - [Sousa2008, Crysis Next Gen Effects, GDC2008]{@link http://www.crytek.com/sites/default/files/GDC08_SousaT_CrysisEffects.ppt}. | ||
| * - [Sousa2008, Crysis Next Gen Effects, GDC2008](http://www.crytek.com/sites/default/files/GDC08_SousaT_CrysisEffects.ppt). | ||
| * | ||
@@ -28,0 +28,0 @@ * @constant |
@@ -18,4 +18,4 @@ import { | ||
| * References: | ||
| * - [Practical Realtime Strategies for Accurate Indirect Occlusion]{@link https://iryoku.com/downloads/Practical-Realtime-Strategies-for-Accurate-Indirect-Occlusion.pdf}. | ||
| * - [Horizon-Based Indirect Lighting (HBIL)]{@link https://github.com/Patapom/GodComplex/blob/master/Tests/TestHBIL/2018%20Mayaux%20-%20Horizon-Based%20Indirect%20Lighting%20(HBIL).pdf} | ||
| * - [Practical Realtime Strategies for Accurate Indirect Occlusion](https://iryoku.com/downloads/Practical-Realtime-Strategies-for-Accurate-Indirect-Occlusion.pdf). | ||
| * - [Horizon-Based Indirect Lighting (HBIL)](https://github.com/Patapom/GodComplex/blob/master/Tests/TestHBIL/2018%20Mayaux%20-%20Horizon-Based%20Indirect%20Lighting%20(HBIL).pdf) | ||
| * | ||
@@ -22,0 +22,0 @@ * @constant |
@@ -10,3 +10,3 @@ /** | ||
| * Ported from: {@link http://pixelshaders.com/editor/} | ||
| * by [Toby Schachman]{@link http://tobyschachman.com/} | ||
| * by [Toby Schachman](http://tobyschachman.com/) | ||
| * | ||
@@ -13,0 +13,0 @@ * sides: number of reflections |
@@ -16,4 +16,4 @@ import { | ||
| * References: | ||
| * - [Self-Supervised Poisson-Gaussian Denoising]{@link https://openaccess.thecvf.com/content/WACV2021/papers/Khademi_Self-Supervised_Poisson-Gaussian_Denoising_WACV_2021_paper.pdf}. | ||
| * - [Poisson2Sparse: Self-Supervised Poisson Denoising From a Single Image]{@link https://arxiv.org/pdf/2206.01856.pdf} | ||
| * - [Self-Supervised Poisson-Gaussian Denoising](https://openaccess.thecvf.com/content/WACV2021/papers/Khademi_Self-Supervised_Poisson-Gaussian_Denoising_WACV_2021_paper.pdf). | ||
| * - [Poisson2Sparse: Self-Supervised Poisson Denoising From a Single Image](https://arxiv.org/pdf/2206.01856.pdf) | ||
| * | ||
@@ -20,0 +20,0 @@ * @constant |
@@ -7,3 +7,3 @@ /** | ||
| /** | ||
| * Sepia tone shader based on [glfx.js sepia shader]{@link https://github.com/evanw/glfx.js}. | ||
| * Sepia tone shader based on [glfx.js sepia shader](https://github.com/evanw/glfx.js). | ||
| * | ||
@@ -10,0 +10,0 @@ * @constant |
@@ -11,3 +11,3 @@ import { | ||
| * References: | ||
| * - [3D Game Shaders For Beginners, Screen Space Reflection (SSR)]{@link https://lettier.github.io/3d-game-shaders-for-beginners/screen-space-reflection.html}. | ||
| * - [3D Game Shaders For Beginners, Screen Space Reflection (SSR)](https://lettier.github.io/3d-game-shaders-for-beginners/screen-space-reflection.html). | ||
| * | ||
@@ -14,0 +14,0 @@ * @module SSRShader |
@@ -25,3 +25,3 @@ import { | ||
| * | ||
| * Based on GDC 2011 – [Approximating Translucency for a Fast, Cheap and Convincing Subsurface Scattering Look]{@link https://colinbarrebrisebois.com/2011/03/07/gdc-2011-approximating-translucency-for-a-fast-cheap-and-convincing-subsurface-scattering-look/} | ||
| * Based on GDC 2011 – [Approximating Translucency for a Fast, Cheap and Convincing Subsurface Scattering Look](https://colinbarrebrisebois.com/2011/03/07/gdc-2011-approximating-translucency-for-a-fast-cheap-and-convincing-subsurface-scattering-look/) | ||
| * | ||
@@ -28,0 +28,0 @@ * @constant |
@@ -11,3 +11,3 @@ import { | ||
| /** | ||
| * Triangle blur shader based on [glfx.js triangle blur shader]{@link https://github.com/evanw/glfx.js}. | ||
| * Triangle blur shader based on [glfx.js triangle blur shader](https://github.com/evanw/glfx.js). | ||
| * | ||
@@ -14,0 +14,0 @@ * A basic blur filter, which convolves the image with a |
@@ -7,3 +7,3 @@ /** | ||
| /** | ||
| * Based on [PaintEffect postprocess from ro.me]{@link http://code.google.com/p/3-dreams-of-black/source/browse/deploy/js/effects/PaintEffect.js}. | ||
| * Based on [PaintEffect postprocess from ro.me](http://code.google.com/p/3-dreams-of-black/source/browse/deploy/js/effects/PaintEffect.js). | ||
| * | ||
@@ -10,0 +10,0 @@ * @constant |
@@ -684,2 +684,8 @@ import { REVISION } from 'three/webgpu'; | ||
| if ( node.needsToVar ) { | ||
| varStr = varStr + '.toVar()'; | ||
| } | ||
| return varStr; | ||
@@ -754,2 +760,3 @@ | ||
| mutableParam.linker.assignments.push( mutableParam ); | ||
| mutableParam.needsToVar = true; // force var declaration | ||
@@ -756,0 +763,0 @@ node.body.unshift( mutableParam ); |
| import { RenderTarget, Vector2, QuadMesh, NodeMaterial, RendererUtils, TempNode, NodeUpdateType } from 'three/webgpu'; | ||
| import { nodeObject, Fn, float, uv, texture, passTexture, uniform, sign, max, convertToTexture } from 'three/tsl'; | ||
| import { nodeObject, Fn, float, uv, texture, passTexture, sign, max, convertToTexture } from 'three/tsl'; | ||
| const _size = /*@__PURE__*/ new Vector2(); | ||
| const _quadMeshComp = /*@__PURE__*/ new QuadMesh(); | ||
| const _quadMesh = /*@__PURE__*/ new QuadMesh(); | ||
@@ -27,5 +27,5 @@ let _rendererState; | ||
| * @param {TextureNode} textureNode - The texture node that represents the input of the effect. | ||
| * @param {number} [damp=0.96] - The damping intensity. A higher value means a stronger after image effect. | ||
| * @param {Node<float>} [damp=0.96] - The damping intensity. A higher value means a stronger after image effect. | ||
| */ | ||
| constructor( textureNode, damp = 0.96 ) { | ||
| constructor( textureNode, damp = float( 0.96 ) ) { | ||
@@ -42,9 +42,2 @@ super( 'vec4' ); | ||
| /** | ||
| * The texture represents the pervious frame. | ||
| * | ||
| * @type {TextureNode} | ||
| */ | ||
| this.textureNodeOld = texture( null ); | ||
| /** | ||
| * How quickly the after-image fades. A higher value means the after-image | ||
@@ -54,5 +47,5 @@ * persists longer, while a lower value means it fades faster. Should be in | ||
| * | ||
| * @type {UniformNode<float>} | ||
| * @type {Node<float>} | ||
| */ | ||
| this.damp = uniform( damp ); | ||
| this.damp = damp; | ||
@@ -86,2 +79,10 @@ /** | ||
| /** | ||
| * The texture represents the pervious frame. | ||
| * | ||
| * @private | ||
| * @type {TextureNode} | ||
| */ | ||
| this._textureNodeOld = texture( this._oldRT.texture ); | ||
| /** | ||
| * The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node renders | ||
@@ -146,13 +147,16 @@ * its effect once per frame in `updateBefore()`. | ||
| const currentTexture = textureNode.value; | ||
| // make sure texture nodes point to correct render targets | ||
| this.textureNodeOld.value = this._oldRT.texture; | ||
| this._textureNode.value = this._compRT.texture; | ||
| this._textureNodeOld.value = this._oldRT.texture; | ||
| // comp | ||
| _quadMeshComp.material = this._materialComposed; | ||
| // composite | ||
| _quadMesh.material = this._materialComposed; | ||
| _quadMesh.name = 'AfterImage'; | ||
| renderer.setRenderTarget( this._compRT ); | ||
| _quadMeshComp.render( renderer ); | ||
| _quadMesh.render( renderer ); | ||
| // Swap the textures | ||
| // swap | ||
@@ -165,4 +169,2 @@ const temp = this._oldRT; | ||
| textureNode.value = currentTexture; | ||
| RendererUtils.restoreRendererState( renderer, _rendererState ); | ||
@@ -181,3 +183,3 @@ | ||
| const textureNode = this.textureNode; | ||
| const textureNodeOld = this.textureNodeOld; | ||
| const textureNodeOld = this._textureNodeOld; | ||
@@ -244,7 +246,7 @@ // | ||
| * @param {Node<vec4>} node - The node that represents the input of the effect. | ||
| * @param {number} [damp=0.96] - The damping intensity. A higher value means a stronger after image effect. | ||
| * @param {(Node<float>|number)} [damp=0.96] - The damping intensity. A higher value means a stronger after image effect. | ||
| * @returns {AfterImageNode} | ||
| */ | ||
| export const afterImage = ( node, damp ) => nodeObject( new AfterImageNode( convertToTexture( node ), damp ) ); | ||
| export const afterImage = ( node, damp ) => nodeObject( new AfterImageNode( convertToTexture( node ), nodeObject( damp ) ) ); | ||
| export default AfterImageNode; |
@@ -72,3 +72,3 @@ import { RenderTarget, Vector2, TempNode, QuadMesh, NodeMaterial, RendererUtils } from 'three/webgpu'; | ||
| * | ||
| * @type {float} | ||
| * @type {number} | ||
| */ | ||
@@ -162,2 +162,3 @@ this.resolutionScale = 1; | ||
| _quadMesh.material = this._material; | ||
| _quadMesh.name = 'Anamorphic'; | ||
@@ -164,0 +165,0 @@ this.setSize( map.image.width, map.image.height ); |
@@ -303,2 +303,3 @@ import { HalfFloatType, RenderTarget, Vector2, Vector3, TempNode, QuadMesh, NodeMaterial, RendererUtils, NodeUpdateType } from 'three/webgpu'; | ||
| _quadMesh.material = this._highPassFilterMaterial; | ||
| _quadMesh.name = 'Bloom [ High Pass ]'; | ||
| _quadMesh.render( renderer ); | ||
@@ -317,2 +318,3 @@ | ||
| renderer.setRenderTarget( this._renderTargetsHorizontal[ i ] ); | ||
| _quadMesh.name = `Bloom [ Blur Horizontal - ${ i } ]`; | ||
| _quadMesh.render( renderer ); | ||
@@ -323,2 +325,3 @@ | ||
| renderer.setRenderTarget( this._renderTargetsVertical[ i ] ); | ||
| _quadMesh.name = `Bloom [ Blur Vertical - ${ i } ]`; | ||
| _quadMesh.render( renderer ); | ||
@@ -334,2 +337,3 @@ | ||
| _quadMesh.material = this._compositeMaterial; | ||
| _quadMesh.name = 'Bloom [ Composite ]'; | ||
| _quadMesh.render( renderer ); | ||
@@ -336,0 +340,0 @@ |
@@ -17,2 +17,3 @@ import { Fn, vec2, uv, Loop, vec4, premultiplyAlpha, unpremultiplyAlpha, max, int, textureSize, nodeObject, convertToTexture } from 'three/tsl'; | ||
| * | ||
| * @tsl | ||
| * @function | ||
@@ -19,0 +20,0 @@ * @param {Node<vec4>} textureNode - The texture node that should be blurred. |
@@ -262,2 +262,3 @@ import { DataTexture, RepeatWrapping, Vector2, Vector3, TempNode } from 'three/webgpu'; | ||
| * | ||
| * @private | ||
| * @param {number} numSamples - The number of samples. | ||
@@ -287,2 +288,3 @@ * @param {number} numRings - The number of rings. | ||
| * | ||
| * @private | ||
| * @param {number} [size=64] - The texture size. | ||
@@ -289,0 +291,0 @@ * @return {DataTexture} The generated noise texture. |
@@ -288,2 +288,3 @@ import { TempNode, NodeMaterial, NodeUpdateType, RenderTarget, Vector2, HalfFloatType, RedFormat, QuadMesh, RendererUtils } from 'three/webgpu'; | ||
| renderer.setRenderTarget( this._CoCRT ); | ||
| _quadMesh.name = 'DoF [ CoC ]'; | ||
| _quadMesh.render( renderer ); | ||
@@ -298,2 +299,3 @@ | ||
| renderer.setRenderTarget( this._CoCBlurredRT ); | ||
| _quadMesh.name = 'DoF [ CoC Blur ]'; | ||
| _quadMesh.render( renderer ); | ||
@@ -307,2 +309,3 @@ | ||
| renderer.setRenderTarget( this._blur64RT ); | ||
| _quadMesh.name = 'DoF [ Blur64 Near ]'; | ||
| _quadMesh.render( renderer ); | ||
@@ -314,2 +317,3 @@ | ||
| renderer.setRenderTarget( this._blur16NearRT ); | ||
| _quadMesh.name = 'DoF [ Blur16 Near ]'; | ||
| _quadMesh.render( renderer ); | ||
@@ -323,2 +327,3 @@ | ||
| renderer.setRenderTarget( this._blur64RT ); | ||
| _quadMesh.name = 'DoF [ Blur64 Far ]'; | ||
| _quadMesh.render( renderer ); | ||
@@ -330,2 +335,3 @@ | ||
| renderer.setRenderTarget( this._blur16FarRT ); | ||
| _quadMesh.name = 'DoF [ Blur16 Far ]'; | ||
| _quadMesh.render( renderer ); | ||
@@ -337,2 +343,3 @@ | ||
| renderer.setRenderTarget( this._compositeRT ); | ||
| _quadMesh.name = 'DoF [ Composite ]'; | ||
| _quadMesh.render( renderer ); | ||
@@ -339,0 +346,0 @@ |
@@ -30,3 +30,3 @@ import { RenderTarget, Vector2, NodeMaterial, RendererUtils, QuadMesh, TempNode, NodeUpdateType } from 'three/webgpu'; | ||
| * @param {boolean} [options.premultipliedAlpha=false] - Whether to use premultiplied alpha for the blur effect. | ||
| * @param {Vector2} [options.resolution=new Vector2(1, 1)] - The resolution of the effect. 0.5 means half the resolution of the texture node. | ||
| * @param {number} [options.resolutionScale=1] - The resolution of the effect. 0.5 means half the resolution of the texture node. | ||
| */ | ||
@@ -114,3 +114,3 @@ constructor( textureNode, directionNode = null, sigma = 4, options = {} ) { | ||
| * | ||
| * @type {float} | ||
| * @type {number} | ||
| * @default (1) | ||
@@ -181,2 +181,3 @@ */ | ||
| _quadMesh.name = 'Gaussian Blur [ Horizontal Pass ]'; | ||
| _quadMesh.render( renderer ); | ||
@@ -191,2 +192,3 @@ | ||
| _quadMesh.name = 'Gaussian Blur [ Vertical Pass ]'; | ||
| _quadMesh.render( renderer ); | ||
@@ -360,3 +362,3 @@ | ||
| * @param {boolean} [options.premultipliedAlpha=false] - Whether to use premultiplied alpha for the blur effect. | ||
| * @param {Vector2} [options.resolution=new Vector2(1, 1)] - The resolution of the effect. 0.5 means half the resolution of the texture node. | ||
| * @param {number} [options.resolutionScale=1] - The resolution of the effect. 0.5 means half the resolution of the texture node. | ||
| * @returns {GaussianBlurNode} | ||
@@ -363,0 +365,0 @@ */ |
@@ -1,2 +0,2 @@ | ||
| import { DataTexture, RenderTarget, RepeatWrapping, Vector2, Vector3, TempNode, QuadMesh, NodeMaterial, RendererUtils } from 'three/webgpu'; | ||
| import { DataTexture, RenderTarget, RepeatWrapping, Vector2, Vector3, TempNode, QuadMesh, NodeMaterial, RendererUtils, RedFormat } from 'three/webgpu'; | ||
| import { reference, logarithmicDepthToViewZ, viewZToPerspectiveDepth, getNormalFromDepth, getScreenPosition, getViewPosition, nodeObject, Fn, float, NodeUpdateType, uv, uniform, Loop, vec2, vec3, vec4, int, dot, max, pow, abs, If, textureSize, sin, cos, PI, texture, passTexture, mat3, add, normalize, mul, cross, div, mix, sqrt, sub, acos, clamp } from 'three/tsl'; | ||
@@ -7,2 +7,5 @@ | ||
| // From Activision GTAO paper: https://www.activision.com/cdn/research/s2016_pbs_activision_occlusion.pptx | ||
| const _temporalRotations = [ 60, 300, 180, 240, 120, 0 ]; | ||
| let _rendererState; | ||
@@ -52,3 +55,3 @@ | ||
| super( 'vec4' ); | ||
| super( 'float' ); | ||
@@ -95,3 +98,3 @@ /** | ||
| */ | ||
| this._aoRenderTarget = new RenderTarget( 1, 1, { depthBuffer: false } ); | ||
| this._aoRenderTarget = new RenderTarget( 1, 1, { depthBuffer: false, format: RedFormat } ); | ||
| this._aoRenderTarget.texture.name = 'GTAONode.AO'; | ||
@@ -157,2 +160,16 @@ | ||
| /** | ||
| * Whether to use temporal filtering or not. Setting this property to | ||
| * `true` requires the usage of `TRAANode`. This will help to reduce noise | ||
| * although it introduces typical TAA artifacts like ghosting and temporal | ||
| * instabilities. | ||
| * | ||
| * If setting this property to `false`, a manual denoise via `DenoiseNode` | ||
| * might be required. | ||
| * | ||
| * @type {boolean} | ||
| * @default false | ||
| */ | ||
| this.useTemporalFiltering = false; | ||
| /** | ||
| * The node represents the internal noise texture used by the AO. | ||
@@ -198,2 +215,9 @@ * | ||
| /** | ||
| * Temporal direction that influences the rotation angle for each slice. | ||
| * | ||
| * @type {UniformNode<float>} | ||
| */ | ||
| this._temporalDirection = uniform( 0 ); | ||
| /** | ||
| * The material that is used to render the effect. | ||
@@ -255,2 +279,16 @@ * | ||
| // update temporal uniforms | ||
| if ( this.useTemporalFiltering === true ) { | ||
| const frameId = frame.frameId; | ||
| this._temporalDirection.value = _temporalRotations[ frameId % 6 ] / 360; | ||
| } else { | ||
| this._temporalDirection.value = 0; | ||
| } | ||
| // | ||
@@ -262,2 +300,3 @@ | ||
| _quadMesh.material = this._material; | ||
| _quadMesh.name = 'AO'; | ||
@@ -322,2 +361,3 @@ // clear | ||
| noiseUv = noiseUv.mul( this.resolution.div( noiseResolution ) ); | ||
| const noiseTexel = sampleNoise( noiseUv ); | ||
@@ -338,3 +378,3 @@ const randomVec = noiseTexel.xyz.mul( 2.0 ).sub( 1.0 ); | ||
| const angle = float( i ).div( float( DIRECTIONS ) ).mul( PI ).toVar(); | ||
| const angle = float( i ).div( float( DIRECTIONS ) ).mul( PI ).add( this._temporalDirection ).toVar(); | ||
| const sampleDir = vec4( cos( angle ), sin( angle ), 0., add( 0.5, mul( 0.5, noiseTexel.w ) ) ); | ||
@@ -404,3 +444,3 @@ sampleDir.xyz = normalize( kernelMatrix.mul( sampleDir.xyz ) ); | ||
| return vec4( vec3( ao ), 1.0 ); | ||
| return ao; | ||
@@ -407,0 +447,0 @@ } ); |
@@ -15,2 +15,3 @@ import { float, Fn, vec2, uv, sin, rand, degrees, cos, Loop, vec4, premultiplyAlpha, unpremultiplyAlpha, convertToTexture, nodeObject } from 'three/tsl'; | ||
| * | ||
| * @tsl | ||
| * @function | ||
@@ -17,0 +18,0 @@ * @param {Node<vec4>} textureNode - The texture node that should be blurred. |
@@ -458,2 +458,4 @@ import { DepthTexture, FloatType, RenderTarget, Vector2, TempNode, QuadMesh, NodeMaterial, RendererUtils, NodeUpdateType } from 'three/webgpu'; | ||
| const currentSceneName = scene.name; | ||
| // 1. Draw non-selected objects in the depth buffer | ||
@@ -474,2 +476,3 @@ | ||
| scene.name = 'Outline [ Non-Selected Objects Pass ]'; | ||
| renderer.render( scene, camera ); | ||
@@ -492,2 +495,3 @@ | ||
| scene.name = 'Outline [ Selected Objects Pass ]'; | ||
| renderer.render( scene, camera ); | ||
@@ -501,5 +505,8 @@ | ||
| scene.name = currentSceneName; | ||
| // 3. Downsample to (at least) half resolution | ||
| _quadMesh.material = this._materialCopy; | ||
| _quadMesh.name = 'Outline [ Downsample ]'; | ||
| renderer.setRenderTarget( this._renderTargetMaskDownSampleBuffer ); | ||
@@ -511,2 +518,3 @@ _quadMesh.render( renderer ); | ||
| _quadMesh.material = this._edgeDetectionMaterial; | ||
| _quadMesh.name = 'Outline [ Edge Detection ]'; | ||
| renderer.setRenderTarget( this._renderTargetEdgeBuffer1 ); | ||
@@ -521,2 +529,3 @@ _quadMesh.render( renderer ); | ||
| _quadMesh.material = this._separableBlurMaterial; | ||
| _quadMesh.name = 'Outline [ Blur Half Resolution ]'; | ||
| renderer.setRenderTarget( this._renderTargetBlurBuffer1 ); | ||
@@ -537,2 +546,3 @@ _quadMesh.render( renderer ); | ||
| _quadMesh.material = this._separableBlurMaterial2; | ||
| _quadMesh.name = 'Outline [ Blur Quarter Resolution ]'; | ||
| renderer.setRenderTarget( this._renderTargetBlurBuffer2 ); | ||
@@ -550,2 +560,3 @@ _quadMesh.render( renderer ); | ||
| _quadMesh.material = this._compositeMaterial; | ||
| _quadMesh.name = 'Outline [ Blur Quarter Resolution ]'; | ||
| renderer.setRenderTarget( this._renderTargetComposite ); | ||
@@ -552,0 +563,0 @@ _quadMesh.render( renderer ); |
@@ -350,2 +350,3 @@ import { HalfFloatType, RenderTarget, Vector2, RendererUtils, QuadMesh, TempNode, NodeMaterial, NodeUpdateType, LinearFilter, LinearMipmapLinearFilter } from 'three/webgpu'; | ||
| renderer.setRenderTarget( ssrRenderTarget ); | ||
| _quadMesh.name = 'SSR [ Reflections ]'; | ||
| _quadMesh.render( renderer ); | ||
@@ -365,2 +366,3 @@ | ||
| renderer.setRenderTarget( blurRenderTarget, 0, i ); | ||
| _quadMesh.name = 'SSR [ Blur Level ' + i + ' ]'; | ||
| _quadMesh.render( renderer ); | ||
@@ -367,0 +369,0 @@ |
@@ -1,3 +0,3 @@ | ||
| import { HalfFloatType, Vector2, RenderTarget, RendererUtils, QuadMesh, NodeMaterial, TempNode, NodeUpdateType, Matrix4 } from 'three/webgpu'; | ||
| import { add, float, If, Loop, int, Fn, min, max, clamp, nodeObject, texture, uniform, uv, vec2, vec4, luminance, convertToTexture, passTexture, velocity } from 'three/tsl'; | ||
| import { HalfFloatType, Vector2, RenderTarget, RendererUtils, QuadMesh, NodeMaterial, TempNode, NodeUpdateType, Matrix4, DepthTexture } from 'three/webgpu'; | ||
| import { add, float, If, Loop, int, Fn, min, max, clamp, nodeObject, texture, uniform, uv, vec2, vec4, luminance, convertToTexture, passTexture, velocity, getViewPosition, length } from 'three/tsl'; | ||
@@ -104,2 +104,34 @@ const _quadMesh = /*@__PURE__*/ new QuadMesh(); | ||
| /** | ||
| * A uniform node holding the camera world matrix. | ||
| * | ||
| * @private | ||
| * @type {UniformNode<mat4>} | ||
| */ | ||
| this._cameraWorldMatrix = uniform( new Matrix4() ); | ||
| /** | ||
| * A uniform node holding the camera projection matrix inverse. | ||
| * | ||
| * @private | ||
| * @type {UniformNode<mat4>} | ||
| */ | ||
| this._cameraProjectionMatrixInverse = uniform( new Matrix4() ); | ||
| /** | ||
| * A uniform node holding the previous frame's view matrix. | ||
| * | ||
| * @private | ||
| * @type {UniformNode<mat4>} | ||
| */ | ||
| this._previousCameraWorldMatrix = uniform( new Matrix4() ); | ||
| /** | ||
| * A uniform node holding the previous frame's projection matrix inverse. | ||
| * | ||
| * @private | ||
| * @type {UniformNode<mat4>} | ||
| */ | ||
| this._previousCameraProjectionMatrixInverse = uniform( new Matrix4() ); | ||
| /** | ||
| * The render target that represents the history of frame data. | ||
@@ -110,3 +142,3 @@ * | ||
| */ | ||
| this._historyRenderTarget = new RenderTarget( 1, 1, { depthBuffer: false, type: HalfFloatType } ); | ||
| this._historyRenderTarget = new RenderTarget( 1, 1, { depthBuffer: false, type: HalfFloatType, depthTexture: new DepthTexture() } ); | ||
| this._historyRenderTarget.texture.name = 'TRAANode.history'; | ||
@@ -149,2 +181,10 @@ | ||
| /** | ||
| * A texture node for the previous depth buffer. | ||
| * | ||
| * @private | ||
| * @type {TextureNode} | ||
| */ | ||
| this._previousDepthNode = texture( new DepthTexture( 1, 1 ) ); | ||
| /** | ||
| * Sync the post processing stack with the TRAA node. | ||
@@ -252,2 +292,12 @@ * @private | ||
| // store previous frame matrices before updating current ones | ||
| this._previousCameraWorldMatrix.value.copy( this._cameraWorldMatrix.value ); | ||
| this._previousCameraProjectionMatrixInverse.value.copy( this._cameraProjectionMatrixInverse.value ); | ||
| // update camera matrices uniforms | ||
| this._cameraWorldMatrix.value.copy( this.camera.matrixWorld ); | ||
| this._cameraProjectionMatrixInverse.value.copy( this.camera.projectionMatrixInverse ); | ||
| // keep the TRAA in sync with the dimensions of the beauty node | ||
@@ -300,2 +350,3 @@ | ||
| _quadMesh.material = this._resolveMaterial; | ||
| _quadMesh.name = 'TRAA'; | ||
| _quadMesh.render( renderer ); | ||
@@ -308,2 +359,19 @@ renderer.setRenderTarget( null ); | ||
| // Copy current depth to previous depth buffer | ||
| const size = renderer.getDrawingBufferSize( _size ); | ||
| // only allow the depth copy if the dimensions of the history render target match with the drawing | ||
| // render buffer and thus the depth texture of the scene. For some reasons, there are timing issues | ||
| // with WebGPU resulting in different size of the drawing buffer and the beauty render target when | ||
| // resizing the browser window. This does not happen with the WebGL backend | ||
| if ( this._historyRenderTarget.height === size.height && this._historyRenderTarget.width === size.width ) { | ||
| const currentDepth = this.depthNode.value; | ||
| renderer.copyTextureToTexture( currentDepth, this._historyRenderTarget.depthTexture ); | ||
| this._previousDepthNode.value = this._historyRenderTarget.depthTexture; | ||
| } | ||
| // restore | ||
@@ -356,2 +424,3 @@ | ||
| const closestDepth = float( 1 ).toVar(); | ||
| const farthestDepth = float( 0 ).toVar(); | ||
| const closestDepthPixelPosition = vec2( 0 ).toVar(); | ||
@@ -383,2 +452,10 @@ | ||
| // find the farthest depth in the neighborhood (used to preserve edge anti-aliasing) | ||
| If( currentDepth.greaterThan( farthestDepth ), () => { | ||
| farthestDepth.assign( currentDepth ); | ||
| } ); | ||
| } ); | ||
@@ -399,7 +476,45 @@ | ||
| // flicker reduction based on luminance weighing | ||
| // calculate current frame world position | ||
| const currentWeight = float( 0.05 ).toVar(); | ||
| const currentDepth = depthTexture.sample( uvNode ).r; | ||
| const currentViewPosition = getViewPosition( uvNode, currentDepth, this._cameraProjectionMatrixInverse ); | ||
| const currentWorldPosition = this._cameraWorldMatrix.mul( vec4( currentViewPosition, 1.0 ) ).xyz; | ||
| // calculate previous frame world position from history UV and previous depth | ||
| const historyUV = uvNode.sub( offset ); | ||
| const previousDepth = this._previousDepthNode.sample( historyUV ).r; | ||
| const previousViewPosition = getViewPosition( historyUV, previousDepth, this._previousCameraProjectionMatrixInverse ); | ||
| const previousWorldPosition = this._previousCameraWorldMatrix.mul( vec4( previousViewPosition, 1.0 ) ).xyz; | ||
| // calculate difference in world positions | ||
| const worldPositionDifference = length( currentWorldPosition.sub( previousWorldPosition ) ).toVar(); | ||
| worldPositionDifference.assign( min( max( worldPositionDifference.sub( 1.0 ), 0.0 ), 1.0 ) ); | ||
| // Adaptive blend weights based on velocity magnitude suggested by CLAUDE in #32133 | ||
| // Higher velocity or position difference = more weight on current frame to reduce ghosting | ||
| const velocityMagnitude = length( offset ).toConst(); | ||
| const motionFactor = max( worldPositionDifference.mul( 0.5 ), velocityMagnitude.mul( 10.0 ) ).toVar(); | ||
| motionFactor.assign( min( motionFactor, 1.0 ) ); | ||
| const currentWeight = float( 0.05 ).add( motionFactor.mul( 0.25 ) ).toVar(); | ||
| const historyWeight = currentWeight.oneMinus().toVar(); | ||
| // zero out history weight if world positions are different (indicating motion) except on edges. | ||
| // note that the constants 0.00001 and 0.5 were suggested by CLAUDE in #32133 | ||
| const isEdge = farthestDepth.sub( closestDepth ).greaterThan( 0.00001 ); | ||
| const strongDisocclusion = worldPositionDifference.greaterThan( 0.5 ).and( isEdge.not() ); | ||
| If( strongDisocclusion, () => { | ||
| currentWeight.assign( 1.0 ); | ||
| historyWeight.assign( 0.0 ); | ||
| } ); | ||
| // flicker reduction based on luminance weighing | ||
| const compressedCurrent = currentColor.mul( float( 1 ).div( ( max( currentColor.r, currentColor.g, currentColor.b ).add( 1.0 ) ) ) ); | ||
@@ -414,4 +529,6 @@ const compressedHistory = clampedHistoryColor.mul( float( 1 ).div( ( max( clampedHistoryColor.r, clampedHistoryColor.g, clampedHistoryColor.b ).add( 1.0 ) ) ) ); | ||
| return add( currentColor.mul( currentWeight ), clampedHistoryColor.mul( historyWeight ) ).div( max( currentWeight.add( historyWeight ), 0.00001 ) ); | ||
| const smoothedOutput = add( currentColor.mul( currentWeight ), clampedHistoryColor.mul( historyWeight ) ).div( max( currentWeight.add( historyWeight ), 0.00001 ) ).toVar(); | ||
| return smoothedOutput; | ||
| } ); | ||
@@ -418,0 +535,0 @@ |
@@ -8,2 +8,13 @@ import { DataTexture, FloatType, RGBAFormat, Vector2, Vector3, LightsNode, NodeUpdateType } from 'three/webgpu'; | ||
| /** | ||
| * TSL function that checks if a circle intersects with an axis-aligned bounding box (AABB). | ||
| * | ||
| * @tsl | ||
| * @function | ||
| * @param {Node<vec2>} circleCenter - The center of the circle. | ||
| * @param {Node<float>} radius - The radius of the circle. | ||
| * @param {Node<vec2>} minBounds - The minimum bounds of the AABB. | ||
| * @param {Node<vec2>} maxBounds - The maximum bounds of the AABB. | ||
| * @return {Node<bool>} True if the circle intersects the AABB. | ||
| */ | ||
| export const circleIntersectsAABB = /*@__PURE__*/ Fn( ( [ circleCenter, radius, minBounds, maxBounds ] ) => { | ||
@@ -396,3 +407,3 @@ | ||
| } )().compute( count ); | ||
| } )().compute( count ).setName( 'Update Tiled Lights' ); | ||
@@ -424,2 +435,11 @@ // screen coordinate lighting indexes | ||
| /** | ||
| * TSL function that creates a tiled lights node. | ||
| * | ||
| * @tsl | ||
| * @function | ||
| * @param {number} [maxLights=1024] - The maximum number of lights. | ||
| * @param {number} [tileSize=32] - The tile size. | ||
| * @return {TiledLightsNode} The tiled lights node. | ||
| */ | ||
| export const tiledLights = /*@__PURE__*/ nodeProxy( TiledLightsNode ); |
@@ -248,3 +248,3 @@ import { | ||
| * | ||
| * This module depends on the [motion-controllers]{@link https://github.com/immersive-web/webxr-input-profiles/blob/main/packages/motion-controllers/README.md} | ||
| * This module depends on the [motion-controllers](https://github.com/immersive-web/webxr-input-profiles/blob/main/packages/motion-controllers/README.md) | ||
| * third-part library. | ||
@@ -251,0 +251,0 @@ * |
@@ -182,4 +182,2 @@ import { | ||
| controller.visible = true; | ||
| } ); | ||
@@ -189,6 +187,4 @@ | ||
| controller.visible = false; | ||
| // handModel.motionController = null; | ||
| // handModel.remove( scene ); | ||
| // scene = null; | ||
| handModel.clear(); | ||
| handModel.motionController = null; | ||
@@ -195,0 +191,0 @@ } ); |
+5
-10
| { | ||
| "name": "three", | ||
| "version": "0.180.0", | ||
| "version": "0.181.0", | ||
| "description": "JavaScript 3D library", | ||
@@ -66,4 +66,4 @@ "type": "module", | ||
| "lint-fix": "npm run lint-core -- --fix && npm run lint-addons -- --fix && npm run lint-examples -- --fix && npm run lint-docs -- --fix && npm run lint-editor -- --fix && npm run lint-playground -- --fix && npm run lint-manual -- --fix && npm run lint-test -- --fix && npm run lint-utils -- --fix", | ||
| "test-unit": "qunit -r failonlyreporter -f !-webonly test/unit/three.source.unit.js", | ||
| "test-unit-addons": "qunit -r failonlyreporter -f !-webonly test/unit/three.addons.unit.js", | ||
| "test-unit": "qunit test/unit/three.source.unit.js", | ||
| "test-unit-addons": "qunit test/unit/three.addons.unit.js", | ||
| "test-e2e": "node test/e2e/puppeteer.js", | ||
@@ -73,3 +73,2 @@ "test-e2e-cov": "node test/e2e/check-coverage.js", | ||
| "test-treeshake": "rollup -c test/rollup.treeshake.config.js", | ||
| "test-circular-deps": "dpdm --no-warning --no-tree --exit-code circular:1 src/nodes/Nodes.js", | ||
| "make-screenshot": "node test/e2e/puppeteer.js --make" | ||
@@ -102,5 +101,3 @@ }, | ||
| "@rollup/plugin-terser": "^0.4.0", | ||
| "chalk": "^5.2.0", | ||
| "concurrently": "^9.0.0", | ||
| "dpdm": "^3.14.0", | ||
| "eslint": "^8.37.0", | ||
@@ -111,12 +108,10 @@ "eslint-config-mdcs": "^5.0.0", | ||
| "eslint-plugin-import": "^2.27.5", | ||
| "failonlyreporter": "^1.0.0", | ||
| "jimp": "^1.6.0", | ||
| "jsdoc": "^4.0.4", | ||
| "jsdoc": "^4.0.5", | ||
| "magic-string": "^0.30.0", | ||
| "pixelmatch": "^7.0.0", | ||
| "puppeteer": "^22.0.0", | ||
| "puppeteer": "^24.25.0", | ||
| "qunit": "^2.19.4", | ||
| "rollup": "^4.6.0", | ||
| "rollup-plugin-filesize": "^10.0.0", | ||
| "rollup-plugin-visualizer": "^6.0.0", | ||
| "servez": "^2.2.4" | ||
@@ -123,0 +118,0 @@ }, |
@@ -11,2 +11,3 @@ import * as AnimationUtils from './AnimationUtils.js'; | ||
| import { NormalAnimationBlendMode } from '../constants.js'; | ||
| import { warn, error } from '../utils.js'; | ||
@@ -309,7 +310,7 @@ /** | ||
| console.warn( 'THREE.AnimationClip: parseAnimation() is deprecated and will be removed with r185' ); | ||
| warn( 'AnimationClip: parseAnimation() is deprecated and will be removed with r185' ); | ||
| if ( ! animation ) { | ||
| console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' ); | ||
| error( 'AnimationClip: No animation in JSONLoader data.' ); | ||
| return null; | ||
@@ -316,0 +317,0 @@ |
@@ -644,3 +644,3 @@ import { AnimationAction } from './AnimationAction.js'; | ||
| * | ||
| * @return {AnimationMixer} A reference to thi animation mixer. | ||
| * @return {AnimationMixer} A reference to this animation mixer. | ||
| */ | ||
@@ -669,3 +669,3 @@ stopAllAction() { | ||
| * @param {number} deltaTime - The delta time in seconds. | ||
| * @return {AnimationMixer} A reference to thi animation mixer. | ||
| * @return {AnimationMixer} A reference to this animation mixer. | ||
| */ | ||
@@ -716,3 +716,3 @@ update( deltaTime ) { | ||
| * @param {number} time - The time to set in seconds. | ||
| * @return {AnimationMixer} A reference to thi animation mixer. | ||
| * @return {AnimationMixer} A reference to this animation mixer. | ||
| */ | ||
@@ -719,0 +719,0 @@ setTime( time ) { |
| import { PropertyBinding } from './PropertyBinding.js'; | ||
| import { generateUUID } from '../math/MathUtils.js'; | ||
| import { error } from '../utils.js'; | ||
@@ -178,3 +179,3 @@ /** | ||
| console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' + | ||
| error( 'AnimationObjectGroup: Different objects with the same UUID ' + | ||
| 'detected. Clean the caches or recreate your infrastructure when reloading scenes.' ); | ||
@@ -181,0 +182,0 @@ |
@@ -10,2 +10,3 @@ import { | ||
| import * as AnimationUtils from './AnimationUtils.js'; | ||
| import { warn, error } from '../utils.js'; | ||
@@ -195,3 +196,3 @@ /** | ||
| console.warn( 'THREE.KeyframeTrack:', message ); | ||
| warn( 'KeyframeTrack:', message ); | ||
| return this; | ||
@@ -356,3 +357,3 @@ | ||
| console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this ); | ||
| error( 'KeyframeTrack: Invalid value size in track.', this ); | ||
| valid = false; | ||
@@ -369,3 +370,3 @@ | ||
| console.error( 'THREE.KeyframeTrack: Track is empty.', this ); | ||
| error( 'KeyframeTrack: Track is empty.', this ); | ||
| valid = false; | ||
@@ -383,3 +384,3 @@ | ||
| console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime ); | ||
| error( 'KeyframeTrack: Time is not a valid number.', this, i, currTime ); | ||
| valid = false; | ||
@@ -392,3 +393,3 @@ break; | ||
| console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); | ||
| error( 'KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); | ||
| valid = false; | ||
@@ -413,3 +414,3 @@ break; | ||
| console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value ); | ||
| error( 'KeyframeTrack: Value is not a valid number.', this, i, value ); | ||
| valid = false; | ||
@@ -416,0 +417,0 @@ break; |
@@ -0,1 +1,2 @@ | ||
| import { warn, error } from '../utils.js'; | ||
| // Characters [].:/ are reserved for track binding syntax. | ||
@@ -510,3 +511,3 @@ const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/'; | ||
| console.warn( 'THREE.PropertyBinding: No target node found for track: ' + this.path + '.' ); | ||
| warn( 'PropertyBinding: No target node found for track: ' + this.path + '.' ); | ||
| return; | ||
@@ -527,3 +528,3 @@ | ||
| console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); | ||
| error( 'PropertyBinding: Can not bind to material as node does not have a material.', this ); | ||
| return; | ||
@@ -535,3 +536,3 @@ | ||
| console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this ); | ||
| error( 'PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this ); | ||
| return; | ||
@@ -549,3 +550,3 @@ | ||
| console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this ); | ||
| error( 'PropertyBinding: Can not bind to bones as node does not have a skeleton.', this ); | ||
| return; | ||
@@ -585,3 +586,3 @@ | ||
| console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); | ||
| error( 'PropertyBinding: Can not bind to material as node does not have a material.', this ); | ||
| return; | ||
@@ -593,3 +594,3 @@ | ||
| console.error( 'THREE.PropertyBinding: Can not bind to material.map as node.material does not have a map.', this ); | ||
| error( 'PropertyBinding: Can not bind to material.map as node.material does not have a map.', this ); | ||
| return; | ||
@@ -606,3 +607,3 @@ | ||
| console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this ); | ||
| error( 'PropertyBinding: Can not bind to objectName of node undefined.', this ); | ||
| return; | ||
@@ -621,3 +622,3 @@ | ||
| console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject ); | ||
| error( 'PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject ); | ||
| return; | ||
@@ -640,3 +641,3 @@ | ||
| console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName + | ||
| error( 'PropertyBinding: Trying to update property for track: ' + nodeName + | ||
| '.' + propertyName + ' but it wasn\'t found.', targetObject ); | ||
@@ -676,3 +677,3 @@ return; | ||
| console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this ); | ||
| error( 'PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this ); | ||
| return; | ||
@@ -684,3 +685,3 @@ | ||
| console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this ); | ||
| error( 'PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this ); | ||
| return; | ||
@@ -687,0 +688,0 @@ |
+10
-9
| import { Object3D } from '../core/Object3D.js'; | ||
| import { warn } from '../utils.js'; | ||
@@ -6,3 +7,3 @@ /** | ||
| * | ||
| * This and related audio modules make use of the [Web Audio API]{@link https://www.w3.org/TR/webaudio-1.1/}. | ||
| * This and related audio modules make use of the [Web Audio API](https://www.w3.org/TR/webaudio-1.1/). | ||
| * | ||
@@ -318,3 +319,3 @@ * ```js | ||
| console.warn( 'THREE.Audio: Audio is already playing.' ); | ||
| warn( 'Audio: Audio is already playing.' ); | ||
| return; | ||
@@ -326,3 +327,3 @@ | ||
| console.warn( 'THREE.Audio: this Audio has no playback control.' ); | ||
| warn( 'Audio: this Audio has no playback control.' ); | ||
| return; | ||
@@ -364,3 +365,3 @@ | ||
| console.warn( 'THREE.Audio: this Audio has no playback control.' ); | ||
| warn( 'Audio: this Audio has no playback control.' ); | ||
| return; | ||
@@ -407,3 +408,3 @@ | ||
| console.warn( 'THREE.Audio: this Audio has no playback control.' ); | ||
| warn( 'Audio: this Audio has no playback control.' ); | ||
| return; | ||
@@ -601,3 +602,3 @@ | ||
| console.warn( 'THREE.Audio: this Audio has no playback control.' ); | ||
| warn( 'Audio: this Audio has no playback control.' ); | ||
| return; | ||
@@ -651,3 +652,3 @@ | ||
| console.warn( 'THREE.Audio: this Audio has no playback control.' ); | ||
| warn( 'Audio: this Audio has no playback control.' ); | ||
| return false; | ||
@@ -673,3 +674,3 @@ | ||
| console.warn( 'THREE.Audio: this Audio has no playback control.' ); | ||
| warn( 'Audio: this Audio has no playback control.' ); | ||
| return; | ||
@@ -752,3 +753,3 @@ | ||
| console.warn( 'THREE.Audio: Audio source type cannot be copied.' ); | ||
| warn( 'Audio: Audio source type cannot be copied.' ); | ||
@@ -755,0 +756,0 @@ return this; |
@@ -157,3 +157,3 @@ import { Vector3 } from '../math/Vector3.js'; | ||
| * | ||
| * Read [the spec]{@link https://www.w3.org/TR/webaudio-1.1/#enumdef-distancemodeltype} | ||
| * Read [the spec](https://www.w3.org/TR/webaudio-1.1/#enumdef-distancemodeltype) | ||
| * for more details. | ||
@@ -160,0 +160,0 @@ * |
| import { Camera } from './Camera.js'; | ||
| /** | ||
| * Camera that uses [orthographic projection]{@link https://en.wikipedia.org/wiki/Orthographic_projection}. | ||
| * Camera that uses [orthographic projection](https://en.wikipedia.org/wiki/Orthographic_projection). | ||
| * | ||
@@ -6,0 +6,0 @@ * In this projection mode, an object's size in the rendered image stays |
@@ -11,3 +11,3 @@ import { Camera } from './Camera.js'; | ||
| /** | ||
| * Camera that uses [perspective projection]{@link https://en.wikipedia.org/wiki/Perspective_(graphical)}. | ||
| * Camera that uses [perspective projection](https://en.wikipedia.org/wiki/Perspective_(graphical)). | ||
| * | ||
@@ -14,0 +14,0 @@ * This projection mode is designed to mimic the way the human eye sees. It |
@@ -12,4 +12,4 @@ import { Matrix4 } from '../math/Matrix4.js'; | ||
| * stereoscopic projection. Can be used for rendering stereo effects | ||
| * like [3D Anaglyph]{@link https://en.wikipedia.org/wiki/Anaglyph_3D} or | ||
| * [Parallax Barrier]{@link https://en.wikipedia.org/wiki/parallax_barrier}. | ||
| * like [3D Anaglyph](https://en.wikipedia.org/wiki/Anaglyph_3D) or | ||
| * [Parallax Barrier](https://en.wikipedia.org/wiki/parallax_barrier). | ||
| */ | ||
@@ -16,0 +16,0 @@ class StereoCamera { |
+1
-1
@@ -1,2 +0,2 @@ | ||
| export const REVISION = '180'; | ||
| export const REVISION = '181'; | ||
@@ -3,0 +3,0 @@ /** |
@@ -11,3 +11,3 @@ import { Vector3 } from '../math/Vector3.js'; | ||
| import { generateUUID } from '../math/MathUtils.js'; | ||
| import { arrayNeedsUint32 } from '../utils.js'; | ||
| import { arrayNeedsUint32, warn, error } from '../utils.js'; | ||
@@ -600,3 +600,3 @@ let _id = 0; | ||
| console.warn( 'THREE.BufferGeometry: Buffer size too small for points data. Use .dispose() and create a new geometry.' ); | ||
| warn( 'BufferGeometry: Buffer size too small for points data. Use .dispose() and create a new geometry.' ); | ||
@@ -631,3 +631,3 @@ } | ||
| console.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box.', this ); | ||
| error( 'BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box.', this ); | ||
@@ -683,3 +683,3 @@ this.boundingBox.set( | ||
| console.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this ); | ||
| error( 'BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this ); | ||
@@ -708,3 +708,3 @@ } | ||
| console.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere.', this ); | ||
| error( 'BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere.', this ); | ||
@@ -800,3 +800,3 @@ this.boundingSphere.set( new Vector3(), Infinity ); | ||
| console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); | ||
| error( 'BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); | ||
@@ -829,3 +829,3 @@ } | ||
| console.error( 'THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' ); | ||
| error( 'BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' ); | ||
| return; | ||
@@ -1140,3 +1140,3 @@ | ||
| console.warn( 'THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' ); | ||
| warn( 'BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' ); | ||
| return this; | ||
@@ -1143,0 +1143,0 @@ |
| /** | ||
| * This modules allows to dispatch event objects on custom JavaScript objects. | ||
| * | ||
| * Main repository: [eventdispatcher.js]{@link https://github.com/mrdoob/eventdispatcher.js/} | ||
| * Main repository: [eventdispatcher.js](https://github.com/mrdoob/eventdispatcher.js/) | ||
| * | ||
@@ -6,0 +6,0 @@ * Code Example: |
@@ -8,3 +8,3 @@ import { generateUUID } from '../math/MathUtils.js'; | ||
| * | ||
| * An introduction into interleaved arrays can be found here: [Interleaved array basics]{@link https://blog.tojicode.com/2011/05/interleaved-array-basics.html} | ||
| * An introduction into interleaved arrays can be found here: [Interleaved array basics](https://blog.tojicode.com/2011/05/interleaved-array-basics.html) | ||
| */ | ||
@@ -11,0 +11,0 @@ class InterleavedBuffer { |
| import { Vector3 } from '../math/Vector3.js'; | ||
| import { BufferAttribute } from './BufferAttribute.js'; | ||
| import { denormalize, normalize } from '../math/MathUtils.js'; | ||
| import { log } from '../utils.js'; | ||
@@ -442,3 +443,3 @@ const _vector = /*@__PURE__*/ new Vector3(); | ||
| console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will de-interleave buffer data.' ); | ||
| log( 'InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will de-interleave buffer data.' ); | ||
@@ -493,3 +494,3 @@ const array = []; | ||
| console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will de-interleave buffer data.' ); | ||
| log( 'InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will de-interleave buffer data.' ); | ||
@@ -496,0 +497,0 @@ const array = []; |
@@ -9,2 +9,3 @@ import { Quaternion } from '../math/Quaternion.js'; | ||
| import { generateUUID } from '../math/MathUtils.js'; | ||
| import { error } from '../utils.js'; | ||
@@ -737,3 +738,3 @@ let _object3DId = 0; | ||
| console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object ); | ||
| error( 'Object3D.add: object can\'t be added as a child of itself.', object ); | ||
| return this; | ||
@@ -757,3 +758,3 @@ | ||
| console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object ); | ||
| error( 'Object3D.add: object not an instance of THREE.Object3D.', object ); | ||
@@ -760,0 +761,0 @@ } |
| import { Matrix4 } from '../math/Matrix4.js'; | ||
| import { Ray } from '../math/Ray.js'; | ||
| import { Layers } from './Layers.js'; | ||
| import { error } from '../utils.js'; | ||
@@ -134,3 +135,3 @@ const _matrix = /*@__PURE__*/ new Matrix4(); | ||
| console.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type ); | ||
| error( 'Raycaster: Unsupported camera type: ' + camera.type ); | ||
@@ -137,0 +138,0 @@ } |
@@ -297,4 +297,13 @@ import { EventDispatcher } from './EventDispatcher.js'; | ||
| this.textures[ i ].image.depth = depth; | ||
| this.textures[ i ].isArrayTexture = this.textures[ i ].image.depth > 1; | ||
| if ( this.textures[ i ].isData3DTexture !== true ) { // Fix for #31693 | ||
| // TODO: Reconsider setting isArrayTexture flag here and in the ctor of Texture. | ||
| // Maybe a method `isArrayTexture()` or just a getter could replace a flag since | ||
| // both are evaluated on each call? | ||
| this.textures[ i ].isArrayTexture = this.textures[ i ].image.depth > 1; | ||
| } | ||
| } | ||
@@ -301,0 +310,0 @@ |
| import { EventDispatcher } from '../core/EventDispatcher.js'; | ||
| import { warn } from '../utils.js'; | ||
@@ -15,3 +16,3 @@ /** | ||
| * @param {Object3D} object - The object that is managed by the controls. | ||
| * @param {?HTMLDOMElement} domElement - The HTML element used for event listeners. | ||
| * @param {?HTMLElement} domElement - The HTML element used for event listeners. | ||
| */ | ||
@@ -32,3 +33,3 @@ constructor( object, domElement = null ) { | ||
| * | ||
| * @type {?HTMLDOMElement} | ||
| * @type {?HTMLElement} | ||
| * @default null | ||
@@ -83,3 +84,3 @@ */ | ||
| * | ||
| * @param {HTMLDOMElement} element - The DOM element to connect to. | ||
| * @param {HTMLElement} element - The DOM element to connect to. | ||
| */ | ||
@@ -90,3 +91,3 @@ connect( element ) { | ||
| console.warn( 'THREE.Controls: connect() now requires an element.' ); // @deprecated, the warning can be removed with r185 | ||
| warn( 'Controls: connect() now requires an element.' ); // @deprecated, the warning can be removed with r185 | ||
| return; | ||
@@ -93,0 +94,0 @@ |
@@ -5,2 +5,3 @@ import { clamp } from '../../math/MathUtils.js'; | ||
| import { Matrix4 } from '../../math/Matrix4.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -70,3 +71,3 @@ /** | ||
| console.warn( 'THREE.Curve: .getPoint() not implemented.' ); | ||
| warn( 'Curve: .getPoint() not implemented.' ); | ||
@@ -73,0 +74,0 @@ } |
@@ -1,2 +0,8 @@ | ||
| // Bezier Curves formulas obtained from: https://en.wikipedia.org/wiki/B%C3%A9zier_curve | ||
| /** | ||
| * Interpolations contains spline and Bézier functions internally used by concrete curve classes. | ||
| * | ||
| * Bezier Curves formulas obtained from: https://en.wikipedia.org/wiki/B%C3%A9zier_curve | ||
| * | ||
| * @module Interpolations | ||
| */ | ||
@@ -3,0 +9,0 @@ /** |
@@ -239,3 +239,3 @@ import { Color } from '../../math/Color.js'; | ||
| // console.log("Holes first", holesFirst); | ||
| // log("Holes first", holesFirst); | ||
@@ -268,3 +268,3 @@ const betterShapeHoles = []; | ||
| //console.log('cw', i); | ||
| //log('cw', i); | ||
@@ -275,3 +275,3 @@ } else { | ||
| //console.log('ccw', i); | ||
| //log('ccw', i); | ||
@@ -361,3 +361,3 @@ } | ||
| //console.log("shape", shapes); | ||
| //log("shape", shapes); | ||
@@ -364,0 +364,0 @@ return shapes; |
| import { clamp } from '../math/MathUtils.js'; | ||
| import { warn } from '../utils.js'; | ||
@@ -151,3 +152,3 @@ // Fast Half Float Conversions, http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf | ||
| if ( Math.abs( val ) > 65504 ) console.warn( 'THREE.DataUtils.toHalfFloat(): Value out of range.' ); | ||
| if ( Math.abs( val ) > 65504 ) warn( 'DataUtils.toHalfFloat(): Value out of range.' ); | ||
@@ -154,0 +155,0 @@ val = clamp( val, - 65504, 65504 ); |
| import earcut from './lib/earcut.js'; | ||
| /** | ||
| * An implementation of the earcut polygon triangulation algorithm. | ||
| * The code is a port of [mapbox/earcut](https://github.com/mapbox/earcut). | ||
| * | ||
| * @see https://github.com/mapbox/earcut | ||
| */ | ||
| class Earcut { | ||
@@ -4,0 +10,0 @@ |
@@ -1,2 +0,2 @@ | ||
| import { createElementNS } from '../utils.js'; | ||
| import { createElementNS, warn } from '../utils.js'; | ||
| import { SRGBToLinear } from '../math/ColorManagement.js'; | ||
@@ -128,3 +128,3 @@ | ||
| console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' ); | ||
| warn( 'ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' ); | ||
| return image; | ||
@@ -131,0 +131,0 @@ |
| /* eslint-disable */ | ||
| // copy of mapbox/earcut version 3.0.1 | ||
| // https://github.com/mapbox/earcut/tree/v3.0.1 | ||
| // copy of mapbox/earcut version 3.0.2 | ||
| // https://github.com/mapbox/earcut/tree/v3.0.2 | ||
@@ -20,6 +20,6 @@ export default function earcut(data, holeIndices, dim = 2) { | ||
| if (data.length > 80 * dim) { | ||
| minX = Infinity; | ||
| minY = Infinity; | ||
| let maxX = -Infinity; | ||
| let maxY = -Infinity; | ||
| minX = data[0]; | ||
| minY = data[1]; | ||
| let maxX = minX; | ||
| let maxY = minY; | ||
@@ -300,3 +300,3 @@ for (let i = dim; i < outerLen; i += dim) { | ||
| // find a bridge between vertices that connects hole with an outer ring and and link it | ||
| // find a bridge between vertices that connects hole with an outer ring and link it | ||
| function eliminateHole(hole, outerNode) { | ||
@@ -303,0 +303,0 @@ const bridge = findHoleBridge(hole, outerNode); |
+268
-55
@@ -25,9 +25,8 @@ import { | ||
| import { BoxGeometry } from '../geometries/BoxGeometry.js'; | ||
| import { error, warn } from '../utils.js'; | ||
| const LOD_MIN = 4; | ||
| // The standard deviations (radians) associated with the extra mips. These are | ||
| // chosen to approximate a Trowbridge-Reitz distribution function times the | ||
| // geometric shadowing function. These sigma values squared must match the | ||
| // variance #defines in cube_uv_reflection_fragment.glsl.js. | ||
| // The standard deviations (radians) associated with the extra mips. | ||
| // Used for scene blur in fromScene() method. | ||
| const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ]; | ||
@@ -37,4 +36,8 @@ | ||
| // samples and exit early, but not recompile the shader. | ||
| // Used for scene blur in fromScene() method. | ||
| const MAX_SAMPLES = 20; | ||
| // GGX VNDF importance sampling configuration | ||
| const GGX_SAMPLES = 512; | ||
| const _flatCamera = /*@__PURE__*/ new OrthographicCamera(); | ||
@@ -47,20 +50,2 @@ const _clearColor = /*@__PURE__*/ new Color(); | ||
| // Golden Ratio | ||
| const PHI = ( 1 + Math.sqrt( 5 ) ) / 2; | ||
| const INV_PHI = 1 / PHI; | ||
| // Vertices of a dodecahedron (except the opposites, which represent the | ||
| // same axis), used as axis directions evenly spread on a sphere. | ||
| const _axisDirections = [ | ||
| /*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ), | ||
| /*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ), | ||
| /*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ), | ||
| /*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ), | ||
| /*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ), | ||
| /*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ), | ||
| /*@__PURE__*/ new Vector3( - 1, 1, - 1 ), | ||
| /*@__PURE__*/ new Vector3( 1, 1, - 1 ), | ||
| /*@__PURE__*/ new Vector3( - 1, 1, 1 ), | ||
| /*@__PURE__*/ new Vector3( 1, 1, 1 ) ]; | ||
| const _origin = /*@__PURE__*/ new Vector3(); | ||
@@ -79,5 +64,7 @@ | ||
| * | ||
| * Paper: Fast, Accurate Image-Based Lighting: | ||
| * {@link https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view} | ||
| */ | ||
| * The prefiltering uses GGX VNDF (Visible Normal Distribution Function) | ||
| * importance sampling based on "Sampling the GGX Distribution of Visible Normals" | ||
| * (Heitz, 2018) to generate environment maps that accurately match the GGX BRDF | ||
| * used in material rendering for physically-based image-based lighting. | ||
| */ | ||
| class PMREMGenerator { | ||
@@ -97,11 +84,13 @@ | ||
| this._cubeSize = 0; | ||
| this._lodPlanes = []; | ||
| this._sizeLods = []; | ||
| this._sigmas = []; | ||
| this._lodMeshes = []; | ||
| this._blurMaterial = null; | ||
| this._backgroundBox = null; | ||
| this._cubemapMaterial = null; | ||
| this._equirectMaterial = null; | ||
| this._compileMaterial( this._blurMaterial ); | ||
| this._blurMaterial = null; | ||
| this._ggxMaterial = null; | ||
@@ -231,2 +220,9 @@ } | ||
| if ( this._backgroundBox !== null ) { | ||
| this._backgroundBox.geometry.dispose(); | ||
| this._backgroundBox.material.dispose(); | ||
| } | ||
| } | ||
@@ -246,8 +242,9 @@ | ||
| if ( this._blurMaterial !== null ) this._blurMaterial.dispose(); | ||
| if ( this._ggxMaterial !== null ) this._ggxMaterial.dispose(); | ||
| if ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose(); | ||
| for ( let i = 0; i < this._lodPlanes.length; i ++ ) { | ||
| for ( let i = 0; i < this._lodMeshes.length; i ++ ) { | ||
| this._lodPlanes[ i ].dispose(); | ||
| this._lodMeshes[ i ].geometry.dispose(); | ||
@@ -324,3 +321,3 @@ } | ||
| const { _lodMax } = this; | ||
| ( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas } = _createPlanes( _lodMax ) ); | ||
| ( { lodMeshes: this._lodMeshes, sizeLods: this._sizeLods, sigmas: this._sigmas } = _createPlanes( _lodMax ) ); | ||
@@ -337,4 +334,4 @@ this._blurMaterial = _getBlurShader( _lodMax, width, height ); | ||
| const tmpMesh = new Mesh( this._lodPlanes[ 0 ], material ); | ||
| this._renderer.compile( tmpMesh, _flatCamera ); | ||
| const mesh = new Mesh( new BufferGeometry(), material ); | ||
| this._renderer.compile( mesh, _flatCamera ); | ||
@@ -370,12 +367,21 @@ } | ||
| const backgroundMaterial = new MeshBasicMaterial( { | ||
| name: 'PMREM.Background', | ||
| side: BackSide, | ||
| depthWrite: false, | ||
| depthTest: false, | ||
| } ); | ||
| if ( this._backgroundBox === null ) { | ||
| const backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial ); | ||
| this._backgroundBox = new Mesh( | ||
| new BoxGeometry(), | ||
| new MeshBasicMaterial( { | ||
| name: 'PMREM.Background', | ||
| side: BackSide, | ||
| depthWrite: false, | ||
| depthTest: false, | ||
| } ) | ||
| ); | ||
| } | ||
| const backgroundBox = this._backgroundBox; | ||
| const backgroundMaterial = backgroundBox.material; | ||
| let useSolidColor = false; | ||
| const background = scene.background; | ||
@@ -441,5 +447,2 @@ | ||
| backgroundBox.geometry.dispose(); | ||
| backgroundBox.material.dispose(); | ||
| renderer.toneMapping = toneMapping; | ||
@@ -478,4 +481,6 @@ renderer.autoClear = originalAutoClear; | ||
| const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial; | ||
| const mesh = new Mesh( this._lodPlanes[ 0 ], material ); | ||
| const mesh = this._lodMeshes[ 0 ]; | ||
| mesh.material = material; | ||
| const uniforms = material.uniforms; | ||
@@ -499,16 +504,79 @@ | ||
| renderer.autoClear = false; | ||
| const n = this._lodPlanes.length; | ||
| const n = this._lodMeshes.length; | ||
| // Use GGX VNDF importance sampling | ||
| for ( let i = 1; i < n; i ++ ) { | ||
| const sigma = Math.sqrt( this._sigmas[ i ] * this._sigmas[ i ] - this._sigmas[ i - 1 ] * this._sigmas[ i - 1 ] ); | ||
| this._applyGGXFilter( cubeUVRenderTarget, i - 1, i ); | ||
| const poleAxis = _axisDirections[ ( n - i - 1 ) % _axisDirections.length ]; | ||
| } | ||
| this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis ); | ||
| renderer.autoClear = autoClear; | ||
| } | ||
| /** | ||
| * Applies GGX VNDF importance sampling filter to generate a prefiltered environment map. | ||
| * Uses Monte Carlo integration with VNDF importance sampling to accurately represent the | ||
| * GGX BRDF for physically-based rendering. Reads from the previous LOD level and | ||
| * applies incremental roughness filtering to avoid over-blurring. | ||
| * | ||
| * @private | ||
| * @param {WebGLRenderTarget} cubeUVRenderTarget | ||
| * @param {number} lodIn - Source LOD level to read from | ||
| * @param {number} lodOut - Target LOD level to write to | ||
| */ | ||
| _applyGGXFilter( cubeUVRenderTarget, lodIn, lodOut ) { | ||
| const renderer = this._renderer; | ||
| const pingPongRenderTarget = this._pingPongRenderTarget; | ||
| if ( this._ggxMaterial === null ) { | ||
| const width = 3 * Math.max( this._cubeSize, 16 ); | ||
| const height = 4 * this._cubeSize; | ||
| this._ggxMaterial = _getGGXShader( this._lodMax, width, height ); | ||
| } | ||
| renderer.autoClear = autoClear; | ||
| const ggxMaterial = this._ggxMaterial; | ||
| const ggxMesh = this._lodMeshes[ lodOut ]; | ||
| ggxMesh.material = ggxMaterial; | ||
| const ggxUniforms = ggxMaterial.uniforms; | ||
| // Calculate incremental roughness between LOD levels | ||
| const targetRoughness = lodOut / ( this._lodMeshes.length - 1 ); | ||
| const sourceRoughness = lodIn / ( this._lodMeshes.length - 1 ); | ||
| const incrementalRoughness = Math.sqrt( targetRoughness * targetRoughness - sourceRoughness * sourceRoughness ); | ||
| // Apply blur strength mapping for better quality across the roughness range | ||
| const blurStrength = 0.05 + targetRoughness * 0.95; | ||
| const adjustedRoughness = incrementalRoughness * blurStrength; | ||
| // Calculate viewport position based on output LOD level | ||
| const { _lodMax } = this; | ||
| const outputSize = this._sizeLods[ lodOut ]; | ||
| const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 ); | ||
| const y = 4 * ( this._cubeSize - outputSize ); | ||
| // Read from previous LOD with incremental roughness | ||
| ggxUniforms[ 'envMap' ].value = cubeUVRenderTarget.texture; | ||
| ggxUniforms[ 'roughness' ].value = adjustedRoughness; | ||
| ggxUniforms[ 'mipInt' ].value = _lodMax - lodIn; // Sample from input LOD | ||
| _setViewport( pingPongRenderTarget, x, y, 3 * outputSize, 2 * outputSize ); | ||
| renderer.setRenderTarget( pingPongRenderTarget ); | ||
| renderer.render( ggxMesh, _flatCamera ); | ||
| // Copy from pingPong back to cubeUV (simple direct copy) | ||
| ggxUniforms[ 'envMap' ].value = pingPongRenderTarget.texture; | ||
| ggxUniforms[ 'roughness' ].value = 0.0; // Direct copy | ||
| ggxUniforms[ 'mipInt' ].value = _lodMax - lodOut; // Read from the level we just wrote | ||
| _setViewport( cubeUVRenderTarget, x, y, 3 * outputSize, 2 * outputSize ); | ||
| renderer.setRenderTarget( cubeUVRenderTarget ); | ||
| renderer.render( ggxMesh, _flatCamera ); | ||
| } | ||
@@ -523,2 +591,4 @@ | ||
| * | ||
| * Used for initial scene blur in fromScene() method when sigma > 0. | ||
| * | ||
| * @private | ||
@@ -562,3 +632,3 @@ * @param {WebGLRenderTarget} cubeUVRenderTarget | ||
| console.error( | ||
| error( | ||
| 'blur direction must be either latitudinal or longitudinal!' ); | ||
@@ -571,3 +641,5 @@ | ||
| const blurMesh = new Mesh( this._lodPlanes[ lodOut ], blurMaterial ); | ||
| const blurMesh = this._lodMeshes[ lodOut ]; | ||
| blurMesh.material = blurMaterial; | ||
| const blurUniforms = blurMaterial.uniforms; | ||
@@ -582,3 +654,3 @@ | ||
| console.warn( `sigmaRadians, ${ | ||
| warn( `sigmaRadians, ${ | ||
| sigmaRadians}, is too large and will clip, as it requested ${ | ||
@@ -647,5 +719,5 @@ samples} samples when the maximum is set to ${MAX_SAMPLES}` ); | ||
| const lodPlanes = []; | ||
| const sizeLods = []; | ||
| const sigmas = []; | ||
| const lodMeshes = []; | ||
@@ -712,3 +784,3 @@ let lod = lodMax; | ||
| planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) ); | ||
| lodPlanes.push( planes ); | ||
| lodMeshes.push( new Mesh( planes, null ) ); | ||
@@ -723,3 +795,3 @@ if ( lod > LOD_MIN ) { | ||
| return { lodPlanes, sizeLods, sigmas }; | ||
| return { lodMeshes, sizeLods, sigmas }; | ||
@@ -745,2 +817,143 @@ } | ||
| function _getGGXShader( lodMax, width, height ) { | ||
| const shaderMaterial = new ShaderMaterial( { | ||
| name: 'PMREMGGXConvolution', | ||
| defines: { | ||
| 'GGX_SAMPLES': GGX_SAMPLES, | ||
| 'CUBEUV_TEXEL_WIDTH': 1.0 / width, | ||
| 'CUBEUV_TEXEL_HEIGHT': 1.0 / height, | ||
| 'CUBEUV_MAX_MIP': `${lodMax}.0`, | ||
| }, | ||
| uniforms: { | ||
| 'envMap': { value: null }, | ||
| 'roughness': { value: 0.0 }, | ||
| 'mipInt': { value: 0 } | ||
| }, | ||
| vertexShader: _getCommonVertexShader(), | ||
| fragmentShader: /* glsl */` | ||
| precision mediump float; | ||
| precision mediump int; | ||
| varying vec3 vOutputDirection; | ||
| uniform sampler2D envMap; | ||
| uniform float roughness; | ||
| uniform float mipInt; | ||
| #define ENVMAP_TYPE_CUBE_UV | ||
| #include <cube_uv_reflection_fragment> | ||
| #define PI 3.14159265359 | ||
| // Van der Corput radical inverse | ||
| float radicalInverse_VdC(uint bits) { | ||
| bits = (bits << 16u) | (bits >> 16u); | ||
| bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); | ||
| bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); | ||
| bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); | ||
| bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); | ||
| return float(bits) * 2.3283064365386963e-10; // / 0x100000000 | ||
| } | ||
| // Hammersley sequence | ||
| vec2 hammersley(uint i, uint N) { | ||
| return vec2(float(i) / float(N), radicalInverse_VdC(i)); | ||
| } | ||
| // GGX VNDF importance sampling (Eric Heitz 2018) | ||
| // "Sampling the GGX Distribution of Visible Normals" | ||
| // https://jcgt.org/published/0007/04/01/ | ||
| vec3 importanceSampleGGX_VNDF(vec2 Xi, vec3 V, float roughness) { | ||
| float alpha = roughness * roughness; | ||
| // Section 3.2: Transform view direction to hemisphere configuration | ||
| vec3 Vh = normalize(vec3(alpha * V.x, alpha * V.y, V.z)); | ||
| // Section 4.1: Orthonormal basis | ||
| float lensq = Vh.x * Vh.x + Vh.y * Vh.y; | ||
| vec3 T1 = lensq > 0.0 ? vec3(-Vh.y, Vh.x, 0.0) / sqrt(lensq) : vec3(1.0, 0.0, 0.0); | ||
| vec3 T2 = cross(Vh, T1); | ||
| // Section 4.2: Parameterization of projected area | ||
| float r = sqrt(Xi.x); | ||
| float phi = 2.0 * PI * Xi.y; | ||
| float t1 = r * cos(phi); | ||
| float t2 = r * sin(phi); | ||
| float s = 0.5 * (1.0 + Vh.z); | ||
| t2 = (1.0 - s) * sqrt(1.0 - t1 * t1) + s * t2; | ||
| // Section 4.3: Reprojection onto hemisphere | ||
| vec3 Nh = t1 * T1 + t2 * T2 + sqrt(max(0.0, 1.0 - t1 * t1 - t2 * t2)) * Vh; | ||
| // Section 3.4: Transform back to ellipsoid configuration | ||
| return normalize(vec3(alpha * Nh.x, alpha * Nh.y, max(0.0, Nh.z))); | ||
| } | ||
| void main() { | ||
| vec3 N = normalize(vOutputDirection); | ||
| vec3 V = N; // Assume view direction equals normal for pre-filtering | ||
| vec3 prefilteredColor = vec3(0.0); | ||
| float totalWeight = 0.0; | ||
| // For very low roughness, just sample the environment directly | ||
| if (roughness < 0.001) { | ||
| gl_FragColor = vec4(bilinearCubeUV(envMap, N, mipInt), 1.0); | ||
| return; | ||
| } | ||
| // Tangent space basis for VNDF sampling | ||
| vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); | ||
| vec3 tangent = normalize(cross(up, N)); | ||
| vec3 bitangent = cross(N, tangent); | ||
| for(uint i = 0u; i < uint(GGX_SAMPLES); i++) { | ||
| vec2 Xi = hammersley(i, uint(GGX_SAMPLES)); | ||
| // For PMREM, V = N, so in tangent space V is always (0, 0, 1) | ||
| vec3 H_tangent = importanceSampleGGX_VNDF(Xi, vec3(0.0, 0.0, 1.0), roughness); | ||
| // Transform H back to world space | ||
| vec3 H = normalize(tangent * H_tangent.x + bitangent * H_tangent.y + N * H_tangent.z); | ||
| vec3 L = normalize(2.0 * dot(V, H) * H - V); | ||
| float NdotL = max(dot(N, L), 0.0); | ||
| if(NdotL > 0.0) { | ||
| // Sample environment at fixed mip level | ||
| // VNDF importance sampling handles the distribution filtering | ||
| vec3 sampleColor = bilinearCubeUV(envMap, L, mipInt); | ||
| // Weight by NdotL for the split-sum approximation | ||
| // VNDF PDF naturally accounts for the visible microfacet distribution | ||
| prefilteredColor += sampleColor * NdotL; | ||
| totalWeight += NdotL; | ||
| } | ||
| } | ||
| if (totalWeight > 0.0) { | ||
| prefilteredColor = prefilteredColor / totalWeight; | ||
| } | ||
| gl_FragColor = vec4(prefilteredColor, 1.0); | ||
| } | ||
| `, | ||
| blending: NoBlending, | ||
| depthTest: false, | ||
| depthWrite: false | ||
| } ); | ||
| return shaderMaterial; | ||
| } | ||
| function _getBlurShader( lodMax, width, height ) { | ||
@@ -747,0 +960,0 @@ |
@@ -18,2 +18,3 @@ import { BufferGeometry } from '../core/BufferGeometry.js'; | ||
| * @augments BufferGeometry | ||
| * @demo scenes/geometry-browser.html#BoxGeometry | ||
| */ | ||
@@ -20,0 +21,0 @@ class BoxGeometry extends BufferGeometry { |
@@ -16,2 +16,3 @@ import { BufferGeometry } from '../core/BufferGeometry.js'; | ||
| * @augments BufferGeometry | ||
| * @demo scenes/geometry-browser.html#CapsuleGeometry | ||
| */ | ||
@@ -18,0 +19,0 @@ class CapsuleGeometry extends BufferGeometry { |
@@ -22,2 +22,3 @@ import { BufferGeometry } from '../core/BufferGeometry.js'; | ||
| * @augments BufferGeometry | ||
| * @demo scenes/geometry-browser.html#CircleGeometry | ||
| */ | ||
@@ -24,0 +25,0 @@ class CircleGeometry extends BufferGeometry { |
@@ -14,2 +14,3 @@ import { CylinderGeometry } from './CylinderGeometry.js'; | ||
| * @augments CylinderGeometry | ||
| * @demo scenes/geometry-browser.html#ConeGeometry | ||
| */ | ||
@@ -16,0 +17,0 @@ class ConeGeometry extends CylinderGeometry { |
@@ -17,2 +17,3 @@ import { BufferGeometry } from '../core/BufferGeometry.js'; | ||
| * @augments BufferGeometry | ||
| * @demo scenes/geometry-browser.html#CylinderGeometry | ||
| */ | ||
@@ -19,0 +20,0 @@ class CylinderGeometry extends BufferGeometry { |
@@ -14,2 +14,3 @@ import { PolyhedronGeometry } from './PolyhedronGeometry.js'; | ||
| * @augments PolyhedronGeometry | ||
| * @demo scenes/geometry-browser.html#DodecahedronGeometry | ||
| */ | ||
@@ -16,0 +17,0 @@ class DodecahedronGeometry extends PolyhedronGeometry { |
@@ -8,2 +8,3 @@ import { BufferGeometry } from '../core/BufferGeometry.js'; | ||
| import { ShapeUtils } from '../extras/ShapeUtils.js'; | ||
| import { error } from '../utils.js'; | ||
@@ -30,2 +31,3 @@ /** | ||
| * @augments BufferGeometry | ||
| * @demo scenes/geometry-browser.html#ExtrudeGeometry | ||
| */ | ||
@@ -119,3 +121,3 @@ class ExtrudeGeometry extends BufferGeometry { | ||
| // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); | ||
| // log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); | ||
@@ -225,3 +227,3 @@ binormal = new Vector3(); | ||
| if ( ! vec ) console.error( 'THREE.ExtrudeGeometry: vec does not exist' ); | ||
| if ( ! vec ) error( 'ExtrudeGeometry: vec does not exist' ); | ||
@@ -341,3 +343,3 @@ return pt.clone().addScaledVector( vec, size ); | ||
| // console.log("Warning: lines are a straight sequence"); | ||
| // log("Warning: lines are a straight sequence"); | ||
| v_trans_x = - v_prev_y; | ||
@@ -349,3 +351,3 @@ v_trans_y = v_prev_x; | ||
| // console.log("Warning: lines are a straight spike"); | ||
| // log("Warning: lines are a straight spike"); | ||
| v_trans_x = v_prev_x; | ||
@@ -372,3 +374,3 @@ v_trans_y = v_prev_y; | ||
| // (j)---(i)---(k) | ||
| // console.log('i,j,k', i, j , k) | ||
| // log('i,j,k', i, j , k) | ||
@@ -670,3 +672,3 @@ contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); | ||
| //console.log('b', i,j, i-1, k,vertices.length); | ||
| //log('b', i,j, i-1, k,vertices.length); | ||
@@ -673,0 +675,0 @@ for ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) { |
@@ -14,2 +14,3 @@ import { PolyhedronGeometry } from './PolyhedronGeometry.js'; | ||
| * @augments PolyhedronGeometry | ||
| * @demo scenes/geometry-browser.html#IcosahedronGeometry | ||
| */ | ||
@@ -16,0 +17,0 @@ class IcosahedronGeometry extends PolyhedronGeometry { |
@@ -22,2 +22,3 @@ import { Float32BufferAttribute } from '../core/BufferAttribute.js'; | ||
| * @augments BufferGeometry | ||
| * @demo scenes/geometry-browser.html#LatheGeometry | ||
| */ | ||
@@ -24,0 +25,0 @@ class LatheGeometry extends BufferGeometry { |
@@ -14,2 +14,3 @@ import { PolyhedronGeometry } from './PolyhedronGeometry.js'; | ||
| * @augments PolyhedronGeometry | ||
| * @demo scenes/geometry-browser.html#OctahedronGeometry | ||
| */ | ||
@@ -16,0 +17,0 @@ class OctahedronGeometry extends PolyhedronGeometry { |
@@ -15,2 +15,3 @@ import { BufferGeometry } from '../core/BufferGeometry.js'; | ||
| * @augments BufferGeometry | ||
| * @demo scenes/geometry-browser.html#PlaneGeometry | ||
| */ | ||
@@ -17,0 +18,0 @@ class PlaneGeometry extends BufferGeometry { |
@@ -17,2 +17,3 @@ import { BufferGeometry } from '../core/BufferGeometry.js'; | ||
| * @augments BufferGeometry | ||
| * @demo scenes/geometry-browser.html#RingGeometry | ||
| */ | ||
@@ -19,0 +20,0 @@ class RingGeometry extends BufferGeometry { |
@@ -22,2 +22,3 @@ import { BufferGeometry } from '../core/BufferGeometry.js'; | ||
| * @augments BufferGeometry | ||
| * @demo scenes/geometry-browser.html#ShapeGeometry | ||
| */ | ||
@@ -24,0 +25,0 @@ class ShapeGeometry extends BufferGeometry { |
@@ -16,2 +16,3 @@ import { BufferGeometry } from '../core/BufferGeometry.js'; | ||
| * @augments BufferGeometry | ||
| * @demo scenes/geometry-browser.html#SphereGeometry | ||
| */ | ||
@@ -18,0 +19,0 @@ class SphereGeometry extends BufferGeometry { |
@@ -14,2 +14,3 @@ import { PolyhedronGeometry } from './PolyhedronGeometry.js'; | ||
| * @augments PolyhedronGeometry | ||
| * @demo scenes/geometry-browser.html#TetrahedronGeometry | ||
| */ | ||
@@ -16,0 +17,0 @@ class TetrahedronGeometry extends PolyhedronGeometry { |
@@ -16,2 +16,3 @@ import { BufferGeometry } from '../core/BufferGeometry.js'; | ||
| * @augments BufferGeometry | ||
| * @demo scenes/geometry-browser.html#TorusGeometry | ||
| */ | ||
@@ -18,0 +19,0 @@ class TorusGeometry extends BufferGeometry { |
@@ -18,2 +18,3 @@ import { BufferGeometry } from '../core/BufferGeometry.js'; | ||
| * @augments BufferGeometry | ||
| * @demo scenes/geometry-browser.html#TorusKnotGeometry | ||
| */ | ||
@@ -20,0 +21,0 @@ class TorusKnotGeometry extends BufferGeometry { |
@@ -32,2 +32,3 @@ import { BufferGeometry } from '../core/BufferGeometry.js'; | ||
| * @augments BufferGeometry | ||
| * @demo scenes/geometry-browser.html#TubeGeometry | ||
| */ | ||
@@ -34,0 +35,0 @@ class TubeGeometry extends BufferGeometry { |
@@ -17,3 +17,3 @@ import { Camera } from '../cameras/Camera.js'; | ||
| * | ||
| * Based on frustum visualization in [lightgl.js shadowmap example]{@link https://github.com/evanw/lightgl.js/blob/master/tests/shadowmap.html}. | ||
| * Based on frustum visualization in [lightgl.js shadowmap example](https://github.com/evanw/lightgl.js/blob/master/tests/shadowmap.html). | ||
| * | ||
@@ -20,0 +20,0 @@ * `CameraHelper` must be a child of the scene. |
| import { AnimationClip } from '../animation/AnimationClip.js'; | ||
| import { FileLoader } from './FileLoader.js'; | ||
| import { Loader } from './Loader.js'; | ||
| import { error } from '../utils.js'; | ||
@@ -60,3 +61,3 @@ /** | ||
| console.error( e ); | ||
| error( e ); | ||
@@ -63,0 +64,0 @@ } |
| import { AudioContext } from '../audio/AudioContext.js'; | ||
| import { FileLoader } from './FileLoader.js'; | ||
| import { Loader } from './Loader.js'; | ||
| import { error } from '../utils.js'; | ||
@@ -84,3 +85,3 @@ /** | ||
| console.error( e ); | ||
| error( e ); | ||
@@ -87,0 +88,0 @@ } |
@@ -10,3 +10,3 @@ import { Sphere } from '../math/Sphere.js'; | ||
| import { InterleavedBuffer } from '../core/InterleavedBuffer.js'; | ||
| import { getTypedArray } from '../utils.js'; | ||
| import { getTypedArray, error } from '../utils.js'; | ||
@@ -71,3 +71,3 @@ /** | ||
| console.error( e ); | ||
| error( e ); | ||
@@ -74,0 +74,0 @@ } |
@@ -38,3 +38,3 @@ /** | ||
| // console.log( 'THREE.Cache', 'Adding key:', key ); | ||
| // log( 'Cache', 'Adding key:', key ); | ||
@@ -56,3 +56,3 @@ this.files[ key ] = file; | ||
| // console.log( 'THREE.Cache', 'Checking key:', key ); | ||
| // log( 'Cache', 'Checking key:', key ); | ||
@@ -59,0 +59,0 @@ return this.files[ key ]; |
@@ -68,3 +68,3 @@ import { LinearFilter, LinearMipmapLinearFilter, ClampToEdgeWrapping } from '../constants.js'; | ||
| console.error( error ); | ||
| error( error ); | ||
| return; | ||
@@ -71,0 +71,0 @@ |
| import { Cache } from './Cache.js'; | ||
| import { Loader } from './Loader.js'; | ||
| import { warn } from '../utils.js'; | ||
@@ -45,3 +46,3 @@ const loading = {}; | ||
| * The expected mime type. Valid values can be found | ||
| * [here]{@link hhttps://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString#mimetype} | ||
| * [here](hhttps://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString#mimetype) | ||
| * | ||
@@ -152,3 +153,3 @@ * @type {string} | ||
| console.warn( 'THREE.FileLoader: HTTP Status 0 received.' ); | ||
| warn( 'FileLoader: HTTP Status 0 received.' ); | ||
@@ -155,0 +156,0 @@ } |
| import { Cache } from './Cache.js'; | ||
| import { Loader } from './Loader.js'; | ||
| import { warn } from '../utils.js'; | ||
@@ -7,3 +8,3 @@ const _errorMap = new WeakMap(); | ||
| /** | ||
| * A loader for loading images as an [ImageBitmap]{@link https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap}. | ||
| * A loader for loading images as an [ImageBitmap](https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap). | ||
| * An `ImageBitmap` provides an asynchronous and resource efficient pathway to prepare | ||
@@ -52,3 +53,3 @@ * textures for rendering. | ||
| console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' ); | ||
| warn( 'ImageBitmapLoader: createImageBitmap() not supported.' ); | ||
@@ -59,3 +60,3 @@ } | ||
| console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' ); | ||
| warn( 'ImageBitmapLoader: fetch() not supported.' ); | ||
@@ -84,3 +85,3 @@ } | ||
| * Sets the given loader options. The structure of the object must match the `options` parameter of | ||
| * [createImageBitmap]{@link https://developer.mozilla.org/en-US/docs/Web/API/Window/createImageBitmap}. | ||
| * [createImageBitmap](https://developer.mozilla.org/en-US/docs/Web/API/Window/createImageBitmap). | ||
| * | ||
@@ -87,0 +88,0 @@ * @param {Object} options - The loader options to set. |
@@ -16,3 +16,3 @@ import { Cache } from './Cache.js'; | ||
| * events in `r84`. For an `ImageLoader` that supports progress events, see | ||
| * [this thread]{@link https://github.com/mrdoob/three.js/issues/10439#issuecomment-275785639}. | ||
| * [this thread](https://github.com/mrdoob/three.js/issues/10439#issuecomment-275785639). | ||
| * | ||
@@ -19,0 +19,0 @@ * @augments Loader |
@@ -57,3 +57,3 @@ import { DefaultLoadingManager } from './LoadingManager.js'; | ||
| /** | ||
| * The [request header]{@link https://developer.mozilla.org/en-US/docs/Glossary/Request_header} | ||
| * The [request header](https://developer.mozilla.org/en-US/docs/Glossary/Request_header) | ||
| * used in HTTP request. | ||
@@ -123,3 +123,3 @@ * | ||
| * Whether the XMLHttpRequest uses credentials such as cookies, authorization | ||
| * headers or TLS client certificates, see [XMLHttpRequest.withCredentials]{@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials}. | ||
| * headers or TLS client certificates, see [XMLHttpRequest.withCredentials](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials). | ||
| * | ||
@@ -167,3 +167,3 @@ * Note: This setting has no effect if you are loading files locally or from the same domain. | ||
| * | ||
| * @param {Object} requestHeader - A [request header]{@link https://developer.mozilla.org/en-US/docs/Glossary/Request_header} | ||
| * @param {Object} requestHeader - A [request header](https://developer.mozilla.org/en-US/docs/Glossary/Request_header) | ||
| * for configuring the HTTP request. | ||
@@ -170,0 +170,0 @@ * @return {Loader} A reference to this instance. |
@@ -75,5 +75,6 @@ /** | ||
| * | ||
| * @type {AbortController} | ||
| * @private | ||
| * @type {AbortController | null} | ||
| */ | ||
| this.abortController = new AbortController(); | ||
| this._abortController = null; | ||
@@ -289,4 +290,5 @@ /** | ||
| this.abortController.abort(); | ||
| this.abortController = new AbortController(); | ||
| this._abortController = null; | ||
@@ -299,2 +301,22 @@ return this; | ||
| // TODO: Revert this back to a single member variable once this issue has been fixed | ||
| // https://github.com/cloudflare/workerd/issues/3657 | ||
| /** | ||
| * Used for aborting ongoing requests in loaders using this manager. | ||
| * | ||
| * @type {AbortController} | ||
| */ | ||
| get abortController() { | ||
| if ( ! this._abortController ) { | ||
| this._abortController = new AbortController(); | ||
| } | ||
| return this._abortController; | ||
| } | ||
| } | ||
@@ -301,0 +323,0 @@ |
@@ -29,2 +29,3 @@ import { Color } from '../math/Color.js'; | ||
| } from '../materials/Materials.js'; | ||
| import { error, warn } from '../utils.js'; | ||
@@ -93,3 +94,3 @@ /** | ||
| console.error( e ); | ||
| error( e ); | ||
@@ -120,3 +121,3 @@ } | ||
| console.warn( 'THREE.MaterialLoader: Undefined texture', name ); | ||
| warn( 'MaterialLoader: Undefined texture', name ); | ||
@@ -123,0 +124,0 @@ } |
@@ -5,2 +5,3 @@ import { nodeObject, float } from '../../nodes/tsl/TSLBase.js'; | ||
| import { FileLoader } from '../../loaders/FileLoader.js'; | ||
| import { error } from '../../utils.js'; | ||
@@ -67,3 +68,3 @@ /** | ||
| console.error( e ); | ||
| error( e ); | ||
@@ -184,3 +185,3 @@ } | ||
| console.error( 'THREE.NodeLoader: Node type not found:', type ); | ||
| error( 'NodeLoader: Node type not found:', type ); | ||
| return float(); | ||
@@ -187,0 +188,0 @@ |
@@ -62,3 +62,3 @@ import { | ||
| import * as Geometries from '../geometries/Geometries.js'; | ||
| import { getTypedArray } from '../utils.js'; | ||
| import { getTypedArray, error, warn } from '../utils.js'; | ||
| import { Box3 } from '../math/Box3.js'; | ||
@@ -68,3 +68,3 @@ import { Sphere } from '../math/Sphere.js'; | ||
| /** | ||
| * A loader for loading a JSON resource in the [JSON Object/Scene format]{@link https://github.com/mrdoob/three.js/wiki/JSON-Object-Scene-format-4}. | ||
| * A loader for loading a JSON resource in the [JSON Object/Scene format](https://github.com/mrdoob/three.js/wiki/JSON-Object-Scene-format-4). | ||
| * The files are internally loaded via {@link FileLoader}. | ||
@@ -128,3 +128,3 @@ * | ||
| console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); | ||
| error( 'ObjectLoader: Can\'t parse ' + url + '.', error.message ); | ||
@@ -141,3 +141,3 @@ return; | ||
| console.error( 'THREE.ObjectLoader: Can\'t load ' + url ); | ||
| error( 'ObjectLoader: Can\'t load ' + url ); | ||
| return; | ||
@@ -352,3 +352,3 @@ | ||
| console.warn( `THREE.ObjectLoader: Unsupported geometry type "${ data.type }"` ); | ||
| warn( `ObjectLoader: Unsupported geometry type "${ data.type }"` ); | ||
@@ -644,3 +644,3 @@ } | ||
| console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); | ||
| warn( 'ObjectLoader.parseTexture: Constant should be in numeric form.', value ); | ||
@@ -661,3 +661,3 @@ return type[ value ]; | ||
| console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); | ||
| warn( 'ObjectLoader: No "image" specified for', data.uuid ); | ||
@@ -668,3 +668,3 @@ } | ||
| console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); | ||
| warn( 'ObjectLoader: Undefined image', data.image ); | ||
@@ -757,3 +757,3 @@ } | ||
| console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); | ||
| warn( 'ObjectLoader: Undefined geometry', name ); | ||
@@ -780,3 +780,3 @@ } | ||
| console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); | ||
| warn( 'ObjectLoader: Undefined material', uuid ); | ||
@@ -795,3 +795,3 @@ } | ||
| console.warn( 'THREE.ObjectLoader: Undefined material', name ); | ||
| warn( 'ObjectLoader: Undefined material', name ); | ||
@@ -808,3 +808,3 @@ } | ||
| console.warn( 'THREE.ObjectLoader: Undefined texture', uuid ); | ||
| warn( 'ObjectLoader: Undefined texture', uuid ); | ||
@@ -1210,3 +1210,3 @@ } | ||
| console.warn( 'THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton ); | ||
| warn( 'ObjectLoader: No skeleton found with UUID:', child.skeleton ); | ||
@@ -1213,0 +1213,0 @@ } else { |
@@ -17,3 +17,3 @@ import { ImageLoader } from './ImageLoader.js'; | ||
| * events in `r84`. For a `TextureLoader` that supports progress events, see | ||
| * [this thread]{@link https://github.com/mrdoob/three.js/issues/10439#issuecomment-293260145}. | ||
| * [this thread](https://github.com/mrdoob/three.js/issues/10439#issuecomment-293260145). | ||
| * | ||
@@ -20,0 +20,0 @@ * @augments Loader |
@@ -5,2 +5,3 @@ import { Color } from '../math/Color.js'; | ||
| import { generateUUID } from '../math/MathUtils.js'; | ||
| import { warn } from '../utils.js'; | ||
@@ -526,3 +527,3 @@ let _materialId = 0; | ||
| * recommended approach when customizing materials is to use `WebGPURenderer` with the new | ||
| * Node Material system and [TSL]{@link https://github.com/mrdoob/three.js/wiki/Three.js-Shading-Language}. | ||
| * Node Material system and [TSL](https://github.com/mrdoob/three.js/wiki/Three.js-Shading-Language). | ||
| * | ||
@@ -566,3 +567,3 @@ * @param {{vertexShader:string,fragmentShader:string,uniforms:Object}} shaderobject - The object holds the uniforms and the vertex and fragment shader source. | ||
| console.warn( `THREE.Material: parameter '${ key }' has value of undefined.` ); | ||
| warn( `Material: parameter '${ key }' has value of undefined.` ); | ||
| continue; | ||
@@ -576,3 +577,3 @@ | ||
| console.warn( `THREE.Material: '${ key }' is not a property of THREE.${ this.type }.` ); | ||
| warn( `Material: '${ key }' is not a property of THREE.${ this.type }.` ); | ||
| continue; | ||
@@ -579,0 +580,0 @@ |
@@ -12,2 +12,3 @@ import { Material } from './Material.js'; | ||
| * @augments Material | ||
| * @demo scenes/material-browser.html#MeshBasicMaterial | ||
| */ | ||
@@ -14,0 +15,0 @@ class MeshBasicMaterial extends Material { |
@@ -9,2 +9,3 @@ import { Material } from './Material.js'; | ||
| * @augments Material | ||
| * @demo scenes/material-browser.html#MeshDepthMaterial | ||
| */ | ||
@@ -11,0 +12,0 @@ class MeshDepthMaterial extends Material { |
@@ -10,3 +10,3 @@ import { MultiplyOperation, TangentSpaceNormalMap } from '../constants.js'; | ||
| * | ||
| * The material uses a non-physically based [Lambertian]{@link https://en.wikipedia.org/wiki/Lambertian_reflectance} | ||
| * The material uses a non-physically based [Lambertian](https://en.wikipedia.org/wiki/Lambertian_reflectance) | ||
| * model for calculating reflectance. This can simulate some surfaces (such | ||
@@ -23,2 +23,3 @@ * as untreated wood or stone) well, but cannot simulate shiny surfaces with | ||
| * @augments Material | ||
| * @demo scenes/material-browser.html#MeshLambertMaterial | ||
| */ | ||
@@ -25,0 +26,0 @@ class MeshLambertMaterial extends Material { |
@@ -16,2 +16,3 @@ import { TangentSpaceNormalMap } from '../constants.js'; | ||
| * @augments Material | ||
| * @demo scenes/material-browser.html#MeshMatcapMaterial | ||
| */ | ||
@@ -169,2 +170,20 @@ class MeshMatcapMaterial extends Material { | ||
| /** | ||
| * Renders the geometry as a wireframe. | ||
| * | ||
| * @type {boolean} | ||
| * @default false | ||
| */ | ||
| this.wireframe = false; | ||
| /** | ||
| * Controls the thickness of the wireframe. | ||
| * | ||
| * Can only be used with {@link SVGRenderer}. | ||
| * | ||
| * @type {number} | ||
| * @default 1 | ||
| */ | ||
| this.wireframeLinewidth = 1; | ||
| /** | ||
| * Whether the material is rendered with flat shading or not. | ||
@@ -215,2 +234,5 @@ * | ||
| this.wireframe = source.wireframe; | ||
| this.wireframeLinewidth = source.wireframeLinewidth; | ||
| this.flatShading = source.flatShading; | ||
@@ -217,0 +239,0 @@ |
@@ -9,2 +9,3 @@ import { TangentSpaceNormalMap } from '../constants.js'; | ||
| * @augments Material | ||
| * @demo scenes/material-browser.html#MeshNormalMaterial | ||
| */ | ||
@@ -11,0 +12,0 @@ class MeshNormalMaterial extends Material { |
@@ -10,3 +10,3 @@ import { MultiplyOperation, TangentSpaceNormalMap } from '../constants.js'; | ||
| * | ||
| * The material uses a non-physically based [Blinn-Phong]{@link https://en.wikipedia.org/wiki/Blinn-Phong_shading_model} | ||
| * The material uses a non-physically based [Blinn-Phong](https://en.wikipedia.org/wiki/Blinn-Phong_shading_model) | ||
| * model for calculating reflectance. Unlike the Lambertian model used in the | ||
@@ -21,2 +21,3 @@ * {@link MeshLambertMaterial} this can simulate shiny surfaces with specular | ||
| * @augments Material | ||
| * @demo scenes/material-browser.html#MeshPhongMaterial | ||
| */ | ||
@@ -23,0 +24,0 @@ class MeshPhongMaterial extends Material { |
@@ -30,2 +30,3 @@ import { Vector2 } from '../math/Vector2.js'; | ||
| * @augments MeshStandardMaterial | ||
| * @demo scenes/material-browser.html#MeshPhysicalMaterial | ||
| */ | ||
@@ -327,3 +328,3 @@ class MeshPhysicalMaterial extends MeshStandardMaterial { | ||
| /** | ||
| * The anisotropy strength. | ||
| * The anisotropy strength, from `0.0` to `1.0`. | ||
| * | ||
@@ -330,0 +331,0 @@ * @type {number} |
@@ -11,5 +11,5 @@ import { TangentSpaceNormalMap } from '../constants.js'; | ||
| * Physically based rendering (PBR) has recently become the standard in many | ||
| * 3D applications, such as [Unity]{@link https://blogs.unity3d.com/2014/10/29/physically-based-shading-in-unity-5-a-primer/}, | ||
| * [Unreal]{@link https://docs.unrealengine.com/latest/INT/Engine/Rendering/Materials/PhysicallyBased/} and | ||
| * [3D Studio Max]{@link http://area.autodesk.com/blogs/the-3ds-max-blog/what039s-new-for-rendering-in-3ds-max-2017}. | ||
| * 3D applications, such as [Unity](https://blogs.unity3d.com/2014/10/29/physically-based-shading-in-unity-5-a-primer/), | ||
| * [Unreal](https://docs.unrealengine.com/latest/INT/Engine/Rendering/Materials/PhysicallyBased/) and | ||
| * [3D Studio Max](http://area.autodesk.com/blogs/the-3ds-max-blog/what039s-new-for-rendering-in-3ds-max-2017). | ||
| * | ||
@@ -30,12 +30,13 @@ * This approach differs from older approaches in that instead of using | ||
| * For a non-technical introduction to the concept of PBR and how to set up a | ||
| * PBR material, check out these articles by the people at [marmoset]{@link https://www.marmoset.co}: | ||
| * PBR material, check out these articles by the people at [marmoset](https://www.marmoset.co): | ||
| * | ||
| * - [Basic Theory of Physically Based Rendering]{@link https://www.marmoset.co/posts/basic-theory-of-physically-based-rendering/} | ||
| * - [Physically Based Rendering and You Can Too]{@link https://www.marmoset.co/posts/physically-based-rendering-and-you-can-too/} | ||
| * - [Basic Theory of Physically Based Rendering](https://www.marmoset.co/posts/basic-theory-of-physically-based-rendering/) | ||
| * - [Physically Based Rendering and You Can Too](https://www.marmoset.co/posts/physically-based-rendering-and-you-can-too/) | ||
| * | ||
| * Technical details of the approach used in three.js (and most other PBR systems) can be found is this | ||
| * [paper from Disney]{@link https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf} | ||
| * [paper from Disney](https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf) | ||
| * (pdf), by Brent Burley. | ||
| * | ||
| * @augments Material | ||
| * @demo scenes/material-browser.html#MeshStandardMaterial | ||
| */ | ||
@@ -42,0 +43,0 @@ class MeshStandardMaterial extends Material { |
@@ -10,2 +10,3 @@ import { TangentSpaceNormalMap } from '../constants.js'; | ||
| * @augments Material | ||
| * @demo scenes/material-browser.html#MeshToonMaterial | ||
| */ | ||
@@ -12,0 +13,0 @@ class MeshToonMaterial extends Material { |
@@ -381,3 +381,3 @@ import NodeMaterial from './NodeMaterial.js'; | ||
| if ( useAlphaToCoverage && renderer.samples > 1 ) { | ||
| if ( useAlphaToCoverage && renderer.currentSamples > 0 ) { | ||
@@ -399,3 +399,3 @@ const dnorm = norm.fwidth(); | ||
| if ( useAlphaToCoverage && renderer.samples > 1 ) { | ||
| if ( useAlphaToCoverage && renderer.currentSamples > 0 ) { | ||
@@ -402,0 +402,0 @@ const a = vUv.x; |
@@ -468,2 +468,3 @@ const refreshUniforms = [ | ||
| renderObjectData.morphTargetInfluences[ i ] = object.morphTargetInfluences[ i ]; | ||
| morphChanged = true; | ||
@@ -475,3 +476,3 @@ | ||
| if ( morphChanged ) return true; | ||
| if ( morphChanged ) return false; | ||
@@ -478,0 +479,0 @@ } |
@@ -42,3 +42,3 @@ import MeshPhysicalNodeMaterial from './MeshPhysicalNodeMaterial.js'; | ||
| * | ||
| * Reference: [Approximating Translucency for a Fast, Cheap and Convincing Subsurface Scattering Look]{@link https://colinbarrebrisebois.com/2011/03/07/gdc-2011-approximating-translucency-for-a-fast-cheap-and-convincing-subsurface-scattering-look/} | ||
| * Reference: [Approximating Translucency for a Fast, Cheap and Convincing Subsurface Scattering Look](https://colinbarrebrisebois.com/2011/03/07/gdc-2011-approximating-translucency-for-a-fast-cheap-and-convincing-subsurface-scattering-look/) | ||
| * | ||
@@ -45,0 +45,0 @@ * @param {Object} input - The input data. |
| import { Material } from '../Material.js'; | ||
| import { NormalBlending } from '../../constants.js'; | ||
| import { getNodeChildren, getCacheKey } from '../../nodes/core/NodeUtils.js'; | ||
| import { hashArray, hashString } from '../../nodes/core/NodeUtils.js'; | ||
| import { output, diffuseColor, emissive, varyingProperty } from '../../nodes/core/PropertyNode.js'; | ||
@@ -15,3 +14,3 @@ import { materialAlphaTest, materialColor, materialOpacity, materialEmissive, materialNormal, materialLightMap, materialAO } from '../../nodes/accessors/MaterialNode.js'; | ||
| import { morphReference } from '../../nodes/accessors/MorphNode.js'; | ||
| import { mix } from '../../nodes/math/MathNode.js'; | ||
| import { fwidth, mix, smoothstep } from '../../nodes/math/MathNode.js'; | ||
| import { float, vec3, vec4, bool } from '../../nodes/tsl/TSLBase.js'; | ||
@@ -30,2 +29,3 @@ import AONode from '../../nodes/lighting/AONode.js'; | ||
| import { subBuild } from '../../nodes/core/SubBuildNode.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -186,3 +186,3 @@ /** | ||
| * | ||
| * If you don't want to overwrite the normals but modify the existing | ||
| * If you don't want to overwrite the opacity but modify the existing | ||
| * value instead, use {@link materialOpacity}. | ||
@@ -400,3 +400,3 @@ * | ||
| console.warn( 'THREE.NodeMaterial: ".shadowPositionNode" was renamed to ".receivedShadowPositionNode".' ); | ||
| warn( 'NodeMaterial: ".shadowPositionNode" was renamed to ".receivedShadowPositionNode".' ); | ||
@@ -412,2 +412,30 @@ this.receivedShadowPositionNode = value; | ||
| /** | ||
| * Returns an array of child nodes for this material. | ||
| * | ||
| * @private | ||
| * @returns {Array<{property: string, childNode: Node}>} | ||
| */ | ||
| _getNodeChildren() { | ||
| const children = []; | ||
| for ( const property of Object.getOwnPropertyNames( this ) ) { | ||
| if ( property.startsWith( '_' ) === true ) continue; | ||
| const object = this[ property ]; | ||
| if ( object && object.isNode === true ) { | ||
| children.push( { property, childNode: object } ); | ||
| } | ||
| } | ||
| return children; | ||
| } | ||
| /** | ||
| * Allows to define a custom cache key that influence the material key computation | ||
@@ -420,4 +448,12 @@ * for render objects. | ||
| return this.type + getCacheKey( this ); | ||
| const values = []; | ||
| for ( const { property, childNode } of this._getNodeChildren() ) { | ||
| values.push( hashString( property.slice( 0, - 4 ) ), childNode.getCacheKey() ); | ||
| } | ||
| return this.type + hashArray( values ); | ||
| } | ||
@@ -513,3 +549,3 @@ | ||
| if ( clippingNode !== null ) builder.stack.add( clippingNode ); | ||
| if ( clippingNode !== null ) builder.stack.addToStack( clippingNode ); | ||
@@ -599,3 +635,3 @@ // force unsigned floats - useful for RenderTargets | ||
| const samples = builder.renderer.samples; | ||
| const samples = builder.renderer.currentSamples; | ||
@@ -609,3 +645,3 @@ if ( this.alphaToCoverage && samples > 1 ) { | ||
| builder.stack.add( clipping() ); | ||
| builder.stack.addToStack( clipping() ); | ||
@@ -637,3 +673,3 @@ } | ||
| builder.stack.add( hardwareClipping() ); | ||
| builder.stack.addToStack( hardwareClipping() ); | ||
@@ -796,4 +832,6 @@ this.hardwareClipping = true; | ||
| */ | ||
| setupDiffuseColor( { object, geometry } ) { | ||
| setupDiffuseColor( builder ) { | ||
| const { object, geometry } = builder; | ||
| // MASK | ||
@@ -856,4 +894,13 @@ | ||
| diffuseColor.a.lessThanEqual( alphaTestNode ).discard(); | ||
| if ( this.alphaToCoverage === true ) { | ||
| diffuseColor.a = smoothstep( alphaTestNode, alphaTestNode.add( fwidth( diffuseColor.a ) ), diffuseColor.a ); | ||
| diffuseColor.a.lessThanEqual( 0 ).discard(); | ||
| } else { | ||
| diffuseColor.a.lessThanEqual( alphaTestNode ).discard(); | ||
| } | ||
| } | ||
@@ -871,12 +918,6 @@ | ||
| const isOpaque = this.transparent === false && this.blending === NormalBlending && this.alphaToCoverage === false; | ||
| if ( builder.isOpaque() ) { | ||
| if ( isOpaque ) { | ||
| diffuseColor.a.assign( 1.0 ); | ||
| } else if ( alphaTestNode === null ) { | ||
| diffuseColor.a.lessThanEqual( 0 ).discard(); | ||
| } | ||
@@ -1199,7 +1240,5 @@ | ||
| const data = Material.prototype.toJSON.call( this, meta ); | ||
| const nodeChildren = getNodeChildren( this ); | ||
| data.inputNodes = {}; | ||
| for ( const { property, childNode } of nodeChildren ) { | ||
| for ( const { property, childNode } of this._getNodeChildren() ) { | ||
@@ -1254,2 +1293,3 @@ data.inputNodes[ property ] = childNode.toJSON( meta ).uuid; | ||
| this.envNode = source.envNode; | ||
| this.aoNode = source.aoNode; | ||
@@ -1256,0 +1296,0 @@ this.colorNode = source.colorNode; |
@@ -91,3 +91,3 @@ import { Material } from './Material.js'; | ||
| * | ||
| * Might be capped if the value exceeds hardware dependent parameters like [gl.ALIASED_POINT_SIZE_RANGE]{@link https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/getParamete}. | ||
| * Might be capped if the value exceeds hardware dependent parameters like [gl.ALIASED_POINT_SIZE_RANGE](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/getParamete). | ||
| * | ||
@@ -94,0 +94,0 @@ * @type {number} |
@@ -20,3 +20,3 @@ import { Material } from './Material.js'; | ||
| * to be placed right above the loop. The loop formatting has to correspond to a defined standard. | ||
| * - The loop has to be [normalized]{@link https://en.wikipedia.org/wiki/Normalized_loop}. | ||
| * - The loop has to be [normalized](https://en.wikipedia.org/wiki/Normalized_loop). | ||
| * - The loop variable has to be *i*. | ||
@@ -227,3 +227,3 @@ * - The value `UNROLLED_LOOP_INDEX` will be replaced with the explicitly | ||
| /** | ||
| * If set, this calls [gl.bindAttribLocation]{@link https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/bindAttribLocation} | ||
| * If set, this calls [gl.bindAttribLocation](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/bindAttribLocation) | ||
| * to bind a generic vertex index to an attribute variable. | ||
@@ -230,0 +230,0 @@ * |
| import { clamp, euclideanModulo, lerp } from './MathUtils.js'; | ||
| import { ColorManagement, SRGBToLinear, LinearToSRGB } from './ColorManagement.js'; | ||
| import { SRGBColorSpace } from '../constants.js'; | ||
| import { warn } from '../utils.js'; | ||
@@ -278,3 +279,3 @@ const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, | ||
| * `rgb(100%, 0%, 0%)`, `hsl(0, 100%, 50%)`, `#ff0000`, `#f00`, or `red` ( or | ||
| * any [X11 color name]{@link https://en.wikipedia.org/wiki/X11_color_names#Color_name_chart} - | ||
| * any [X11 color name](https://en.wikipedia.org/wiki/X11_color_names#Color_name_chart) - | ||
| * all 140 color names are supported). | ||
@@ -294,3 +295,3 @@ * | ||
| console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); | ||
| warn( 'Color: Alpha component of ' + style + ' will be ignored.' ); | ||
@@ -371,3 +372,3 @@ } | ||
| console.warn( 'THREE.Color: Unknown color model ' + style ); | ||
| warn( 'Color: Unknown color model ' + style ); | ||
@@ -400,3 +401,3 @@ } | ||
| console.warn( 'THREE.Color: Invalid hex color ' + style ); | ||
| warn( 'Color: Invalid hex color ' + style ); | ||
@@ -441,3 +442,3 @@ } | ||
| // unknown color | ||
| console.warn( 'THREE.Color: Unknown color ' + style ); | ||
| warn( 'Color: Unknown color ' + style ); | ||
@@ -444,0 +445,0 @@ } |
@@ -150,3 +150,3 @@ import { SRGBColorSpace, LinearSRGBColorSpace, SRGBTransfer, LinearTransfer, NoColorSpace } from '../constants.js'; | ||
| warnOnce( 'THREE.ColorManagement: .fromWorkingColorSpace() has been renamed to .workingToColorSpace().' ); // @deprecated, r177 | ||
| warnOnce( 'ColorManagement: .fromWorkingColorSpace() has been renamed to .workingToColorSpace().' ); // @deprecated, r177 | ||
@@ -159,3 +159,3 @@ return ColorManagement.workingToColorSpace( color, targetColorSpace ); | ||
| warnOnce( 'THREE.ColorManagement: .toWorkingColorSpace() has been renamed to .colorSpaceToWorking().' ); // @deprecated, r177 | ||
| warnOnce( 'ColorManagement: .toWorkingColorSpace() has been renamed to .colorSpaceToWorking().' ); // @deprecated, r177 | ||
@@ -162,0 +162,0 @@ return ColorManagement.colorSpaceToWorking( color, sourceColorSpace ); |
| /** | ||
| * This class can be used to represent points in 3D space as | ||
| * [Cylindrical coordinates]{@link https://en.wikipedia.org/wiki/Cylindrical_coordinate_system}. | ||
| * [Cylindrical coordinates](https://en.wikipedia.org/wiki/Cylindrical_coordinate_system). | ||
| */ | ||
@@ -5,0 +5,0 @@ class Cylindrical { |
| import { Quaternion } from './Quaternion.js'; | ||
| import { Matrix4 } from './Matrix4.js'; | ||
| import { clamp } from './MathUtils.js'; | ||
| import { warn } from '../utils.js'; | ||
@@ -307,3 +308,3 @@ const _matrix = /*@__PURE__*/ new Matrix4(); | ||
| console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order ); | ||
| warn( 'Euler: .setFromRotationMatrix() encountered an unknown order: ' + order ); | ||
@@ -310,0 +311,0 @@ } |
+13
-11
@@ -0,1 +1,3 @@ | ||
| import { warn } from '../utils.js'; | ||
| const _lut = [ '00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '0a', '0b', '0c', '0d', '0e', '0f', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '1a', '1b', '1c', '1d', '1e', '1f', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '2a', '2b', '2c', '2d', '2e', '2f', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '3a', '3b', '3c', '3d', '3e', '3f', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '4a', '4b', '4c', '4d', '4e', '4f', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '5a', '5b', '5c', '5d', '5e', '5f', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '6a', '6b', '6c', '6d', '6e', '6f', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '7a', '7b', '7c', '7d', '7e', '7f', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '8a', '8b', '8c', '8d', '8e', '8f', '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', '9a', '9b', '9c', '9d', '9e', '9f', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'a9', 'aa', 'ab', 'ac', 'ad', 'ae', 'af', 'b0', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'b9', 'ba', 'bb', 'bc', 'bd', 'be', 'bf', 'c0', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'ca', 'cb', 'cc', 'cd', 'ce', 'cf', 'd0', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9', 'da', 'db', 'dc', 'dd', 'de', 'df', 'e0', 'e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7', 'e8', 'e9', 'ea', 'eb', 'ec', 'ed', 'ee', 'ef', 'f0', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'fa', 'fb', 'fc', 'fd', 'fe', 'ff' ]; | ||
@@ -10,3 +12,3 @@ | ||
| /** | ||
| * Generate a [UUID]{@link https://en.wikipedia.org/wiki/Universally_unique_identifier} | ||
| * Generate a [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier) | ||
| * (universally unique identifier). | ||
@@ -124,3 +126,3 @@ * | ||
| * time to maintain frame rate independent movement. For details, see | ||
| * [Frame rate independent damping using lerp]{@link http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/}. | ||
| * [Frame rate independent damping using lerp](http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/). | ||
| * | ||
@@ -160,3 +162,3 @@ * @param {number} x - The current point. | ||
| * | ||
| * See [Smoothstep]{@link http://en.wikipedia.org/wiki/Smoothstep} for more details. | ||
| * See [Smoothstep](http://en.wikipedia.org/wiki/Smoothstep) for more details. | ||
| * | ||
@@ -180,3 +182,3 @@ * @param {number} x - The value to evaluate based on its position between min and max. | ||
| /** | ||
| * A [variation on smoothstep]{@link https://en.wikipedia.org/wiki/Smoothstep#Variations} | ||
| * A [variation on smoothstep](https://en.wikipedia.org/wiki/Smoothstep#Variations) | ||
| * that has zero 1st and 2nd order derivatives at x=0 and x=1. | ||
@@ -321,3 +323,3 @@ * | ||
| /** | ||
| * Sets the given quaternion from the [Intrinsic Proper Euler Angles]{@link https://en.wikipedia.org/wiki/Euler_angles} | ||
| * Sets the given quaternion from the [Intrinsic Proper Euler Angles](https://en.wikipedia.org/wiki/Euler_angles) | ||
| * defined by the given angles and order. | ||
@@ -378,3 +380,3 @@ * | ||
| default: | ||
| console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order ); | ||
| warn( 'MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order ); | ||
@@ -488,3 +490,3 @@ } | ||
| /** | ||
| * Generate a [UUID]{@link https://en.wikipedia.org/wiki/Universally_unique_identifier} | ||
| * Generate a [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier) | ||
| * (universally unique identifier). | ||
@@ -560,3 +562,3 @@ * | ||
| * time to maintain frame rate independent movement. For details, see | ||
| * [Frame rate independent damping using lerp]{@link http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/}. | ||
| * [Frame rate independent damping using lerp](http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/). | ||
| * | ||
@@ -588,3 +590,3 @@ * @static | ||
| * | ||
| * See [Smoothstep]{@link http://en.wikipedia.org/wiki/Smoothstep} for more details. | ||
| * See [Smoothstep](http://en.wikipedia.org/wiki/Smoothstep) for more details. | ||
| * | ||
@@ -600,3 +602,3 @@ * @static | ||
| /** | ||
| * A [variation on smoothstep]{@link https://en.wikipedia.org/wiki/Smoothstep#Variations} | ||
| * A [variation on smoothstep](https://en.wikipedia.org/wiki/Smoothstep#Variations) | ||
| * that has zero 1st and 2nd order derivatives at x=0 and x=1. | ||
@@ -696,3 +698,3 @@ * | ||
| /** | ||
| * Sets the given quaternion from the [Intrinsic Proper Euler Angles]{@link https://en.wikipedia.org/wiki/Euler_angles} | ||
| * Sets the given quaternion from the [Intrinsic Proper Euler Angles](https://en.wikipedia.org/wiki/Euler_angles) | ||
| * defined by the given angles and order. | ||
@@ -699,0 +701,0 @@ * |
@@ -7,3 +7,3 @@ /** | ||
| * The constructor and {@link Matrix2#set} method take arguments in | ||
| * [row-major]{@link https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order} | ||
| * [row-major](https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order) | ||
| * order, while internally they are stored in the {@link Matrix2#elements} array in column-major order. | ||
@@ -10,0 +10,0 @@ * This means that calling: |
@@ -7,3 +7,3 @@ /** | ||
| * The constructor and {@link Matrix3#set} method take arguments in | ||
| * [row-major]{@link https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order} | ||
| * [row-major](https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order) | ||
| * order, while internally they are stored in the {@link Matrix3#elements} array in column-major order. | ||
@@ -282,3 +282,3 @@ * This means that calling: | ||
| /** | ||
| * Inverts this matrix, using the [analytic method]{@link https://en.wikipedia.org/wiki/Invertible_matrix#Analytic_solution}. | ||
| * Inverts this matrix, using the [analytic method](https://en.wikipedia.org/wiki/Invertible_matrix#Analytic_solution). | ||
| * You can not invert with a determinant of zero. If you attempt this, the method produces | ||
@@ -285,0 +285,0 @@ * a zero matrix instead. |
@@ -8,3 +8,3 @@ import { WebGLCoordinateSystem, WebGPUCoordinateSystem } from '../constants.js'; | ||
| * The most common use of a 4x4 matrix in 3D computer graphics is as a transformation matrix. | ||
| * For an introduction to transformation matrices as used in WebGL, check out [this tutorial]{@link https://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices} | ||
| * For an introduction to transformation matrices as used in WebGL, check out [this tutorial](https://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices) | ||
| * | ||
@@ -19,3 +19,3 @@ * This allows a 3D vector representing a point in 3D space to undergo | ||
| * The constructor and {@link Matrix3#set} method take arguments in | ||
| * [row-major]{@link https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order} | ||
| * [row-major](https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order) | ||
| * order, while internally they are stored in the {@link Matrix3#elements} array in column-major order. | ||
@@ -314,3 +314,3 @@ * This means that calling: | ||
| * the matrix is set to the identity. Depending on the {@link Euler#order}, | ||
| * there are six possible outcomes. See [this page]{@link https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix} | ||
| * there are six possible outcomes. See [this page](https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix) | ||
| * for a complete list. | ||
@@ -445,3 +445,3 @@ * | ||
| * Sets the rotation component of this matrix to the rotation specified by | ||
| * the given Quaternion as outlined [here]{@link https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion} | ||
| * the given Quaternion as outlined [here](https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion) | ||
| * The rest of the matrix is set to the identity. | ||
@@ -608,3 +608,3 @@ * | ||
| * | ||
| * Based on the method outlined [here]{@link http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.html}. | ||
| * Based on the method outlined [here](http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.html). | ||
| * | ||
@@ -716,3 +716,3 @@ * @return {number} The determinant. | ||
| /** | ||
| * Inverts this matrix, using the [analytic method]{@link https://en.wikipedia.org/wiki/Invertible_matrix#Analytic_solution}. | ||
| * Inverts this matrix, using the [analytic method](https://en.wikipedia.org/wiki/Invertible_matrix#Analytic_solution). | ||
| * You can not invert with a determinant of zero. If you attempt this, the method produces | ||
@@ -920,3 +920,3 @@ * a zero matrix instead. | ||
| * This is a somewhat controversial but mathematically sound alternative to | ||
| * rotating via Quaternions. See the discussion [here]{@link https://www.gamedev.net/articles/programming/math-and-physics/do-we-really-need-quaternions-r1199}. | ||
| * rotating via Quaternions. See the discussion [here](https://www.gamedev.net/articles/programming/math-and-physics/do-we-really-need-quaternions-r1199). | ||
| * | ||
@@ -923,0 +923,0 @@ * @param {Vector3} axis - The normalized rotation axis. |
@@ -10,3 +10,3 @@ import { Matrix3 } from './Matrix3.js'; | ||
| * A two dimensional surface that extends infinitely in 3D space, represented | ||
| * in [Hessian normal form]{@link http://mathworld.wolfram.com/HessianNormalForm.html} | ||
| * in [Hessian normal form](http://mathworld.wolfram.com/HessianNormalForm.html) | ||
| * by a unit length normal vector and a constant. | ||
@@ -13,0 +13,0 @@ */ |
+68
-66
| import { clamp } from './MathUtils.js'; | ||
| import { warn } from '../utils.js'; | ||
@@ -48,3 +49,3 @@ /** | ||
| * Interpolates between two quaternions via SLERP. This implementation assumes the | ||
| * quaternion data are managed in flat arrays. | ||
| * quaternion data are managed in flat arrays. | ||
| * | ||
@@ -62,4 +63,2 @@ * @param {Array<number>} dst - The destination array. | ||
| // fuzz-free, array-based Quaternion SLERP operation | ||
| let x0 = src0[ srcOffset0 + 0 ], | ||
@@ -70,3 +69,3 @@ y0 = src0[ srcOffset0 + 1 ], | ||
| const x1 = src1[ srcOffset1 + 0 ], | ||
| let x1 = src1[ srcOffset1 + 0 ], | ||
| y1 = src1[ srcOffset1 + 1 ], | ||
@@ -76,3 +75,3 @@ z1 = src1[ srcOffset1 + 2 ], | ||
| if ( t === 0 ) { | ||
| if ( t <= 0 ) { | ||
@@ -83,2 +82,3 @@ dst[ dstOffset + 0 ] = x0; | ||
| dst[ dstOffset + 3 ] = w0; | ||
| return; | ||
@@ -88,3 +88,3 @@ | ||
| if ( t === 1 ) { | ||
| if ( t >= 1 ) { | ||
@@ -95,2 +95,3 @@ dst[ dstOffset + 0 ] = x1; | ||
| dst[ dstOffset + 3 ] = w1; | ||
| return; | ||
@@ -102,28 +103,41 @@ | ||
| let s = 1 - t; | ||
| const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, | ||
| dir = ( cos >= 0 ? 1 : - 1 ), | ||
| sqrSin = 1 - cos * cos; | ||
| let dot = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1; | ||
| // Skip the Slerp for tiny steps to avoid numeric problems: | ||
| if ( sqrSin > Number.EPSILON ) { | ||
| if ( dot < 0 ) { | ||
| const sin = Math.sqrt( sqrSin ), | ||
| len = Math.atan2( sin, cos * dir ); | ||
| x1 = - x1; | ||
| y1 = - y1; | ||
| z1 = - z1; | ||
| w1 = - w1; | ||
| s = Math.sin( s * len ) / sin; | ||
| t = Math.sin( t * len ) / sin; | ||
| dot = - dot; | ||
| } | ||
| const tDir = t * dir; | ||
| let s = 1 - t; | ||
| x0 = x0 * s + x1 * tDir; | ||
| y0 = y0 * s + y1 * tDir; | ||
| z0 = z0 * s + z1 * tDir; | ||
| w0 = w0 * s + w1 * tDir; | ||
| if ( dot < 0.9995 ) { | ||
| // Normalize in case we just did a lerp: | ||
| if ( s === 1 - t ) { | ||
| // slerp | ||
| const theta = Math.acos( dot ); | ||
| const sin = Math.sin( theta ); | ||
| s = Math.sin( s * theta ) / sin; | ||
| t = Math.sin( t * theta ) / sin; | ||
| x0 = x0 * s + x1 * t; | ||
| y0 = y0 * s + y1 * t; | ||
| z0 = z0 * s + z1 * t; | ||
| w0 = w0 * s + w1 * t; | ||
| } else { | ||
| // for small angles, lerp then normalize | ||
| x0 = x0 * s + x1 * t; | ||
| y0 = y0 * s + y1 * t; | ||
| z0 = z0 * s + z1 * t; | ||
| w0 = w0 * s + w1 * t; | ||
| const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); | ||
@@ -381,3 +395,3 @@ | ||
| default: | ||
| console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order ); | ||
| warn( 'Quaternion: .setFromEuler() encountered an unknown order: ' + order ); | ||
@@ -738,65 +752,53 @@ } | ||
| if ( t === 0 ) return this; | ||
| if ( t === 1 ) return this.copy( qb ); | ||
| if ( t <= 0 ) return this; | ||
| const x = this._x, y = this._y, z = this._z, w = this._w; | ||
| if ( t >= 1 ) return this.copy( qb ); // copy calls _onChangeCallback() | ||
| // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ | ||
| let x = qb._x, y = qb._y, z = qb._z, w = qb._w; | ||
| let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; | ||
| let dot = this.dot( qb ); | ||
| if ( cosHalfTheta < 0 ) { | ||
| if ( dot < 0 ) { | ||
| this._w = - qb._w; | ||
| this._x = - qb._x; | ||
| this._y = - qb._y; | ||
| this._z = - qb._z; | ||
| x = - x; | ||
| y = - y; | ||
| z = - z; | ||
| w = - w; | ||
| cosHalfTheta = - cosHalfTheta; | ||
| dot = - dot; | ||
| } else { | ||
| } | ||
| this.copy( qb ); | ||
| let s = 1 - t; | ||
| } | ||
| if ( dot < 0.9995 ) { | ||
| if ( cosHalfTheta >= 1.0 ) { | ||
| // slerp | ||
| this._w = w; | ||
| this._x = x; | ||
| this._y = y; | ||
| this._z = z; | ||
| const theta = Math.acos( dot ); | ||
| const sin = Math.sin( theta ); | ||
| return this; | ||
| s = Math.sin( s * theta ) / sin; | ||
| t = Math.sin( t * theta ) / sin; | ||
| } | ||
| this._x = this._x * s + x * t; | ||
| this._y = this._y * s + y * t; | ||
| this._z = this._z * s + z * t; | ||
| this._w = this._w * s + w * t; | ||
| const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; | ||
| this._onChangeCallback(); | ||
| if ( sqrSinHalfTheta <= Number.EPSILON ) { | ||
| } else { | ||
| const s = 1 - t; | ||
| this._w = s * w + t * this._w; | ||
| this._x = s * x + t * this._x; | ||
| this._y = s * y + t * this._y; | ||
| this._z = s * z + t * this._z; | ||
| // for small angles, lerp then normalize | ||
| this._x = this._x * s + x * t; | ||
| this._y = this._y * s + y * t; | ||
| this._z = this._z * s + z * t; | ||
| this._w = this._w * s + w * t; | ||
| this.normalize(); // normalize calls _onChangeCallback() | ||
| return this; | ||
| } | ||
| const sinHalfTheta = Math.sqrt( sqrSinHalfTheta ); | ||
| const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); | ||
| const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, | ||
| ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; | ||
| this._w = ( w * ratioA + this._w * ratioB ); | ||
| this._x = ( x * ratioA + this._x * ratioB ); | ||
| this._y = ( y * ratioA + this._y * ratioB ); | ||
| this._z = ( z * ratioA + this._z * ratioB ); | ||
| this._onChangeCallback(); | ||
| return this; | ||
@@ -803,0 +805,0 @@ |
@@ -5,3 +5,3 @@ import { clamp } from './MathUtils.js'; | ||
| * This class can be used to represent points in 3D space as | ||
| * [Spherical coordinates]{@link https://en.wikipedia.org/wiki/Spherical_coordinate_system}. | ||
| * [Spherical coordinates](https://en.wikipedia.org/wiki/Spherical_coordinate_system). | ||
| */ | ||
@@ -8,0 +8,0 @@ class Spherical { |
@@ -9,2 +9,3 @@ import TextureNode from './TextureNode.js'; | ||
| import { CubeTexture } from '../../textures/CubeTexture.js'; | ||
| import { error } from '../../utils.js'; | ||
@@ -80,3 +81,3 @@ const EmptyTexture = /*@__PURE__*/ new CubeTexture(); | ||
| console.error( 'THREE.CubeTextureNode: Mapping "%s" not supported.', texture.mapping ); | ||
| error( 'CubeTextureNode: Mapping "%s" not supported.', texture.mapping ); | ||
@@ -128,3 +129,3 @@ return vec3( 0, 0, 0 ); | ||
| return cubeUV.build( builder, 'vec3' ); | ||
| return cubeUV.build( builder, this.sampler === true ? 'vec3' : 'ivec3' ); | ||
@@ -131,0 +132,0 @@ } |
@@ -198,12 +198,30 @@ import Node from '../core/Node.js'; | ||
| if ( this.instanceMatrix.usage !== DynamicDrawUsage && this.buffer !== null && this.instanceMatrix.version !== this.buffer.version ) { | ||
| if ( this.buffer !== null ) { | ||
| this.buffer.version = this.instanceMatrix.version; | ||
| // keep update ranges in sync | ||
| this.buffer.clearUpdateRanges(); | ||
| this.buffer.updateRanges.push( ... this.instanceMatrix.updateRanges ); | ||
| // update version if necessary | ||
| if ( this.instanceMatrix.usage !== DynamicDrawUsage && this.instanceMatrix.version !== this.buffer.version ) { | ||
| this.buffer.version = this.instanceMatrix.version; | ||
| } | ||
| } | ||
| if ( this.instanceColor && this.instanceColor.usage !== DynamicDrawUsage && this.bufferColor !== null && this.instanceColor.version !== this.bufferColor.version ) { | ||
| if ( this.instanceColor && this.bufferColor !== null ) { | ||
| this.bufferColor.version = this.instanceColor.version; | ||
| this.bufferColor.clearUpdateRanges(); | ||
| this.bufferColor.updateRanges.push( ... this.instanceColor.updateRanges ); | ||
| if ( this.instanceColor.usage !== DynamicDrawUsage && this.instanceColor.version !== this.bufferColor.version ) { | ||
| this.bufferColor.version = this.instanceColor.version; | ||
| } | ||
| } | ||
@@ -210,0 +228,0 @@ |
@@ -35,4 +35,14 @@ import { uniform } from '../core/UniformNode.js'; | ||
| // normally, shadow matrices are updated in ShadowNode. However, if the shadow matrix is used outside | ||
| // of shadow rendering (like in ProjectorLightNode), the shadow matrix still requires an update | ||
| if ( light.castShadow !== true || frame.renderer.shadowMap.enabled === false ) { | ||
| if ( light.shadow.camera.coordinateSystem !== frame.camera.coordinateSystem ) { | ||
| light.shadow.camera.coordinateSystem = frame.camera.coordinateSystem; | ||
| light.shadow.camera.updateProjectionMatrix(); | ||
| } | ||
| light.shadow.updateMatrices( light ); | ||
@@ -39,0 +49,0 @@ |
@@ -7,2 +7,3 @@ import { attribute } from '../core/AttributeNode.js'; | ||
| import { directionToFaceDirection } from '../display/FrontFacingNode.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -27,3 +28,3 @@ /** | ||
| console.warn( 'THREE.TSL: Vertex attribute "normal" not found on geometry.' ); | ||
| warn( 'TSL: Vertex attribute "normal" not found on geometry.' ); | ||
@@ -213,3 +214,3 @@ return vec3( 0, 1, 0 ); | ||
| console.warn( 'THREE.TSL: "transformedNormalView" is deprecated. Use "normalView" instead.' ); | ||
| warn( 'TSL: "transformedNormalView" is deprecated. Use "normalView" instead.' ); | ||
| return normalView; | ||
@@ -228,3 +229,3 @@ | ||
| console.warn( 'THREE.TSL: "transformedNormalWorld" is deprecated. Use "normalWorld" instead.' ); | ||
| warn( 'TSL: "transformedNormalWorld" is deprecated. Use "normalWorld" instead.' ); | ||
| return normalWorld; | ||
@@ -243,5 +244,5 @@ | ||
| console.warn( 'THREE.TSL: "transformedClearcoatNormalView" is deprecated. Use "clearcoatNormalView" instead.' ); | ||
| warn( 'TSL: "transformedClearcoatNormalView" is deprecated. Use "clearcoatNormalView" instead.' ); | ||
| return clearcoatNormalView; | ||
| } ).once( [ 'NORMAL', 'VERTEX' ] ) )(); |
| import { attribute } from '../core/AttributeNode.js'; | ||
| import { Fn } from '../tsl/TSLCore.js'; | ||
| import { Fn, vec3 } from '../tsl/TSLCore.js'; | ||
| import { modelWorldMatrix } from './ModelNode.js'; | ||
@@ -74,2 +74,18 @@ | ||
| */ | ||
| export const positionViewDirection = /*@__PURE__*/ positionView.negate().toVarying( 'v_positionViewDirection' ).normalize().toVar( 'positionViewDirection' ); | ||
| export const positionViewDirection = /*@__PURE__*/ ( Fn( ( builder ) => { | ||
| let output; | ||
| if ( builder.camera.isOrthographicCamera ) { | ||
| output = vec3( 0, 0, 1 ); | ||
| } else { | ||
| output = positionView.negate().toVarying( 'v_positionViewDirection' ).normalize(); | ||
| } | ||
| return output.toVar( 'positionViewDirection' ); | ||
| }, 'vec3' ).once( [ 'POSITION' ] ) )(); |
@@ -10,2 +10,3 @@ import Node from '../core/Node.js'; | ||
| import ArrayElementNode from '../utils/ArrayElementNode.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -242,3 +243,3 @@ // TODO: Avoid duplicated code and ues only ReferenceBaseNode or ReferenceNode | ||
| console.warn( 'THREE.TSL: "label()" has been deprecated. Use "setName()" instead.' ); // @deprecated r179 | ||
| warn( 'TSL: "label()" has been deprecated. Use "setName()" instead.' ); // @deprecated r179 | ||
@@ -245,0 +246,0 @@ return this.setName( name ); |
@@ -8,2 +8,3 @@ import { UVMapping } from '../../constants.js'; | ||
| import { reference } from './ReferenceNode.js'; | ||
| import { error } from '../../utils.js'; | ||
@@ -107,3 +108,3 @@ const _e1 = /*@__PURE__*/ new Euler(); | ||
| console.error( 'THREE.SceneNode: Unknown scope:', scope ); | ||
| error( 'SceneNode: Unknown scope:', scope ); | ||
@@ -110,0 +111,0 @@ } |
@@ -7,2 +7,3 @@ import BufferNode from './BufferNode.js'; | ||
| import { getTypeFromLength } from '../core/NodeUtils.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -412,3 +413,3 @@ /** | ||
| console.warn( 'THREE.TSL: "storageObject()" is deprecated. Use "storage().setPBO( true )" instead.' ); | ||
| warn( 'TSL: "storageObject()" is deprecated. Use "storage().setPBO( true )" instead.' ); | ||
@@ -415,0 +416,0 @@ return storage( value, type, count ).setPBO( true ); |
@@ -64,2 +64,10 @@ import TextureNode from './TextureNode.js'; | ||
| /** | ||
| * The mip level to write to for storage textures. | ||
| * | ||
| * @type {number} | ||
| * @default 0 | ||
| */ | ||
| this.mipLevel = 0; | ||
| /** | ||
| * This flag can be used for type testing. | ||
@@ -120,2 +128,15 @@ * | ||
| /** | ||
| * Sets the mip level to write to. | ||
| * | ||
| * @param {number} level - The mip level. | ||
| * @return {StorageTextureNode} A reference to this node. | ||
| */ | ||
| setMipLevel( level ) { | ||
| this.mipLevel = level; | ||
| return this; | ||
| } | ||
| /** | ||
| * Generates the code snippet of the storage node. If no `storeNode` | ||
@@ -205,2 +226,3 @@ * is defined, the texture node is generated as normal texture. | ||
| newNode.storeNode = this.storeNode; | ||
| newNode.mipLevel = this.mipLevel; | ||
| return newNode; | ||
@@ -207,0 +229,0 @@ |
@@ -156,3 +156,3 @@ import TextureNode from './TextureNode.js'; | ||
| return uvNode.build( builder, 'vec3' ); | ||
| return uvNode.build( builder, this.sampler === true ? 'vec3' : 'ivec3' ); | ||
@@ -159,0 +159,0 @@ } |
@@ -7,3 +7,3 @@ import UniformNode, { uniform } from '../core/UniformNode.js'; | ||
| import { maxMipLevel } from '../utils/MaxMipLevelNode.js'; | ||
| import { nodeProxy, vec3, nodeObject, int } from '../tsl/TSLBase.js'; | ||
| import { nodeProxy, vec3, nodeObject, int, Fn } from '../tsl/TSLBase.js'; | ||
| import { NodeUpdateType } from '../core/constants.js'; | ||
@@ -14,2 +14,3 @@ | ||
| import { Texture } from '../../textures/Texture.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -128,5 +129,5 @@ const EmptyTexture = /*@__PURE__*/ new Texture(); | ||
| /** | ||
| * By default the `update()` method is not executed. `setUpdateMatrix()` | ||
| * sets the value to `frame` when the uv transformation matrix should | ||
| * automatically be updated. | ||
| * By default the `update()` method is not executed. Depending on | ||
| * whether a uv transformation matrix and/or flipY is applied, `update()` | ||
| * is executed per object. | ||
| * | ||
@@ -159,5 +160,15 @@ * @type {string} | ||
| * @type {?UniformNode<mat3>} | ||
| * @default null | ||
| */ | ||
| this._matrixUniform = null; | ||
| /** | ||
| * The uniform node that represents the y-flip. Only required for WebGL. | ||
| * | ||
| * @private | ||
| * @type {?UniformNode<bool>} | ||
| * @default null | ||
| */ | ||
| this._flipYUniform = null; | ||
| this.setUpdateMatrix( uvNode === null ); | ||
@@ -286,3 +297,2 @@ | ||
| this.updateMatrix = value; | ||
| this.updateType = value ? NodeUpdateType.OBJECT : NodeUpdateType.NONE; | ||
@@ -303,13 +313,15 @@ return this; | ||
| const texture = this.value; | ||
| if ( builder.isFlipY() ) { | ||
| if ( builder.isFlipY() && ( ( texture.image instanceof ImageBitmap && texture.flipY === true ) || texture.isRenderTargetTexture === true || texture.isFramebufferTexture === true || texture.isDepthTexture === true ) ) { | ||
| if ( this._flipYUniform === null ) this._flipYUniform = uniform( false ); | ||
| uvNode = uvNode.toVar(); | ||
| if ( this.sampler ) { | ||
| uvNode = uvNode.flipY(); | ||
| uvNode = this._flipYUniform.select( uvNode.flipY(), uvNode ); | ||
| } else { | ||
| uvNode = uvNode.setY( int( textureSize( this, this.levelNode ).y ).sub( uvNode.y ).sub( 1 ) ); | ||
| uvNode = this._flipYUniform.select( uvNode.setY( int( textureSize( this, this.levelNode ).y ).sub( uvNode.y ).sub( 1 ) ), uvNode ); | ||
@@ -346,20 +358,32 @@ } | ||
| let uvNode = this.uvNode; | ||
| const uvNode = Fn( () => { | ||
| if ( ( uvNode === null || builder.context.forceUVContext === true ) && builder.context.getUV ) { | ||
| let uvNode = this.uvNode; | ||
| uvNode = builder.context.getUV( this, builder ); | ||
| if ( ( uvNode === null || builder.context.forceUVContext === true ) && builder.context.getUV ) { | ||
| } | ||
| uvNode = builder.context.getUV( this, builder ); | ||
| if ( ! uvNode ) uvNode = this.getDefaultUV(); | ||
| } | ||
| if ( this.updateMatrix === true ) { | ||
| if ( ! uvNode ) uvNode = this.getDefaultUV(); | ||
| uvNode = this.getTransformedUV( uvNode ); | ||
| if ( this.updateMatrix === true ) { | ||
| } | ||
| uvNode = this.getTransformedUV( uvNode ); | ||
| uvNode = this.setupUV( builder, uvNode ); | ||
| } | ||
| uvNode = this.setupUV( builder, uvNode ); | ||
| // | ||
| this.updateType = ( this._matrixUniform !== null || this._flipYUniform !== null ) ? NodeUpdateType.OBJECT : NodeUpdateType.NONE; | ||
| // | ||
| return uvNode; | ||
| } )(); | ||
| // | ||
@@ -433,8 +457,4 @@ | ||
| if ( levelSnippet ) { | ||
| if ( biasSnippet ) { | ||
| snippet = builder.generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, offsetSnippet ); | ||
| } else if ( biasSnippet ) { | ||
| snippet = builder.generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet, depthSnippet, offsetSnippet ); | ||
@@ -452,4 +472,8 @@ | ||
| snippet = builder.generateTextureLoad( texture, textureProperty, uvSnippet, depthSnippet, offsetSnippet ); | ||
| snippet = builder.generateTextureLoad( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, offsetSnippet ); | ||
| } else if ( levelSnippet ) { | ||
| snippet = builder.generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, offsetSnippet ); | ||
| } else { | ||
@@ -569,3 +593,3 @@ | ||
| console.warn( 'THREE.TextureNode: .uv() has been renamed. Use .sample() instead.' ); | ||
| warn( 'TextureNode: .uv() has been renamed. Use .sample() instead.' ); | ||
@@ -620,3 +644,3 @@ return this.sample( uvNode ); | ||
| console.warn( 'THREE.TSL: texture().blur() requires mipmaps and sampling. Use .generateMipmaps=true and .minFilter/.magFilter=THREE.LinearFilter in the Texture.' ); | ||
| warn( 'TSL: texture().blur() requires mipmaps and sampling. Use .generateMipmaps=true and .minFilter/.magFilter=THREE.LinearFilter in the Texture.' ); | ||
@@ -790,2 +814,12 @@ textureNode.biasNode = null; | ||
| // | ||
| const flipYUniform = this._flipYUniform; | ||
| if ( flipYUniform !== null ) { | ||
| flipYUniform.value = ( ( texture.image instanceof ImageBitmap && texture.flipY === true ) || texture.isRenderTargetTexture === true || texture.isFramebufferTexture === true || texture.isDepthTexture === true ); | ||
| } | ||
| } | ||
@@ -885,3 +919,3 @@ | ||
| //export const textureLevel = ( value, uv, level ) => texture( value, uv ).level( level ); | ||
| export const textureLevel = ( value, uv, level ) => texture( value, uv ).level( level ); | ||
@@ -888,0 +922,0 @@ /** |
| import TempNode from '../core/TempNode.js'; | ||
| import { addMethodChaining, nodeArray, nodeObject, nodeObjects, float } from '../tsl/TSLCore.js'; | ||
| import { error } from '../../utils.js'; | ||
@@ -124,3 +125,3 @@ /** | ||
| console.error( 'THREE.TSL: The number of provided parameters exceeds the expected number of inputs in \'Fn()\'.' ); | ||
| error( 'TSL: The number of provided parameters exceeds the expected number of inputs in \'Fn()\'.' ); | ||
@@ -131,3 +132,3 @@ parameters.length = inputs.length; | ||
| console.error( 'THREE.TSL: The number of provided parameters is less than the expected number of inputs in \'Fn()\'.' ); | ||
| error( 'TSL: The number of provided parameters is less than the expected number of inputs in \'Fn()\'.' ); | ||
@@ -160,3 +161,3 @@ while ( parameters.length < inputs.length ) { | ||
| console.error( `THREE.TSL: Input '${ inputNode.name }' not found in \'Fn()\'.` ); | ||
| error( `TSL: Input '${ inputNode.name }' not found in \'Fn()\'.` ); | ||
@@ -185,3 +186,3 @@ params.push( generateInput( float( 0 ), inputNode ) ); | ||
| return nodeObject( new FunctionCallNode( nodeObject( func ), params ) ); | ||
| return new FunctionCallNode( nodeObject( func ), params ); | ||
@@ -188,0 +189,0 @@ }; |
@@ -14,2 +14,3 @@ import TempNode from './TempNode.js'; | ||
| * const redColor = tintColors.element( 0 ); | ||
| * ``` | ||
| * | ||
@@ -16,0 +17,0 @@ * @augments TempNode |
| import Node from './Node.js'; | ||
| import { nodeObject, varying } from '../tsl/TSLBase.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -128,3 +129,3 @@ /** | ||
| console.warn( `AttributeNode: Vertex attribute "${ attributeName }" not found on geometry.` ); | ||
| warn( `AttributeNode: Vertex attribute "${ attributeName }" not found on geometry.` ); | ||
@@ -131,0 +132,0 @@ return builder.generateConst( nodeType ); |
| import Node from './Node.js'; | ||
| import { addMethodChaining, nodeProxy } from '../tsl/TSLCore.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -96,6 +97,4 @@ /** | ||
| const previousContext = builder.getContext(); | ||
| const previousContext = builder.addContext( this.value ); | ||
| builder.setContext( { ...builder.context, ...this.value } ); | ||
| this.node.build( builder ); | ||
@@ -109,6 +108,4 @@ | ||
| const previousContext = builder.getContext(); | ||
| const previousContext = builder.addContext( this.value ); | ||
| builder.setContext( { ...builder.context, ...this.value } ); | ||
| this.node.build( builder ); | ||
@@ -122,6 +119,4 @@ | ||
| const previousContext = builder.getContext(); | ||
| const previousContext = builder.addContext( this.value ); | ||
| builder.setContext( { ...builder.context, ...this.value } ); | ||
| const snippet = this.node.build( builder, output ); | ||
@@ -183,3 +178,3 @@ | ||
| console.warn( 'THREE.TSL: "label()" has been deprecated. Use "setName()" instead.' ); // @deprecated r179 | ||
| warn( 'TSL: "label()" has been deprecated. Use "setName()" instead.' ); // @deprecated r179 | ||
@@ -186,0 +181,0 @@ return setName( node, name ); |
@@ -13,3 +13,3 @@ import Node from './Node.js'; | ||
| * - `invocationSubgroupIndex`: The index of a compute invocation within the scope of a subgroup. | ||
| * - `subgroupIndex`: The index of the subgroup the current compute invocation belongs to. | ||
| * - `subgroupIndex`: The index of a compute invocation's subgroup within its workgroup. | ||
| * | ||
@@ -29,3 +29,3 @@ * @augments Node | ||
| * | ||
| * @param {('vertex'|'instance'|'subgroup'|'invocationLocal'|'invocationSubgroup'|'draw')} scope - The scope of the index node. | ||
| * @param {('vertex'|'instance'|'subgroup'|'invocationLocal'|'invocationGlobal'|'invocationSubgroup'|'draw')} scope - The scope of the index node. | ||
| */ | ||
@@ -32,0 +32,0 @@ constructor( scope ) { |
| import Node from './Node.js'; | ||
| import { getValueType, getValueFromType, arrayBufferToBase64 } from './NodeUtils.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -129,3 +130,3 @@ /** | ||
| console.warn( 'Abstract function.' ); | ||
| warn( 'Abstract function.' ); | ||
@@ -132,0 +133,0 @@ } |
+137
-12
| import { NodeUpdateType } from './constants.js'; | ||
| import { getNodeChildren, getCacheKey, hash } from './NodeUtils.js'; | ||
| import { hash, hashArray, hashString } from './NodeUtils.js'; | ||
| import { EventDispatcher } from '../../core/EventDispatcher.js'; | ||
| import { MathUtils } from '../../math/MathUtils.js'; | ||
| import { warn, error } from '../../utils.js'; | ||
@@ -86,2 +87,10 @@ const _parentBuildStage = { | ||
| /** | ||
| * The name of the node. | ||
| * | ||
| * @type {string} | ||
| * @default '' | ||
| */ | ||
| this.name = ''; | ||
| /** | ||
| * Whether this node is global or not. This property is relevant for the internal | ||
@@ -115,2 +124,4 @@ * node caching system. All nodes which should be declared just once should | ||
| this._beforeNodes = null; | ||
| /** | ||
@@ -271,3 +282,3 @@ * The cache key of this node. | ||
| for ( const { childNode } of getNodeChildren( this ) ) { | ||
| for ( const { childNode } of this._getChildren() ) { | ||
@@ -315,8 +326,75 @@ yield childNode; | ||
| /** | ||
| * Returns the child nodes of this node. | ||
| * | ||
| * @private | ||
| * @param {Set<Node>} [ignores=new Set()] - A set of nodes to ignore during the search to avoid circular references. | ||
| * @returns {Array<Object>} An array of objects describing the child nodes. | ||
| */ | ||
| _getChildren( ignores = new Set() ) { | ||
| const children = []; | ||
| // avoid circular references | ||
| ignores.add( this ); | ||
| for ( const property of Object.getOwnPropertyNames( this ) ) { | ||
| const object = this[ property ]; | ||
| // Ignore private properties and ignored nodes. | ||
| if ( property.startsWith( '_' ) === true || ignores.has( object ) ) continue; | ||
| if ( Array.isArray( object ) === true ) { | ||
| for ( let i = 0; i < object.length; i ++ ) { | ||
| const child = object[ i ]; | ||
| if ( child && child.isNode === true ) { | ||
| children.push( { property, index: i, childNode: child } ); | ||
| } | ||
| } | ||
| } else if ( object && object.isNode === true ) { | ||
| children.push( { property, childNode: object } ); | ||
| } else if ( object && Object.getPrototypeOf( object ) === Object.prototype ) { | ||
| for ( const subProperty in object ) { | ||
| // Ignore private sub-properties. | ||
| if ( subProperty.startsWith( '_' ) === true ) continue; | ||
| const child = object[ subProperty ]; | ||
| if ( child && child.isNode === true ) { | ||
| children.push( { property, index: subProperty, childNode: child } ); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| // | ||
| return children; | ||
| } | ||
| /** | ||
| * Returns the cache key for this node. | ||
| * | ||
| * @param {boolean} [force=false] - When set to `true`, a recomputation of the cache key is forced. | ||
| * @param {Set<Node>} [ignores=null] - A set of nodes to ignore during the computation of the cache key. | ||
| * @return {number} The cache key of the node. | ||
| */ | ||
| getCacheKey( force = false ) { | ||
| getCacheKey( force = false, ignores = null ) { | ||
@@ -327,3 +405,17 @@ force = force || this.version !== this._cacheKeyVersion; | ||
| this._cacheKey = hash( getCacheKey( this, force ), this.customCacheKey() ); | ||
| if ( ignores === null ) ignores = new Set(); | ||
| // | ||
| const values = []; | ||
| for ( const { property, childNode } of this._getChildren( ignores ) ) { | ||
| values.push( hashString( property.slice( 0, - 4 ) ), childNode.getCacheKey( force, ignores ) ); | ||
| } | ||
| // | ||
| this._cacheKey = hash( hashArray( values ), this.customCacheKey() ); | ||
| this._cacheKeyVersion = this.version; | ||
@@ -344,3 +436,3 @@ | ||
| return 0; | ||
| return this.id; | ||
@@ -583,3 +675,3 @@ } | ||
| console.warn( 'Abstract function.' ); | ||
| warn( 'Abstract function.' ); | ||
@@ -598,3 +690,3 @@ } | ||
| console.warn( 'Abstract function.' ); | ||
| warn( 'Abstract function.' ); | ||
@@ -613,6 +705,16 @@ } | ||
| console.warn( 'Abstract function.' ); | ||
| warn( 'Abstract function.' ); | ||
| } | ||
| before( node ) { | ||
| if ( this._beforeNodes === null ) this._beforeNodes = []; | ||
| this._beforeNodes.push( node ); | ||
| return this; | ||
| } | ||
| /** | ||
@@ -640,2 +742,20 @@ * This method performs the build of a node. The behavior and return value depend on the current build stage: | ||
| if ( this._beforeNodes !== null ) { | ||
| const currentBeforeNodes = this._beforeNodes; | ||
| this._beforeNodes = null; | ||
| for ( const beforeNode of currentBeforeNodes ) { | ||
| beforeNode.build( builder, output ); | ||
| } | ||
| this._beforeNodes = currentBeforeNodes; | ||
| } | ||
| // | ||
| const nodeData = builder.getDataFromNode( this ); | ||
@@ -723,4 +843,9 @@ nodeData.buildStages = nodeData.buildStages || {}; | ||
| const isGenerateOnce = this.generate.length === 1; | ||
| // If generate has just one argument, it means the output type is not required. | ||
| // This means that the node does not handle output conversions internally, | ||
| // so the value is stored in a cache and the builder handles the conversion | ||
| // for all requested output types. | ||
| const isGenerateOnce = this.generate.length < 2; | ||
| if ( isGenerateOnce ) { | ||
@@ -745,3 +870,3 @@ | ||
| console.warn( 'THREE.Node: Recursion detected.', this ); | ||
| warn( 'Node: Recursion detected.', this ); | ||
@@ -770,3 +895,3 @@ result = '/* Recursion detected. */'; | ||
| console.error( `THREE.TSL: Invalid generated code, expected a "${ output }".` ); | ||
| error( `TSL: Invalid generated code, expected a "${ output }".` ); | ||
@@ -793,3 +918,3 @@ result = builder.generateConst( output ); | ||
| return getNodeChildren( this ); | ||
| return this._getChildren(); | ||
@@ -796,0 +921,0 @@ } |
@@ -127,4 +127,4 @@ import { NodeUpdateType } from './constants.js'; | ||
| maps = { | ||
| renderMap: new WeakMap(), | ||
| frameMap: new WeakMap() | ||
| renderId: 0, | ||
| frameId: 0, | ||
| }; | ||
@@ -155,9 +155,9 @@ | ||
| const { frameMap } = this._getMaps( this.updateBeforeMap, reference ); | ||
| const nodeUpdateBeforeMap = this._getMaps( this.updateBeforeMap, reference ); | ||
| if ( frameMap.get( reference ) !== this.frameId ) { | ||
| if ( nodeUpdateBeforeMap.frameId !== this.frameId ) { | ||
| if ( node.updateBefore( this ) !== false ) { | ||
| frameMap.set( reference, this.frameId ); | ||
| nodeUpdateBeforeMap.frameId = this.frameId; | ||
@@ -170,9 +170,9 @@ } | ||
| const { renderMap } = this._getMaps( this.updateBeforeMap, reference ); | ||
| const nodeUpdateBeforeMap = this._getMaps( this.updateBeforeMap, reference ); | ||
| if ( renderMap.get( reference ) !== this.renderId ) { | ||
| if ( nodeUpdateBeforeMap.renderId !== this.renderId ) { | ||
| if ( node.updateBefore( this ) !== false ) { | ||
| renderMap.set( reference, this.renderId ); | ||
| nodeUpdateBeforeMap.renderId = this.renderId; | ||
@@ -206,9 +206,9 @@ } | ||
| const { frameMap } = this._getMaps( this.updateAfterMap, reference ); | ||
| const nodeUpdateAfterMap = this._getMaps( this.updateAfterMap, reference ); | ||
| if ( frameMap.get( reference ) !== this.frameId ) { | ||
| if ( nodeUpdateAfterMap.frameId !== this.frameId ) { | ||
| if ( node.updateAfter( this ) !== false ) { | ||
| frameMap.set( reference, this.frameId ); | ||
| nodeUpdateAfterMap.frameId = this.frameId; | ||
@@ -221,9 +221,9 @@ } | ||
| const { renderMap } = this._getMaps( this.updateAfterMap, reference ); | ||
| const nodeUpdateAfterMap = this._getMaps( this.updateAfterMap, reference ); | ||
| if ( renderMap.get( reference ) !== this.renderId ) { | ||
| if ( nodeUpdateAfterMap.renderId !== this.renderId ) { | ||
| if ( node.updateAfter( this ) !== false ) { | ||
| renderMap.set( reference, this.renderId ); | ||
| nodeUpdateAfterMap.renderId = this.renderId; | ||
@@ -257,9 +257,9 @@ } | ||
| const { frameMap } = this._getMaps( this.updateMap, reference ); | ||
| const nodeUpdateMap = this._getMaps( this.updateMap, reference ); | ||
| if ( frameMap.get( reference ) !== this.frameId ) { | ||
| if ( nodeUpdateMap.frameId !== this.frameId ) { | ||
| if ( node.update( this ) !== false ) { | ||
| frameMap.set( reference, this.frameId ); | ||
| nodeUpdateMap.frameId = this.frameId; | ||
@@ -272,9 +272,9 @@ } | ||
| const { renderMap } = this._getMaps( this.updateMap, reference ); | ||
| const nodeUpdateMap = this._getMaps( this.updateMap, reference ); | ||
| if ( renderMap.get( reference ) !== this.renderId ) { | ||
| if ( nodeUpdateMap.renderId !== this.renderId ) { | ||
| if ( node.update( this ) !== false ) { | ||
| renderMap.set( reference, this.renderId ); | ||
| nodeUpdateMap.renderId = this.renderId; | ||
@@ -281,0 +281,0 @@ } |
@@ -0,1 +1,2 @@ | ||
| import { warn } from '../../utils.js'; | ||
| /** | ||
@@ -60,3 +61,3 @@ * Base class for node functions. A derived module must be implemented | ||
| console.warn( 'Abstract function.' ); | ||
| warn( 'Abstract function.' ); | ||
@@ -63,0 +64,0 @@ } |
@@ -0,1 +1,2 @@ | ||
| import { warn } from '../../utils.js'; | ||
| /** | ||
@@ -16,3 +17,3 @@ * Base class for node parsers. A derived parser must be implemented | ||
| console.warn( 'Abstract function.' ); | ||
| warn( 'Abstract function.' ); | ||
@@ -19,0 +20,0 @@ } |
@@ -8,2 +8,3 @@ import { Color } from '../../math/Color.js'; | ||
| import { Vector4 } from '../../math/Vector4.js'; | ||
| import { error } from '../../utils.js'; | ||
@@ -53,2 +54,3 @@ // cyrb53 (c) 2018 bryc (github.com/bryc). License: Public domain. Attribution appreciated. | ||
| * | ||
| * @private | ||
| * @method | ||
@@ -63,2 +65,3 @@ * @param {string} str - The string to be hashed. | ||
| * | ||
| * @private | ||
| * @method | ||
@@ -73,2 +76,3 @@ * @param {Array<number>} array - The array to be hashed. | ||
| * | ||
| * @private | ||
| * @method | ||
@@ -80,89 +84,2 @@ * @param {...number} params - A list of parameters. | ||
| /** | ||
| * Computes a cache key for the given node. | ||
| * | ||
| * @method | ||
| * @param {Object|Node} object - The object to be hashed. | ||
| * @param {boolean} [force=false] - Whether to force a cache key computation or not. | ||
| * @return {number} The hash. | ||
| */ | ||
| export function getCacheKey( object, force = false ) { | ||
| const values = []; | ||
| if ( object.isNode === true ) { | ||
| values.push( object.id ); | ||
| } | ||
| for ( const { property, childNode } of getNodeChildren( object ) ) { | ||
| values.push( cyrb53( property.slice( 0, - 4 ) ), childNode.getCacheKey( force ) ); | ||
| } | ||
| return cyrb53( values ); | ||
| } | ||
| /** | ||
| * This generator function can be used to iterate over the node children | ||
| * of the given object. | ||
| * | ||
| * @generator | ||
| * @param {Object} node - The object to be hashed. | ||
| * @param {boolean} [toJSON=false] - Whether to return JSON or not. | ||
| * @yields {Object} A result node holding the property, index (if available) and the child node. | ||
| */ | ||
| export function* getNodeChildren( node, toJSON = false ) { | ||
| for ( const property of Object.getOwnPropertyNames( node ) ) { | ||
| // Ignore private properties. | ||
| if ( property.startsWith( '_' ) === true ) continue; | ||
| const object = node[ property ]; | ||
| if ( Array.isArray( object ) === true ) { | ||
| for ( let i = 0; i < object.length; i ++ ) { | ||
| const child = object[ i ]; | ||
| if ( child && ( child.isNode === true || toJSON && typeof child.toJSON === 'function' ) ) { | ||
| yield { property, index: i, childNode: child }; | ||
| } | ||
| } | ||
| } else if ( object && object.isNode === true ) { | ||
| yield { property, childNode: object }; | ||
| } else if ( object && Object.getPrototypeOf( object ) === Object.prototype ) { | ||
| for ( const subProperty in object ) { | ||
| // Ignore private properties. | ||
| if ( subProperty.startsWith( '_' ) === true ) continue; | ||
| const child = object[ subProperty ]; | ||
| if ( child && ( child.isNode === true || toJSON && typeof child.toJSON === 'function' ) ) { | ||
| yield { property, index: subProperty, childNode: child }; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| const typeFromLength = /*@__PURE__*/ new Map( [ | ||
@@ -182,2 +99,3 @@ [ 1, 'float' ], | ||
| * | ||
| * @private | ||
| * @method | ||
@@ -196,2 +114,3 @@ * @param {number} length - The length. | ||
| * | ||
| * @private | ||
| * @method | ||
@@ -230,2 +149,3 @@ * @param {string} type - The data type. | ||
| * | ||
| * @private | ||
| * @method | ||
@@ -245,3 +165,3 @@ * @param {string} type - The data type. | ||
| console.error( 'THREE.TSL: Unsupported type:', type ); | ||
| error( 'TSL: Unsupported type:', type ); | ||
@@ -253,2 +173,3 @@ } | ||
| * | ||
| * @private | ||
| * @method | ||
@@ -268,3 +189,3 @@ * @param {string} type - The data type. | ||
| console.error( 'THREE.TSL: Unsupported type:', type ); | ||
| error( 'TSL: Unsupported type:', type ); | ||
@@ -276,2 +197,3 @@ } | ||
| * | ||
| * @private | ||
| * @method | ||
@@ -291,3 +213,3 @@ * @param {string} type - The data type. | ||
| console.error( 'THREE.TSL: Unsupported type:', type ); | ||
| error( 'TSL: Unsupported type:', type ); | ||
@@ -299,2 +221,3 @@ } | ||
| * | ||
| * @private | ||
| * @method | ||
@@ -371,2 +294,3 @@ * @param {any} value - The value. | ||
| * | ||
| * @private | ||
| * @method | ||
@@ -442,2 +366,3 @@ * @param {string} type - The given type. | ||
| * | ||
| * @private | ||
| * @param {Object} object - The object to get the data for. | ||
@@ -464,2 +389,3 @@ * @return {Object} The object data. | ||
| * | ||
| * @private | ||
| * @method | ||
@@ -488,2 +414,3 @@ * @param {ArrayBuffer} arrayBuffer - The array buffer. | ||
| * | ||
| * @private | ||
| * @method | ||
@@ -490,0 +417,0 @@ * @param {string} base64 - The Base64 string. |
| import { nodeObject } from '../tsl/TSLBase.js'; | ||
| import { error } from '../../utils.js'; | ||
| import PropertyNode from './PropertyNode.js'; | ||
@@ -38,2 +39,32 @@ | ||
| /** | ||
| * Gets the type of a member variable in the parameter node. | ||
| * | ||
| * @param {NodeBuilder} builder - The node builder. | ||
| * @param {string} name - The name of the member variable. | ||
| * @returns {string} | ||
| */ | ||
| getMemberType( builder, name ) { | ||
| const type = this.getNodeType( builder ); | ||
| const struct = builder.getStructTypeNode( type ); | ||
| let memberType; | ||
| if ( struct !== null ) { | ||
| memberType = struct.getMemberType( builder, name ); | ||
| } else { | ||
| error( `TSL: Member "${ name }" not found in struct "${ type }".` ); | ||
| memberType = 'float'; | ||
| } | ||
| return memberType; | ||
| } | ||
| getHash() { | ||
@@ -40,0 +71,0 @@ |
| import Node from './Node.js'; | ||
| import { nodeImmutable, nodeObject } from '../tsl/TSLCore.js'; | ||
| import { hashString } from './NodeUtils.js'; | ||
@@ -71,2 +72,8 @@ /** | ||
| customCacheKey() { | ||
| return hashString( this.type + ':' + ( this.name || '' ) + ':' + ( this.varying ? '1' : '0' ) ); | ||
| } | ||
| getHash( builder ) { | ||
@@ -73,0 +80,0 @@ |
| import Node from './Node.js'; | ||
| import { select } from '../math/ConditionalNode.js'; | ||
| import { ShaderNode, nodeProxy, getCurrentStack, setCurrentStack, nodeObject } from '../tsl/TSLBase.js'; | ||
| import { error } from '../../utils.js'; | ||
@@ -81,2 +82,8 @@ /** | ||
| getElementType( builder ) { | ||
| return this.hasOutput ? this.outputNode.getElementType( builder ) : 'void'; | ||
| } | ||
| getNodeType( builder ) { | ||
@@ -100,7 +107,7 @@ | ||
| */ | ||
| add( node ) { | ||
| addToStack( node ) { | ||
| if ( node.isNode !== true ) { | ||
| console.error( 'THREE.TSL: Invalid node added to stack.' ); | ||
| error( 'TSL: Invalid node added to stack.' ); | ||
| return this; | ||
@@ -128,3 +135,3 @@ | ||
| return this.add( this._currentCond ); | ||
| return this.addToStack( this._currentCond ); | ||
@@ -204,3 +211,3 @@ } | ||
| console.error( 'THREE.TSL: Invalid parameter length. Case() requires at least two parameters.' ); | ||
| error( 'TSL: Invalid parameter length. Case() requires at least two parameters.' ); | ||
@@ -232,3 +239,3 @@ } | ||
| return this.add( this._currentCond ); | ||
| return this.addToStack( this._currentCond ); | ||
@@ -270,6 +277,4 @@ } else { | ||
| const properties = builder.getNodeProperties( childNode ); | ||
| if ( childNode.isAssign( builder ) !== true ) { | ||
| if ( properties.assign !== true ) { | ||
| continue; | ||
@@ -299,3 +304,2 @@ | ||
| const previousBuildStack = builder.currentStack; | ||
| const previousStack = getCurrentStack(); | ||
@@ -305,3 +309,3 @@ | ||
| builder.currentStack = this; | ||
| builder.setActiveStack( this ); | ||
@@ -314,6 +318,4 @@ const buildStage = builder.buildStage; | ||
| const properties = builder.getNodeProperties( node ); | ||
| if ( node.isAssign( builder ) !== true ) { | ||
| if ( properties.assign !== true ) { | ||
| continue; | ||
@@ -366,3 +368,3 @@ | ||
| builder.currentStack = previousBuildStack; | ||
| builder.removeActiveStack( this ); | ||
@@ -369,0 +371,0 @@ return result; |
@@ -5,2 +5,3 @@ import InputNode from './InputNode.js'; | ||
| import { getValueFromType } from './NodeUtils.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -81,3 +82,3 @@ /** | ||
| console.warn( 'THREE.TSL: "label()" has been deprecated. Use "setName()" instead.' ); // @deprecated r179 | ||
| warn( 'TSL: "label()" has been deprecated. Use "setName()" instead.' ); // @deprecated r179 | ||
@@ -84,0 +85,0 @@ return this.setName( name ); |
| import Node from './Node.js'; | ||
| import { addMethodChaining, getCurrentStack, nodeProxy } from '../tsl/TSLCore.js'; | ||
| import { addMethodChaining, nodeProxy } from '../tsl/TSLCore.js'; | ||
| import { error } from '../../utils.js'; | ||
@@ -149,11 +150,50 @@ /** | ||
| isAssign( builder ) { | ||
| const properties = builder.getNodeProperties( this ); | ||
| let assign = properties.assign; | ||
| if ( assign !== true ) { | ||
| if ( this.node.isShaderCallNodeInternal && this.node.shaderNode.getLayout() === null ) { | ||
| if ( builder.fnCall && builder.fnCall.shaderNode ) { | ||
| const shaderNodeData = builder.getDataFromNode( this.node.shaderNode ); | ||
| if ( shaderNodeData.hasLoop ) { | ||
| assign = true; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return assign; | ||
| } | ||
| build( ...params ) { | ||
| const builder = params[ 0 ]; | ||
| if ( this._hasStack( builder ) === false && builder.buildStage === 'setup' ) { | ||
| if ( builder.context.nodeLoop || builder.context.nodeBlock ) { | ||
| builder.getBaseStack().addToStack( this ); | ||
| } | ||
| } | ||
| if ( this.intent === true ) { | ||
| const builder = params[ 0 ]; | ||
| const properties = builder.getNodeProperties( this ); | ||
| if ( this.isAssign( builder ) !== true ) { | ||
| if ( properties.assign !== true ) { | ||
| return this.node.build( ...params ); | ||
@@ -187,3 +227,19 @@ | ||
| const vectorType = builder.getVectorType( this.getNodeType( builder ) ); | ||
| const nodeType = this.getNodeType( builder ); | ||
| if ( nodeType == 'void' ) { | ||
| if ( this.intent !== true ) { | ||
| error( 'TSL: ".toVar()" can not be used with void type.' ); | ||
| } | ||
| const snippet = node.build( builder ); | ||
| return snippet; | ||
| } | ||
| const vectorType = builder.getVectorType( nodeType ); | ||
| const snippet = node.build( builder, vectorType ); | ||
@@ -221,2 +277,10 @@ | ||
| _hasStack( builder ) { | ||
| const nodeData = builder.getDataFromNode( this ); | ||
| return nodeData.stack !== undefined; | ||
| } | ||
| } | ||
@@ -273,8 +337,2 @@ | ||
| if ( getCurrentStack() === null ) { | ||
| return node; | ||
| } | ||
| return createVar( node ).setIntent( true ).toStack(); | ||
@@ -281,0 +339,0 @@ |
@@ -5,2 +5,3 @@ import Node from './Node.js'; | ||
| import { subBuild } from './SubBuildNode.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -217,3 +218,3 @@ /** | ||
| console.warn( 'THREE.TSL: .varying() has been renamed to .toVarying().' ); | ||
| warn( 'TSL: .varying() has been renamed to .toVarying().' ); | ||
| return varying( ...params ); | ||
@@ -225,5 +226,5 @@ | ||
| console.warn( 'THREE.TSL: .vertexStage() has been renamed to .toVertexStage().' ); | ||
| warn( 'TSL: .vertexStage() has been renamed to .toVertexStage().' ); | ||
| return varying( ...params ); | ||
| } ); |
| import { Fn, If, vec4 } from '../tsl/TSLBase.js'; | ||
| import { mix, min, step } from '../math/MathNode.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -186,3 +187,3 @@ /** | ||
| console.warn( 'THREE.TSL: "burn" has been renamed. Use "blendBurn" instead.' ); | ||
| warn( 'TSL: "burn" has been renamed. Use "blendBurn" instead.' ); | ||
| return blendBurn( params ); | ||
@@ -202,3 +203,3 @@ | ||
| console.warn( 'THREE.TSL: "dodge" has been renamed. Use "blendDodge" instead.' ); | ||
| warn( 'TSL: "dodge" has been renamed. Use "blendDodge" instead.' ); | ||
| return blendDodge( params ); | ||
@@ -218,3 +219,3 @@ | ||
| console.warn( 'THREE.TSL: "screen" has been renamed. Use "blendScreen" instead.' ); | ||
| warn( 'TSL: "screen" has been renamed. Use "blendScreen" instead.' ); | ||
| return blendScreen( params ); | ||
@@ -234,5 +235,5 @@ | ||
| console.warn( 'THREE.TSL: "overlay" has been renamed. Use "blendOverlay" instead.' ); | ||
| warn( 'TSL: "overlay" has been renamed. Use "blendOverlay" instead.' ); | ||
| return blendOverlay( params ); | ||
| }; |
@@ -14,3 +14,3 @@ import TempNode from '../core/TempNode.js'; | ||
| // It's used to preserve the same TextureNode instance | ||
| const sampleTexture = ( callback ) => textureNode.cache().context( { getUV: ( texNode ) => callback( texNode.uvNode || uv() ), forceUVContext: true } ); | ||
| const sampleTexture = ( callback ) => textureNode.isolate().context( { getUV: ( texNode ) => callback( texNode.uvNode || uv() ), forceUVContext: true } ); | ||
@@ -17,0 +17,0 @@ const Hll = float( sampleTexture( ( uvNode ) => uvNode ) ); |
@@ -85,3 +85,3 @@ import { dot, max, mix } from '../math/MathNode.js'; | ||
| * @param {?Node<vec3>} luminanceCoefficients - The luminance coefficients. By default predefined values of the current working color space are used. | ||
| * @return {Node<vec3>} The luminance. | ||
| * @return {Node<float>} The luminance. | ||
| */ | ||
@@ -88,0 +88,0 @@ export const luminance = ( |
@@ -9,2 +9,3 @@ import TempNode from '../core/TempNode.js'; | ||
| import { directionToFaceDirection } from './FrontFacingNode.js'; | ||
| import { error } from '../../utils.js'; | ||
@@ -95,3 +96,3 @@ /** | ||
| console.error( `THREE.NodeMaterial: Unsupported normal map type: ${ normalMapType }` ); | ||
| error( `NodeMaterial: Unsupported normal map type: ${ normalMapType }` ); | ||
@@ -98,0 +99,0 @@ output = normalView; // Fallback to default normal view |
@@ -13,2 +13,3 @@ import TempNode from '../core/TempNode.js'; | ||
| import { RenderTarget } from '../../core/RenderTarget.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -139,2 +140,3 @@ const _size = /*@__PURE__*/ new Vector2(); | ||
| newNode.gradNode = this.gradNode; | ||
| newNode.offsetNode = this.offsetNode; | ||
@@ -346,3 +348,3 @@ return newNode; | ||
| */ | ||
| this._resolution = 1; | ||
| this._resolutionScale = 1; | ||
@@ -396,2 +398,28 @@ /** | ||
| /** | ||
| * Sets the resolution scale for the pass. | ||
| * The resolution scale is a factor that is multiplied with the renderer's width and height. | ||
| * | ||
| * @param {number} resolutionScale - The resolution scale to set. A value of `1` means full resolution. | ||
| * @return {PassNode} A reference to this pass. | ||
| */ | ||
| setResolutionScale( resolutionScale ) { | ||
| this._resolutionScale = resolutionScale; | ||
| return this; | ||
| } | ||
| /** | ||
| * Gets the current resolution scale of the pass. | ||
| * | ||
| * @return {number} The current resolution scale. A value of `1` means full resolution. | ||
| */ | ||
| getResolutionScale() { | ||
| return this._resolutionScale; | ||
| } | ||
| /** | ||
| * Sets the resolution for the pass. | ||
@@ -402,8 +430,9 @@ * The resolution is a factor that is multiplied with the renderer's width and height. | ||
| * @return {PassNode} A reference to this pass. | ||
| * @deprecated since r181. Use {@link PassNode#setResolutionScale `setResolutionScale()`} instead. | ||
| */ | ||
| setResolution( resolution ) { | ||
| setResolution( resolution ) { // @deprecated, r181 | ||
| this._resolution = resolution; | ||
| warn( 'PassNode: .setResolution() is deprecated. Use .setResolutionScale() instead.' ); | ||
| return this; | ||
| return this.setResolutionScale( resolution ); | ||
@@ -416,7 +445,10 @@ } | ||
| * @return {number} The current resolution. A value of `1` means full resolution. | ||
| * @deprecated since r181. Use {@link PassNode#getResolutionScale `getResolutionScale()`} instead. | ||
| */ | ||
| getResolution() { | ||
| getResolution() { // @deprecated, r181 | ||
| return this._resolution; | ||
| warn( 'PassNode: .getResolution() is deprecated. Use .getResolutionScale() instead.' ); | ||
| return this.getResolutionScale(); | ||
| } | ||
@@ -714,2 +746,3 @@ | ||
| const currentMRT = renderer.getMRT(); | ||
| const currentAutoClear = renderer.autoClear; | ||
| const currentMask = camera.layers.mask; | ||
@@ -734,7 +767,15 @@ | ||
| renderer.setMRT( this._mrt ); | ||
| renderer.autoClear = true; | ||
| const currentSceneName = scene.name; | ||
| scene.name = this.name ? this.name : scene.name; | ||
| renderer.render( scene, camera ); | ||
| scene.name = currentSceneName; | ||
| renderer.setRenderTarget( currentRenderTarget ); | ||
| renderer.setMRT( currentMRT ); | ||
| renderer.autoClear = currentAutoClear; | ||
@@ -756,4 +797,4 @@ camera.layers.mask = currentMask; | ||
| const effectiveWidth = this._width * this._pixelRatio * this._resolution; | ||
| const effectiveHeight = this._height * this._pixelRatio * this._resolution; | ||
| const effectiveWidth = Math.floor( this._width * this._pixelRatio * this._resolutionScale ); | ||
| const effectiveHeight = Math.floor( this._height * this._pixelRatio * this._resolutionScale ); | ||
@@ -798,3 +839,3 @@ this.renderTarget.setSize( effectiveWidth, effectiveHeight ); | ||
| this._scissor.multiplyScalar( this._pixelRatio * this._resolution ).floor(); | ||
| this._scissor.multiplyScalar( this._pixelRatio * this._resolutionScale ).floor(); | ||
@@ -835,3 +876,3 @@ } | ||
| this._viewport.multiplyScalar( this._pixelRatio * this._resolution ).floor(); | ||
| this._viewport.multiplyScalar( this._pixelRatio * this._resolutionScale ).floor(); | ||
@@ -838,0 +879,0 @@ } |
@@ -59,5 +59,6 @@ import TempNode from '../core/TempNode.js'; | ||
| * | ||
| * @private | ||
| * @type {?number} | ||
| */ | ||
| this.toneMapping = toneMapping; | ||
| this._toneMapping = toneMapping; | ||
@@ -82,2 +83,27 @@ /** | ||
| /** | ||
| * Sets the tone mapping type. | ||
| * | ||
| * @param {number} value - The tone mapping type. | ||
| * @return {ToneMappingNode} A reference to this node. | ||
| */ | ||
| setToneMapping( value ) { | ||
| this._toneMapping = value; | ||
| return this; | ||
| } | ||
| /** | ||
| * Gets the tone mapping type. | ||
| * | ||
| * @returns {number} The tone mapping type. | ||
| */ | ||
| getToneMapping() { | ||
| return this._toneMapping; | ||
| } | ||
| setup( { context } ) { | ||
@@ -89,3 +115,3 @@ | ||
| const toneMapping = ( this.toneMapping !== null ? this.toneMapping : context.toneMapping ) || NoToneMapping; | ||
| const toneMapping = ( this._toneMapping !== null ? this._toneMapping : context.toneMapping ) || NoToneMapping; | ||
| const outputColorSpace = ( this.outputColorSpace !== null ? this.outputColorSpace : context.outputColorSpace ) || NoColorSpace; | ||
@@ -92,0 +118,0 @@ |
@@ -8,2 +8,3 @@ import Node from '../core/Node.js'; | ||
| import { Vector4 } from '../../math/Vector4.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -286,3 +287,3 @@ let _screenSizeVec, _viewportVec; | ||
| console.warn( 'THREE.TSL: "viewportResolution" is deprecated. Use "screenSize" instead.' ); | ||
| warn( 'TSL: "viewportResolution" is deprecated. Use "screenSize" instead.' ); | ||
@@ -289,0 +290,0 @@ return screenSize; |
@@ -7,2 +7,3 @@ import TempNode from '../core/TempNode.js'; | ||
| import { hash } from '../core/NodeUtils.js'; | ||
| import { error } from '../../utils.js'; | ||
@@ -36,5 +37,6 @@ /** | ||
| * | ||
| * @private | ||
| * @type {number} | ||
| */ | ||
| this.toneMapping = toneMapping; | ||
| this._toneMapping = toneMapping; | ||
@@ -67,10 +69,35 @@ /** | ||
| return hash( this.toneMapping ); | ||
| return hash( this._toneMapping ); | ||
| } | ||
| /** | ||
| * Sets the tone mapping type. | ||
| * | ||
| * @param {number} value - The tone mapping type. | ||
| * @return {ToneMappingNode} A reference to this node. | ||
| */ | ||
| setToneMapping( value ) { | ||
| this._toneMapping = value; | ||
| return this; | ||
| } | ||
| /** | ||
| * Gets the tone mapping type. | ||
| * | ||
| * @returns {number} The tone mapping type. | ||
| */ | ||
| getToneMapping() { | ||
| return this._toneMapping; | ||
| } | ||
| setup( builder ) { | ||
| const colorNode = this.colorNode || builder.context.color; | ||
| const toneMapping = this.toneMapping; | ||
| const toneMapping = this._toneMapping; | ||
@@ -89,3 +116,3 @@ if ( toneMapping === NoToneMapping ) return colorNode; | ||
| console.error( 'ToneMappingNode: Unsupported Tone Mapping configuration.', toneMapping ); | ||
| error( 'ToneMappingNode: Unsupported Tone Mapping configuration.', toneMapping ); | ||
@@ -92,0 +119,0 @@ outputNode = colorNode; |
@@ -75,2 +75,10 @@ import { float, nodeObject, normalize, vec4 } from '../tsl/TSLBase.js'; | ||
| /** | ||
| * The name of this pass. | ||
| * | ||
| * @type {string} | ||
| * @default 'Outline Pass' | ||
| */ | ||
| this.name = 'Outline Pass'; | ||
| } | ||
@@ -77,0 +85,0 @@ |
| import { positionView } from '../accessors/Position.js'; | ||
| import { smoothstep } from '../math/MathNode.js'; | ||
| import { Fn, output, vec4 } from '../tsl/TSLBase.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -94,3 +95,3 @@ /** | ||
| console.warn( 'THREE.TSL: "rangeFog( color, near, far )" is deprecated. Use "fog( color, rangeFogFactor( near, far ) )" instead.' ); | ||
| warn( 'TSL: "rangeFog( color, near, far )" is deprecated. Use "fog( color, rangeFogFactor( near, far ) )" instead.' ); | ||
| return fog( color, rangeFogFactor( near, far ) ); | ||
@@ -111,5 +112,5 @@ | ||
| console.warn( 'THREE.TSL: "densityFog( color, density )" is deprecated. Use "fog( color, densityFogFactor( density ) )" instead.' ); | ||
| warn( 'TSL: "densityFog( color, density )" is deprecated. Use "fog( color, densityFogFactor( density ) )" instead.' ); | ||
| return fog( color, densityFogFactor( density ) ); | ||
| } |
@@ -7,2 +7,3 @@ import LightingModel from '../core/LightingModel.js'; | ||
| import { vec4 } from '../tsl/TSLBase.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -89,3 +90,3 @@ /** | ||
| default: | ||
| console.warn( 'THREE.BasicLightingModel: Unsupported .combine value:', material.combine ); | ||
| warn( 'BasicLightingModel: Unsupported .combine value:', material.combine ); | ||
| break; | ||
@@ -92,0 +93,0 @@ |
@@ -1,30 +0,71 @@ | ||
| import { Fn, vec2, vec4 } from '../../tsl/TSLBase.js'; | ||
| import { Fn, vec2 } from '../../tsl/TSLBase.js'; | ||
| import { texture } from '../../accessors/TextureNode.js'; | ||
| // Analytical approximation of the DFG LUT, one half of the | ||
| // split-sum approximation used in indirect specular lighting. | ||
| // via 'environmentBRDF' from "Physically Based Shading on Mobile" | ||
| // https://www.unrealengine.com/blog/physically-based-shading-on-mobile | ||
| import { DataTexture } from '../../../textures/DataTexture.js'; | ||
| import { RGFormat, HalfFloatType, LinearFilter, ClampToEdgeWrapping } from '../../../constants.js'; | ||
| /** | ||
| * Precomputed DFG LUT for Image-Based Lighting | ||
| * Resolution: 32x32 | ||
| * Samples: 4096 per texel | ||
| * Format: RG16F (2 half floats per texel: scale, bias) | ||
| */ | ||
| const DATA = new Uint16Array( [ | ||
| 0x2cd9, 0x3b64, 0x2d0e, 0x3b43, 0x2e20, 0x3aa7, 0x3061, 0x39fb, 0x325e, 0x397c, 0x3454, 0x3908, 0x357d, 0x3893, 0x3698, 0x381e, 0x379d, 0x375b, 0x3845, 0x3689, 0x38af, 0x35ca, 0x390d, 0x351e, 0x395f, 0x3484, 0x39a8, 0x33f9, 0x39e6, 0x330a, 0x3a1c, 0x3239, 0x3a4b, 0x3183, 0x3a73, 0x30e5, 0x3a95, 0x305b, 0x3ab1, 0x2fc6, 0x3ac9, 0x2ef7, 0x3ade, 0x2e43, 0x3aee, 0x2da7, 0x3afc, 0x2d1f, 0x3b07, 0x2ca9, 0x3b10, 0x2c42, 0x3b17, 0x2bd1, 0x3b1c, 0x2b34, 0x3b1f, 0x2aaa, 0x3b22, 0x2a31, 0x3b23, 0x29c7, 0x3b23, 0x2968, | ||
| 0x32d4, 0x3a4b, 0x32dc, 0x3a45, 0x3308, 0x3a26, 0x3378, 0x39d0, 0x3425, 0x394a, 0x34c9, 0x38be, 0x359c, 0x383e, 0x3688, 0x3796, 0x3778, 0x36c4, 0x382f, 0x3603, 0x3898, 0x3553, 0x38f7, 0x34b3, 0x394b, 0x3424, 0x3994, 0x334c, 0x39d3, 0x326c, 0x3a08, 0x31a9, 0x3a35, 0x30fe, 0x3a5a, 0x306a, 0x3a78, 0x2fd1, 0x3a90, 0x2ef1, 0x3aa2, 0x2e2e, 0x3ab0, 0x2d86, 0x3aba, 0x2cf3, 0x3ac1, 0x2c74, 0x3ac4, 0x2c05, 0x3ac4, 0x2b49, 0x3ac2, 0x2aa1, 0x3abd, 0x2a0c, 0x3ab7, 0x298b, 0x3aaf, 0x2918, 0x3aa6, 0x28b3, 0x3a9b, 0x285a, | ||
| 0x3559, 0x3954, 0x355a, 0x3951, 0x3566, 0x3944, 0x3582, 0x391e, 0x35b6, 0x38d3, 0x360a, 0x386a, 0x3684, 0x37ed, 0x3720, 0x370d, 0x37d3, 0x3641, 0x3847, 0x3588, 0x38a3, 0x34e2, 0x38fa, 0x344d, 0x3948, 0x3391, 0x398d, 0x32a6, 0x39c8, 0x31d6, 0x39fa, 0x3121, 0x3a22, 0x3082, 0x3a43, 0x2ff0, 0x3a5c, 0x2f01, 0x3a6f, 0x2e32, 0x3a7c, 0x2d7e, 0x3a84, 0x2ce2, 0x3a87, 0x2c5b, 0x3a87, 0x2bcc, 0x3a83, 0x2b00, 0x3a7b, 0x2a4e, 0x3a71, 0x29b3, 0x3a66, 0x292c, 0x3a58, 0x28b4, 0x3a4b, 0x284b, 0x3a3d, 0x27dc, 0x3a2e, 0x2739, | ||
| 0x3709, 0x387c, 0x370a, 0x387b, 0x3710, 0x3874, 0x3720, 0x385f, 0x373d, 0x3834, 0x376a, 0x37e1, 0x37ac, 0x3732, 0x3805, 0x3675, 0x383f, 0x35bc, 0x3883, 0x3511, 0x38cb, 0x3476, 0x3912, 0x33d8, 0x3955, 0x32e2, 0x3991, 0x3208, 0x39c6, 0x3149, 0x39f1, 0x30a1, 0x3a15, 0x300f, 0x3a30, 0x2f21, 0x3a44, 0x2e45, 0x3a51, 0x2d87, 0x3a59, 0x2ce2, 0x3a5b, 0x2c53, 0x3a58, 0x2bb0, 0x3a52, 0x2ada, 0x3a49, 0x2a1f, 0x3a40, 0x297d, 0x3a34, 0x28f0, 0x3a25, 0x2874, 0x3a13, 0x2807, 0x3a00, 0x274e, 0x39eb, 0x26a6, 0x39d5, 0x2611, | ||
| 0x3840, 0x3780, 0x3840, 0x377e, 0x3842, 0x3776, 0x3846, 0x375e, 0x384f, 0x372a, 0x385b, 0x36d3, 0x386c, 0x3659, 0x3885, 0x35c7, 0x38a8, 0x352d, 0x38d4, 0x3497, 0x3906, 0x340c, 0x393b, 0x331a, 0x3970, 0x323a, 0x39a0, 0x3172, 0x39cb, 0x30c3, 0x39ef, 0x302a, 0x3a0c, 0x2f4a, 0x3a21, 0x2e63, 0x3a2f, 0x2d9b, 0x3a37, 0x2ced, 0x3a39, 0x2c57, 0x3a37, 0x2baa, 0x3a34, 0x2ac9, 0x3a2c, 0x2a05, 0x3a20, 0x295d, 0x3a11, 0x28ca, 0x39ff, 0x2849, 0x39eb, 0x27b2, 0x39d5, 0x26ed, 0x39be, 0x2640, 0x39a5, 0x25aa, 0x398b, 0x2523, | ||
| 0x38e2, 0x363b, 0x38e2, 0x363b, 0x38e3, 0x3635, 0x38e6, 0x3626, 0x38ea, 0x3606, 0x38f0, 0x35cd, 0x38f8, 0x3579, 0x3903, 0x350e, 0x3915, 0x3495, 0x392d, 0x3418, 0x394c, 0x3340, 0x3970, 0x3261, 0x3995, 0x3197, 0x39b8, 0x30e4, 0x39d8, 0x3046, 0x39f3, 0x2f76, 0x3a08, 0x2e86, 0x3a16, 0x2db5, 0x3a1e, 0x2cff, 0x3a22, 0x2c61, 0x3a24, 0x2bb3, 0x3a20, 0x2ac7, 0x3a17, 0x29fc, 0x3a0a, 0x294c, 0x39fa, 0x28b2, 0x39e7, 0x282e, 0x39d1, 0x2773, 0x39b9, 0x26a9, 0x399f, 0x25fa, 0x3985, 0x255f, 0x3968, 0x24d6, 0x394a, 0x245d, | ||
| 0x396e, 0x3524, 0x396e, 0x3524, 0x396e, 0x3520, 0x396f, 0x3517, 0x3971, 0x3502, 0x3973, 0x34dd, 0x3975, 0x34a5, 0x3978, 0x3458, 0x397e, 0x33f9, 0x3987, 0x3332, 0x3997, 0x326b, 0x39aa, 0x31ac, 0x39c0, 0x30fb, 0x39d7, 0x305c, 0x39eb, 0x2f9e, 0x39fc, 0x2ea7, 0x3a07, 0x2dcf, 0x3a0f, 0x2d13, 0x3a16, 0x2c70, 0x3a17, 0x2bc4, 0x3a14, 0x2ad0, 0x3a0a, 0x29fc, 0x39fd, 0x2945, 0x39ed, 0x28a6, 0x39d9, 0x281d, 0x39c2, 0x274a, 0x39a9, 0x267c, 0x398e, 0x25c7, 0x3971, 0x2528, 0x3952, 0x249e, 0x3931, 0x2425, 0x3910, 0x2374, | ||
| 0x39e5, 0x3436, 0x39e5, 0x3435, 0x39e5, 0x3434, 0x39e5, 0x342e, 0x39e5, 0x3420, 0x39e5, 0x3408, 0x39e3, 0x33c4, 0x39e1, 0x3359, 0x39df, 0x32d3, 0x39de, 0x323a, 0x39e1, 0x319a, 0x39e7, 0x30fb, 0x39f0, 0x3065, 0x39f9, 0x2fb6, 0x3a02, 0x2ec0, 0x3a08, 0x2de6, 0x3a0d, 0x2d26, 0x3a12, 0x2c7e, 0x3a13, 0x2bda, 0x3a0e, 0x2adc, 0x3a05, 0x2a02, 0x39f8, 0x2945, 0x39e7, 0x28a1, 0x39d3, 0x2813, 0x39bc, 0x2730, 0x39a2, 0x265c, 0x3985, 0x25a3, 0x3966, 0x2501, 0x3945, 0x2475, 0x3923, 0x23f3, 0x3901, 0x231c, 0x38dd, 0x225e, | ||
| 0x3a4b, 0x32d6, 0x3a4a, 0x32d6, 0x3a4a, 0x32d4, 0x3a4a, 0x32cc, 0x3a48, 0x32bb, 0x3a47, 0x329d, 0x3a43, 0x326b, 0x3a3d, 0x3222, 0x3a36, 0x31c2, 0x3a2e, 0x314f, 0x3a28, 0x30d2, 0x3a23, 0x3052, 0x3a20, 0x2fab, 0x3a1e, 0x2ec2, 0x3a1b, 0x2def, 0x3a19, 0x2d31, 0x3a1a, 0x2c89, 0x3a18, 0x2beb, 0x3a11, 0x2aea, 0x3a07, 0x2a0a, 0x39fa, 0x2948, 0x39e9, 0x28a1, 0x39d4, 0x280f, 0x39bd, 0x2721, 0x39a2, 0x2647, 0x3985, 0x258b, 0x3964, 0x24e5, 0x3942, 0x2455, 0x391f, 0x23b3, 0x38fb, 0x22d8, 0x38d4, 0x2219, 0x38ad, 0x2172, | ||
| 0x3aa0, 0x3180, 0x3aa0, 0x3180, 0x3aa0, 0x317f, 0x3a9f, 0x317b, 0x3a9d, 0x3170, 0x3a99, 0x315d, 0x3a95, 0x313d, 0x3a8d, 0x310c, 0x3a82, 0x30ca, 0x3a76, 0x3077, 0x3a69, 0x3019, 0x3a5c, 0x2f68, 0x3a4f, 0x2e9e, 0x3a42, 0x2dde, 0x3a37, 0x2d2b, 0x3a30, 0x2c89, 0x3a29, 0x2bef, 0x3a1f, 0x2af0, 0x3a12, 0x2a0f, 0x3a03, 0x294a, 0x39f1, 0x28a0, 0x39dc, 0x280c, 0x39c5, 0x2717, 0x39a9, 0x2638, 0x398b, 0x2578, 0x396a, 0x24d0, 0x3947, 0x243f, 0x3923, 0x2380, 0x38fc, 0x22a4, 0x38d4, 0x21e4, 0x38ac, 0x213c, 0x3883, 0x20a8, | ||
| 0x3ae8, 0x3062, 0x3ae8, 0x3062, 0x3ae7, 0x3061, 0x3ae6, 0x305f, 0x3ae4, 0x305a, 0x3ae0, 0x304f, 0x3ada, 0x303b, 0x3ad1, 0x301b, 0x3ac5, 0x2fdd, 0x3ab6, 0x2f6a, 0x3aa4, 0x2ede, 0x3a91, 0x2e45, 0x3a7c, 0x2da5, 0x3a67, 0x2d0a, 0x3a57, 0x2c77, 0x3a48, 0x2bdc, 0x3a38, 0x2ae5, 0x3a27, 0x2a0a, 0x3a16, 0x2947, 0x3a02, 0x289d, 0x39eb, 0x2808, 0x39d3, 0x270d, 0x39b6, 0x262b, 0x3997, 0x256a, 0x3976, 0x24bf, 0x3952, 0x242b, 0x392d, 0x2358, 0x3904, 0x227a, 0x38db, 0x21b8, 0x38b2, 0x2110, 0x3887, 0x207d, 0x385b, 0x1ff6, | ||
| 0x3b23, 0x2ee8, 0x3b23, 0x2ee8, 0x3b22, 0x2ee8, 0x3b21, 0x2ee7, 0x3b1f, 0x2ee3, 0x3b1a, 0x2ed6, 0x3b14, 0x2ec1, 0x3b0b, 0x2e99, 0x3afe, 0x2e60, 0x3aee, 0x2e12, 0x3ad8, 0x2dad, 0x3ac1, 0x2d3d, 0x3aa5, 0x2cc3, 0x3a8b, 0x2c48, 0x3a76, 0x2ba2, 0x3a60, 0x2ac0, 0x3a49, 0x29f2, 0x3a32, 0x2938, 0x3a1b, 0x2893, 0x3a02, 0x27ff, 0x39e8, 0x26ff, 0x39ca, 0x261e, 0x39aa, 0x255b, 0x3988, 0x24b0, 0x3964, 0x241c, 0x393d, 0x2336, 0x3913, 0x2257, 0x38e9, 0x2195, 0x38be, 0x20eb, 0x3891, 0x2059, 0x3864, 0x1fae, 0x3837, 0x1ecd, | ||
| 0x3b54, 0x2d61, 0x3b54, 0x2d61, 0x3b53, 0x2d61, 0x3b52, 0x2d62, 0x3b4f, 0x2d61, 0x3b4b, 0x2d5c, 0x3b45, 0x2d51, 0x3b3b, 0x2d3d, 0x3b2e, 0x2d1a, 0x3b1d, 0x2ce7, 0x3b06, 0x2ca3, 0x3aeb, 0x2c52, 0x3acb, 0x2bee, 0x3ab0, 0x2b31, 0x3a94, 0x2a74, 0x3a77, 0x29bf, 0x3a5a, 0x2915, 0x3a3f, 0x287a, 0x3a22, 0x27de, 0x3a05, 0x26e4, 0x39e5, 0x2609, 0x39c3, 0x2547, 0x39a0, 0x249f, 0x397b, 0x240c, 0x3953, 0x2314, 0x3928, 0x2238, 0x38fd, 0x2175, 0x38d0, 0x20cb, 0x38a2, 0x2038, 0x3873, 0x1f71, 0x3844, 0x1e90, 0x3815, 0x1dce, | ||
| 0x3b7c, 0x2c22, 0x3b7c, 0x2c22, 0x3b7b, 0x2c23, 0x3b7a, 0x2c25, 0x3b77, 0x2c27, 0x3b73, 0x2c26, 0x3b6d, 0x2c23, 0x3b64, 0x2c1a, 0x3b57, 0x2c07, 0x3b46, 0x2bd1, 0x3b2e, 0x2b79, 0x3b0f, 0x2b07, 0x3aef, 0x2a86, 0x3ad1, 0x29f8, 0x3ab0, 0x2967, 0x3a8e, 0x28d7, 0x3a6d, 0x284e, 0x3a4c, 0x279f, 0x3a2b, 0x26b7, 0x3a08, 0x25e5, 0x39e4, 0x252c, 0x39be, 0x2488, 0x3998, 0x23f0, 0x396f, 0x22f2, 0x3943, 0x2215, 0x3917, 0x2155, 0x38e8, 0x20ae, 0x38b9, 0x201c, 0x3888, 0x1f38, 0x3857, 0x1e5a, 0x3826, 0x1d9a, 0x37eb, 0x1cf0, | ||
| 0x3b9c, 0x2a43, 0x3b9c, 0x2a43, 0x3b9b, 0x2a46, 0x3b9a, 0x2a4a, 0x3b98, 0x2a50, 0x3b93, 0x2a54, 0x3b8e, 0x2a59, 0x3b85, 0x2a56, 0x3b79, 0x2a45, 0x3b67, 0x2a24, 0x3b4f, 0x29ee, 0x3b2f, 0x29a4, 0x3b10, 0x294b, 0x3aef, 0x28e5, 0x3ac9, 0x2877, 0x3aa4, 0x2809, 0x3a7e, 0x2739, 0x3a59, 0x266d, 0x3a34, 0x25af, 0x3a0c, 0x2503, 0x39e4, 0x2468, 0x39bb, 0x23bb, 0x3990, 0x22c6, 0x3963, 0x21f0, 0x3936, 0x2133, 0x3906, 0x208f, 0x38d5, 0x1ffd, 0x38a3, 0x1f04, 0x3870, 0x1e28, 0x383d, 0x1d69, 0x380b, 0x1cc3, 0x37b0, 0x1c32, | ||
| 0x3bb5, 0x28aa, 0x3bb5, 0x28ab, 0x3bb5, 0x28ad, 0x3bb4, 0x28b2, 0x3bb2, 0x28b9, 0x3bae, 0x28c2, 0x3ba8, 0x28ca, 0x3ba0, 0x28d1, 0x3b94, 0x28cd, 0x3b83, 0x28c1, 0x3b6a, 0x28a3, 0x3b4b, 0x2876, 0x3b2d, 0x283d, 0x3b09, 0x27ea, 0x3ae1, 0x274b, 0x3ab9, 0x26a6, 0x3a8f, 0x25fe, 0x3a67, 0x255d, 0x3a3d, 0x24c5, 0x3a11, 0x2439, 0x39e6, 0x2371, 0x39b9, 0x228d, 0x398a, 0x21c1, 0x395a, 0x210b, 0x3929, 0x206c, 0x38f7, 0x1fc1, 0x38c3, 0x1ecb, 0x388f, 0x1df6, 0x385a, 0x1d3a, 0x3825, 0x1c99, 0x37e1, 0x1c08, 0x3779, 0x1b1b, | ||
| 0x3bc9, 0x26d3, 0x3bc9, 0x26d4, 0x3bc9, 0x26d9, 0x3bc8, 0x26e3, 0x3bc6, 0x26ef, 0x3bc2, 0x2705, 0x3bbd, 0x271a, 0x3bb6, 0x2731, 0x3baa, 0x273c, 0x3b9a, 0x273d, 0x3b81, 0x2726, 0x3b65, 0x26f7, 0x3b46, 0x26af, 0x3b20, 0x2650, 0x3af7, 0x25e1, 0x3acd, 0x256a, 0x3aa1, 0x24eb, 0x3a75, 0x246f, 0x3a46, 0x23ee, 0x3a17, 0x230d, 0x39e9, 0x223e, 0x39b7, 0x2183, 0x3985, 0x20d8, 0x3953, 0x2043, 0x391e, 0x1f7a, 0x38e9, 0x1e8d, 0x38b3, 0x1dbf, 0x387c, 0x1d0b, 0x3845, 0x1c6c, 0x380e, 0x1bc4, 0x37b0, 0x1ad2, 0x3745, 0x19fd, | ||
| 0x3bd9, 0x24e4, 0x3bd9, 0x24e5, 0x3bd9, 0x24e8, 0x3bd8, 0x24f2, 0x3bd5, 0x24fe, 0x3bd2, 0x2512, 0x3bce, 0x252b, 0x3bc6, 0x2544, 0x3bbc, 0x255a, 0x3bac, 0x256b, 0x3b93, 0x2569, 0x3b7a, 0x2557, 0x3b5b, 0x252f, 0x3b34, 0x24f7, 0x3b0c, 0x24ad, 0x3adf, 0x2458, 0x3ab1, 0x23f8, 0x3a82, 0x233f, 0x3a4f, 0x2286, 0x3a1e, 0x21d5, 0x39eb, 0x2130, 0x39b6, 0x2098, 0x3982, 0x200e, 0x394b, 0x1f25, 0x3914, 0x1e45, 0x38dc, 0x1d83, 0x38a3, 0x1cd6, 0x386b, 0x1c3d, 0x3831, 0x1b71, 0x37f2, 0x1a87, 0x3782, 0x19bc, 0x3714, 0x1909, | ||
| 0x3be5, 0x22d8, 0x3be5, 0x22d9, 0x3be4, 0x22df, 0x3be4, 0x22ef, 0x3be1, 0x2305, 0x3bde, 0x232a, 0x3bda, 0x2358, 0x3bd4, 0x2392, 0x3bcb, 0x23ca, 0x3bbb, 0x23f4, 0x3ba3, 0x2405, 0x3b8c, 0x2405, 0x3b6c, 0x23ec, 0x3b47, 0x23ae, 0x3b1d, 0x2353, 0x3af0, 0x22e2, 0x3ac0, 0x2261, 0x3a8e, 0x21d9, 0x3a5a, 0x214e, 0x3a26, 0x20c7, 0x39ee, 0x2045, 0x39b7, 0x1f97, 0x397f, 0x1eba, 0x3945, 0x1df0, 0x390b, 0x1d3a, 0x38d0, 0x1c9a, 0x3895, 0x1c0a, 0x385a, 0x1b18, 0x381f, 0x1a39, 0x37c9, 0x1975, 0x3756, 0x18cc, 0x36e6, 0x1836, | ||
| 0x3bed, 0x20a8, 0x3bed, 0x20a9, 0x3bed, 0x20ae, 0x3bed, 0x20bb, 0x3beb, 0x20cf, 0x3be8, 0x20ef, 0x3be4, 0x2119, 0x3bde, 0x214f, 0x3bd6, 0x2189, 0x3bc6, 0x21b8, 0x3bb1, 0x21de, 0x3b9a, 0x21f2, 0x3b7b, 0x21f2, 0x3b57, 0x21d8, 0x3b2d, 0x21a4, 0x3b00, 0x215f, 0x3acf, 0x2108, 0x3a99, 0x20a8, 0x3a64, 0x2043, 0x3a2c, 0x1fba, 0x39f2, 0x1ef3, 0x39b8, 0x1e36, 0x397c, 0x1d86, 0x3940, 0x1ce5, 0x3903, 0x1c52, 0x38c6, 0x1b9e, 0x3888, 0x1ab3, 0x384a, 0x19e4, 0x380e, 0x192b, 0x37a3, 0x188b, 0x372d, 0x17f7, 0x36ba, 0x1701, | ||
| 0x3bf4, 0x1e23, 0x3bf4, 0x1e25, 0x3bf4, 0x1e2d, 0x3bf3, 0x1e41, 0x3bf1, 0x1e64, 0x3bef, 0x1e9c, 0x3beb, 0x1ee1, 0x3be6, 0x1f40, 0x3bde, 0x1fa7, 0x3bce, 0x2001, 0x3bbd, 0x202f, 0x3ba6, 0x204e, 0x3b88, 0x205f, 0x3b64, 0x205b, 0x3b3b, 0x2044, 0x3b0e, 0x201f, 0x3adb, 0x1fcf, 0x3aa6, 0x1f4e, 0x3a6e, 0x1ec1, 0x3a33, 0x1e2b, 0x39f7, 0x1d95, 0x39ba, 0x1d06, 0x397b, 0x1c7d, 0x393c, 0x1bfc, 0x38fc, 0x1b13, 0x38bc, 0x1a40, 0x387c, 0x1983, 0x383c, 0x18da, 0x37fa, 0x1842, 0x377f, 0x177f, 0x3706, 0x1695, 0x3691, 0x15c8, | ||
| 0x3bf8, 0x1bca, 0x3bf8, 0x1bcc, 0x3bf8, 0x1bd8, 0x3bf8, 0x1bf7, 0x3bf6, 0x1c1b, 0x3bf4, 0x1c45, 0x3bf1, 0x1c83, 0x3bec, 0x1cce, 0x3be4, 0x1d21, 0x3bd5, 0x1d78, 0x3bc5, 0x1dd1, 0x3bb0, 0x1e17, 0x3b93, 0x1e4a, 0x3b70, 0x1e5f, 0x3b48, 0x1e57, 0x3b1b, 0x1e35, 0x3ae7, 0x1df6, 0x3ab2, 0x1da4, 0x3a77, 0x1d44, 0x3a3a, 0x1cdb, 0x39fc, 0x1c6e, 0x39bb, 0x1c03, 0x397a, 0x1b35, 0x3938, 0x1a72, 0x38f5, 0x19bb, 0x38b3, 0x1914, 0x3870, 0x187d, 0x382e, 0x17eb, 0x37db, 0x16f9, 0x375c, 0x1621, 0x36e1, 0x1565, 0x3669, 0x14be, | ||
| 0x3bfb, 0x18b9, 0x3bfb, 0x18ba, 0x3bfb, 0x18c3, 0x3bfb, 0x18da, 0x3bf9, 0x190a, 0x3bf7, 0x1948, 0x3bf5, 0x19ac, 0x3bf0, 0x1a20, 0x3be9, 0x1ab3, 0x3bdb, 0x1b49, 0x3bcd, 0x1be6, 0x3bb7, 0x1c34, 0x3b9c, 0x1c6d, 0x3b7a, 0x1c8e, 0x3b54, 0x1c9e, 0x3b26, 0x1c96, 0x3af2, 0x1c75, 0x3abc, 0x1c47, 0x3a80, 0x1c09, 0x3a42, 0x1b85, 0x3a01, 0x1aec, 0x39be, 0x1a50, 0x397a, 0x19b5, 0x3935, 0x1921, 0x38f0, 0x1895, 0x38aa, 0x1814, 0x3866, 0x173a, 0x3821, 0x1665, 0x37be, 0x15a4, 0x373c, 0x14f9, 0x36be, 0x1460, 0x3644, 0x13b3, | ||
| 0x3bfd, 0x156b, 0x3bfd, 0x156c, 0x3bfd, 0x1578, 0x3bfd, 0x1598, 0x3bfc, 0x15dd, 0x3bfa, 0x163c, 0x3bf7, 0x16cb, 0x3bf3, 0x177b, 0x3beb, 0x1833, 0x3be0, 0x18ad, 0x3bd2, 0x192e, 0x3bbd, 0x19a6, 0x3ba4, 0x1a0c, 0x3b83, 0x1a5a, 0x3b5d, 0x1a8c, 0x3b30, 0x1a9b, 0x3afd, 0x1a86, 0x3ac6, 0x1a5c, 0x3a89, 0x1a11, 0x3a49, 0x19b7, 0x3a06, 0x194f, 0x39c1, 0x18e3, 0x397a, 0x1873, 0x3933, 0x1805, 0x38eb, 0x173a, 0x38a3, 0x1676, 0x385c, 0x15bf, 0x3816, 0x1519, 0x37a2, 0x1482, 0x371d, 0x13f7, 0x369c, 0x1306, 0x3620, 0x1231, | ||
| 0x3bff, 0x11cb, 0x3bff, 0x11cd, 0x3bfe, 0x11dd, 0x3bfe, 0x1219, 0x3bfd, 0x126b, 0x3bfb, 0x12e9, 0x3bf9, 0x13c5, 0x3bf5, 0x1460, 0x3bee, 0x150f, 0x3be3, 0x15c9, 0x3bd6, 0x168a, 0x3bc3, 0x174f, 0x3baa, 0x1806, 0x3b8b, 0x184f, 0x3b66, 0x1888, 0x3b39, 0x18a6, 0x3b07, 0x18ad, 0x3acf, 0x189c, 0x3a92, 0x1876, 0x3a50, 0x1840, 0x3a0c, 0x17fd, 0x39c4, 0x176a, 0x397b, 0x16ce, 0x3931, 0x1634, 0x38e6, 0x1599, 0x389c, 0x1508, 0x3852, 0x147f, 0x380a, 0x1401, 0x3788, 0x131c, 0x36ff, 0x124a, 0x367c, 0x1190, 0x35fe, 0x10ea, | ||
| 0x3bff, 0x0daa, 0x3bff, 0x0dad, 0x3bff, 0x0dc0, 0x3bff, 0x0e0e, 0x3bfe, 0x0e87, 0x3bfc, 0x0f14, 0x3bfb, 0x1029, 0x3bf7, 0x10d1, 0x3bf0, 0x11d3, 0x3be6, 0x12c9, 0x3bd9, 0x13fc, 0x3bc7, 0x1499, 0x3bb0, 0x152a, 0x3b92, 0x15ab, 0x3b6e, 0x1615, 0x3b42, 0x165a, 0x3b10, 0x1681, 0x3ad8, 0x1683, 0x3a9a, 0x1665, 0x3a57, 0x1629, 0x3a11, 0x15dd, 0x39c8, 0x1580, 0x397c, 0x1518, 0x3930, 0x14ae, 0x38e3, 0x1441, 0x3896, 0x13b1, 0x384a, 0x12e9, 0x37ff, 0x122f, 0x376f, 0x1182, 0x36e3, 0x10e5, 0x365e, 0x1057, 0x35de, 0x0fac, | ||
| 0x3c00, 0x08ea, 0x3c00, 0x08ed, 0x3c00, 0x0902, 0x3c00, 0x0961, 0x3bff, 0x09f3, 0x3bfd, 0x0abc, 0x3bfb, 0x0c1f, 0x3bf8, 0x0d15, 0x3bf1, 0x0e5b, 0x3be8, 0x0fb4, 0x3bdc, 0x10b0, 0x3bcb, 0x1190, 0x3bb5, 0x126c, 0x3b97, 0x132c, 0x3b74, 0x13de, 0x3b4a, 0x1432, 0x3b18, 0x145e, 0x3ae0, 0x1472, 0x3aa2, 0x146f, 0x3a5f, 0x1456, 0x3a17, 0x142e, 0x39cc, 0x13ee, 0x397e, 0x136b, 0x392f, 0x12e1, 0x38df, 0x124f, 0x3890, 0x11bd, 0x3842, 0x1131, 0x37eb, 0x10ac, 0x3757, 0x102e, 0x36c9, 0x0f76, 0x3640, 0x0ea3, 0x35bf, 0x0de4, | ||
| 0x3c00, 0x039b, 0x3c00, 0x039d, 0x3c00, 0x03b2, 0x3c00, 0x041c, 0x3bff, 0x04be, 0x3bfd, 0x05d6, 0x3bfc, 0x0764, 0x3bf8, 0x08e2, 0x3bf2, 0x0a67, 0x3bea, 0x0c1b, 0x3bde, 0x0d41, 0x3bcd, 0x0e5f, 0x3bb8, 0x0f8c, 0x3b9c, 0x1057, 0x3b7a, 0x10e5, 0x3b51, 0x1155, 0x3b20, 0x11a5, 0x3ae8, 0x11da, 0x3aaa, 0x11ef, 0x3a66, 0x11e5, 0x3a1d, 0x11c1, 0x39d0, 0x1185, 0x3980, 0x113b, 0x392e, 0x10e5, 0x38dc, 0x1087, 0x388b, 0x1028, 0x383b, 0x0f94, 0x37d9, 0x0edb, 0x3741, 0x0e2c, 0x36af, 0x0d89, 0x3625, 0x0cf2, 0x35a1, 0x0c69, | ||
| 0x3c00, 0x0107, 0x3c00, 0x0108, 0x3c00, 0x0110, 0x3c00, 0x0145, 0x3bff, 0x0197, 0x3bfe, 0x0224, 0x3bfc, 0x030c, 0x3bf8, 0x0478, 0x3bf3, 0x062c, 0x3beb, 0x0833, 0x3be0, 0x0979, 0x3bd0, 0x0aeb, 0x3bbc, 0x0c3d, 0x3ba0, 0x0d01, 0x3b80, 0x0dbd, 0x3b57, 0x0e69, 0x3b27, 0x0eeb, 0x3af0, 0x0f53, 0x3ab1, 0x0f8a, 0x3a6c, 0x0f9f, 0x3a22, 0x0f8b, 0x39d4, 0x0f5b, 0x3982, 0x0f0f, 0x392f, 0x0eac, 0x38da, 0x0e3d, 0x3886, 0x0dc9, 0x3834, 0x0d51, 0x37c7, 0x0cd9, 0x372c, 0x0c65, 0x3697, 0x0bef, 0x360a, 0x0b20, 0x3585, 0x0a62, | ||
| 0x3c00, 0x0031, 0x3c00, 0x0031, 0x3c00, 0x0034, 0x3c00, 0x004b, 0x3bff, 0x006f, 0x3bfe, 0x00c9, 0x3bfc, 0x011b, 0x3bf9, 0x0207, 0x3bf4, 0x02d6, 0x3bec, 0x0415, 0x3be1, 0x0587, 0x3bd2, 0x0703, 0x3bbf, 0x087d, 0x3ba5, 0x096a, 0x3b85, 0x0a59, 0x3b5d, 0x0b32, 0x3b2e, 0x0bee, 0x3af7, 0x0c44, 0x3ab8, 0x0c7c, 0x3a73, 0x0c9c, 0x3a28, 0x0ca4, 0x39d8, 0x0c98, 0x3985, 0x0c77, 0x392f, 0x0c4a, 0x38d9, 0x0c10, 0x3882, 0x0ba0, 0x382e, 0x0b14, 0x37b6, 0x0a84, 0x3717, 0x09f5, 0x3680, 0x0969, 0x35f0, 0x08e6, 0x356a, 0x086a, | ||
| 0x3c00, 0x0004, 0x3c00, 0x0004, 0x3c00, 0x0004, 0x3c00, 0x000d, 0x3bff, 0x0021, 0x3bfe, 0x003b, 0x3bfd, 0x0070, 0x3bf9, 0x00c7, 0x3bf4, 0x012e, 0x3bed, 0x01c8, 0x3be3, 0x0274, 0x3bd4, 0x033b, 0x3bc1, 0x043a, 0x3ba8, 0x0534, 0x3b89, 0x0641, 0x3b62, 0x073b, 0x3b34, 0x0815, 0x3afd, 0x087c, 0x3abf, 0x08d0, 0x3a7a, 0x090a, 0x3a2e, 0x092c, 0x39dd, 0x0936, 0x3988, 0x0928, 0x3930, 0x0907, 0x38d7, 0x08d7, 0x387f, 0x089b, 0x3828, 0x0855, 0x37a7, 0x080b, 0x3704, 0x077b, 0x366a, 0x06e1, 0x35d8, 0x0649, 0x3550, 0x05b8, | ||
| 0x3c00, 0x0000, 0x3c00, 0x0000, 0x3c00, 0x0000, 0x3c00, 0x0003, 0x3bff, 0x0012, 0x3bfe, 0x001a, 0x3bfd, 0x0035, 0x3bfa, 0x0050, 0x3bf4, 0x0061, 0x3bed, 0x00a5, 0x3be4, 0x00ee, 0x3bd6, 0x0146, 0x3bc3, 0x01ab, 0x3bab, 0x0211, 0x3b8d, 0x028e, 0x3b67, 0x0303, 0x3b39, 0x0375, 0x3b04, 0x03e2, 0x3ac6, 0x0441, 0x3a80, 0x0492, 0x3a34, 0x04cd, 0x39e1, 0x04f2, 0x398b, 0x0504, 0x3931, 0x0502, 0x38d6, 0x04ec, 0x387c, 0x04c7, 0x3822, 0x0496, 0x3798, 0x045c, 0x36f2, 0x041a, 0x3655, 0x03d5, 0x35c1, 0x038e, 0x3537, 0x0347 | ||
| ] ); | ||
| let lut = null; | ||
| const DFGApprox = /*@__PURE__*/ Fn( ( { roughness, dotNV } ) => { | ||
| const c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 ); | ||
| if ( lut === null ) { | ||
| const c1 = vec4( 1, 0.0425, 1.04, - 0.04 ); | ||
| lut = new DataTexture( DATA, 32, 32, RGFormat, HalfFloatType ); | ||
| lut.minFilter = LinearFilter; | ||
| lut.magFilter = LinearFilter; | ||
| lut.wrapS = ClampToEdgeWrapping; | ||
| lut.wrapT = ClampToEdgeWrapping; | ||
| lut.generateMipmaps = false; | ||
| lut.needsUpdate = true; | ||
| const r = roughness.mul( c0 ).add( c1 ); | ||
| } | ||
| const a004 = r.x.mul( r.x ).min( dotNV.mul( - 9.28 ).exp2() ).mul( r.x ).add( r.y ); | ||
| const uv = vec2( roughness, dotNV ); | ||
| const fab = vec2( - 1.04, 1.04 ).mul( a004 ).add( r.zw ); | ||
| return texture( lut, uv ).rg; | ||
| return fab; | ||
| } ).setLayout( { | ||
| name: 'DFGApprox', | ||
| type: 'vec2', | ||
| inputs: [ | ||
| { name: 'roughness', type: 'float' }, | ||
| { name: 'dotNV', type: 'vec3' } | ||
| ] | ||
| } ); | ||
| export default DFGApprox; |
| import BRDF_Lambert from './BSDF/BRDF_Lambert.js'; | ||
| import BRDF_GGX from './BSDF/BRDF_GGX.js'; | ||
| import BRDF_GGX_Multiscatter from './BSDF/BRDF_GGX_Multiscatter.js'; | ||
| import DFGApprox from './BSDF/DFGApprox.js'; | ||
@@ -564,3 +565,3 @@ import EnvironmentBRDF from './BSDF/EnvironmentBRDF.js'; | ||
| const Favg = specularColor.add( specularColor.oneMinus().mul( 0.047619 ) ); // 1/21 | ||
| const Favg = Fr.add( Fr.oneMinus().mul( 0.047619 ) ); // 1/21 | ||
| const Fms = FssEss.mul( Favg ).div( Ems.mul( Favg ).oneMinus() ); | ||
@@ -601,3 +602,3 @@ | ||
| reflectedLight.directSpecular.addAssign( irradiance.mul( BRDF_GGX( { lightDirection, f0: specularColor, f90: 1, roughness, iridescence: this.iridescence, f: this.iridescenceFresnel, USE_IRIDESCENCE: this.iridescence, USE_ANISOTROPY: this.anisotropy } ) ) ); | ||
| reflectedLight.directSpecular.addAssign( irradiance.mul( BRDF_GGX_Multiscatter( { lightDirection, f0: specularColor, f90: 1, roughness, f: this.iridescenceFresnel, USE_IRIDESCENCE: this.iridescence, USE_ANISOTROPY: this.anisotropy } ) ) ); | ||
@@ -604,0 +605,0 @@ } |
@@ -33,3 +33,3 @@ import LightingModel from '../core/LightingModel.js'; | ||
| const { material, context } = builder; | ||
| const { material } = builder; | ||
@@ -83,9 +83,9 @@ const startPos = property( 'vec3' ); | ||
| context.sceneDepthNode = linearDepth( material.depthNode ).toVar(); | ||
| builder.context.sceneDepthNode = linearDepth( material.depthNode ).toVar(); | ||
| } | ||
| context.positionWorld = positionRay; | ||
| context.shadowPositionWorld = positionRay; | ||
| context.positionView = positionViewRay; | ||
| builder.context.positionWorld = positionRay; | ||
| builder.context.shadowPositionWorld = positionRay; | ||
| builder.context.positionView = positionViewRay; | ||
@@ -92,0 +92,0 @@ scatteringDensity.assign( 0 ); |
@@ -70,5 +70,8 @@ import Node from '../core/Node.js'; | ||
| const minLength = builder.getTypeLength( getValueType( this.minNode.value ) ); | ||
| const maxLength = builder.getTypeLength( getValueType( this.maxNode.value ) ); | ||
| const minNode = this.getConstNode( this.minNode ); | ||
| const maxNode = this.getConstNode( this.maxNode ); | ||
| const minLength = builder.getTypeLength( getValueType( minNode.value ) ); | ||
| const maxLength = builder.getTypeLength( getValueType( maxNode.value ) ); | ||
| return minLength > maxLength ? minLength : maxLength; | ||
@@ -90,2 +93,32 @@ | ||
| /** | ||
| * Returns a constant node from the given node by traversing it. | ||
| * | ||
| * @param {Node} node - The node to traverse. | ||
| * @returns {Node} The constant node, if found. | ||
| */ | ||
| getConstNode( node ) { | ||
| let output = null; | ||
| node.traverse( n => { | ||
| if ( n.isConstNode === true ) { | ||
| output = n; | ||
| } | ||
| } ); | ||
| if ( output === null ) { | ||
| throw new Error( 'THREE.TSL: No "ConstNode" found in node graph.' ); | ||
| } | ||
| return output; | ||
| } | ||
| setup( builder ) { | ||
@@ -99,5 +132,8 @@ | ||
| const minValue = this.minNode.value; | ||
| const maxValue = this.maxNode.value; | ||
| const minNode = this.getConstNode( this.minNode ); | ||
| const maxNode = this.getConstNode( this.maxNode ); | ||
| const minValue = minNode.value; | ||
| const maxValue = maxNode.value; | ||
| const minLength = builder.getTypeLength( getValueType( minValue ) ); | ||
@@ -104,0 +140,0 @@ const maxLength = builder.getTypeLength( getValueType( maxValue ) ); |
| import Node from '../core/Node.js'; | ||
| import { nodeObject } from '../tsl/TSLBase.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -113,3 +114,3 @@ /** | ||
| console.warn( `ComputeBuiltinNode: Compute built-in value ${builtinName} can not be accessed in the ${builder.shaderStage} stage` ); | ||
| warn( `ComputeBuiltinNode: Compute built-in value ${builtinName} can not be accessed in the ${builder.shaderStage} stage` ); | ||
| return builder.generateConst( nodeType ); | ||
@@ -116,0 +117,0 @@ |
| import Node from '../core/Node.js'; | ||
| import { NodeUpdateType } from '../core/constants.js'; | ||
| import { addMethodChaining, nodeObject } from '../tsl/TSLCore.js'; | ||
| import { warn, error } from '../../utils.js'; | ||
@@ -56,3 +57,3 @@ /** | ||
| * | ||
| * @type {number} | ||
| * @type {number|Array<number>} | ||
| */ | ||
@@ -94,2 +95,8 @@ this.count = null; | ||
| /** | ||
| * TODO | ||
| * | ||
| * @param {number|Array<number>} count - Array with [ x, y, z ] values for dispatch or a single number for the count | ||
| * @return {ComputeNode} | ||
| */ | ||
| setCount( count ) { | ||
@@ -103,2 +110,7 @@ | ||
| /** | ||
| * TODO | ||
| * | ||
| * @return {number|Array<number>} | ||
| */ | ||
| getCount() { | ||
@@ -142,3 +154,3 @@ | ||
| console.warn( 'THREE.TSL: "label()" has been deprecated. Use "setName()" instead.' ); // @deprecated r179 | ||
| warn( 'TSL: "label()" has been deprecated. Use "setName()" instead.' ); // @deprecated r179 | ||
@@ -237,3 +249,3 @@ return this.setName( name ); | ||
| console.error( 'THREE.TSL: compute() workgroupSize must have 1, 2, or 3 elements' ); | ||
| error( 'TSL: compute() workgroupSize must have 1, 2, or 3 elements' ); | ||
@@ -248,3 +260,3 @@ } | ||
| console.error( `THREE.TSL: compute() workgroupSize element at index [ ${ i } ] must be a positive integer` ); | ||
| error( `TSL: compute() workgroupSize element at index [ ${ i } ] must be a positive integer` ); | ||
@@ -271,3 +283,3 @@ } | ||
| * @param {Node} node - TODO | ||
| * @param {number} count - TODO. | ||
| * @param {number|Array<number>} count - TODO. | ||
| * @param {Array<number>} [workgroupSize=[64]] - TODO. | ||
@@ -274,0 +286,0 @@ * @returns {AtomicFunctionNode} |
@@ -206,2 +206,3 @@ import TempNode from '../core/TempNode.js'; | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -216,2 +217,3 @@ * @return {bool} The result of the computation. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -226,2 +228,3 @@ * @param {bool} pred - A boolean that sets the bit corresponding to the invocations subgroup invocation id. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -236,2 +239,3 @@ * @param {number} e - The value provided to the reduction by the current invocation. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -246,2 +250,3 @@ * @param {number} e - The value provided to the inclusive scan by the current invocation. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -256,2 +261,3 @@ * @param {number} e - The value provided to the exclusive scan by the current invocation. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -266,2 +272,3 @@ * @param {number} e - The value provided to the reduction by the current invocation. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -276,2 +283,3 @@ * @param {number} e - The value provided to the inclusive scan by the current invocation. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -286,2 +294,3 @@ * @param {number} e - The value provided to the exclusive scan by the current invocation. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -296,2 +305,3 @@ * @param {number} e - The value provided to the reduction by the current invocation. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -306,2 +316,3 @@ * @param {number} e - The value provided to the reduction by the current invocation. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -316,2 +327,3 @@ * @param {number} e - The value provided to the reduction by the current invocation. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -326,2 +338,3 @@ * @param {number} e - The value provided to the reduction by the current invocation. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -336,2 +349,3 @@ * @param {number} e - The value provided to the reduction by the current invocation. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -345,2 +359,3 @@ * @return {bool} The result of the computation. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -354,2 +369,3 @@ * @return {bool} The result of the computation. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -365,2 +381,3 @@ * @param {number} e - The value to broadcast from the lowest subgroup invocation. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -375,2 +392,3 @@ * @param {number} e - The value to swap from the current invocation. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -385,2 +403,3 @@ * @param {number} e - The value to swap from the current invocation. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -395,2 +414,3 @@ * @param {number} e - The value to swap from the current invocation. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -406,2 +426,3 @@ * @param {number} e - The value to broadcast from subgroup invocation 'id'. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -417,2 +438,3 @@ * @param {number} v - The value to return from subgroup invocation id^mask. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -428,2 +450,3 @@ * @param {number} v - The value to return from subgroup invocation id^mask. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -439,2 +462,3 @@ * @param {number} v - The value to return from subgroup invocation id^mask. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -450,2 +474,3 @@ * @param {number} v - The value to return from subgroup invocation id^mask. | ||
| * | ||
| * @tsl | ||
| * @method | ||
@@ -452,0 +477,0 @@ * @param {number} e - The value to broadcast. |
| import ArrayElementNode from '../utils/ArrayElementNode.js'; | ||
| import { nodeObject } from '../tsl/TSLCore.js'; | ||
| import Node from '../core/Node.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -152,3 +153,3 @@ /** | ||
| console.warn( 'THREE.TSL: "label()" has been deprecated. Use "setName()" instead.' ); // @deprecated r179 | ||
| warn( 'TSL: "label()" has been deprecated. Use "setName()" instead.' ); // @deprecated r179 | ||
@@ -155,0 +156,0 @@ return this.setName( name ); |
| import LightingNode from './LightingNode.js'; | ||
| import { cache } from '../core/CacheNode.js'; | ||
| import { isolate } from '../core/IsolateNode.js'; | ||
| import { roughness, clearcoatRoughness } from '../core/PropertyNode.js'; | ||
@@ -7,3 +7,3 @@ import { cameraViewMatrix } from '../accessors/Camera.js'; | ||
| import { positionViewDirection } from '../accessors/Position.js'; | ||
| import { float } from '../tsl/TSLBase.js'; | ||
| import { float, pow4 } from '../tsl/TSLBase.js'; | ||
| import { bentNormalView } from '../accessors/AccessorsUtils.js'; | ||
@@ -81,4 +81,4 @@ import { pmremTexture } from '../pmrem/PMREMNode.js'; | ||
| const isolateRadiance = cache( radiance ); | ||
| const isolateIrradiance = cache( irradiance ); | ||
| const isolateRadiance = isolate( radiance ); | ||
| const isolateIrradiance = isolate( irradiance ); | ||
@@ -98,3 +98,3 @@ // | ||
| const clearcoatRadianceContext = envNode.context( createRadianceContext( clearcoatRoughness, clearcoatNormalView ) ).mul( materialEnvIntensity ); | ||
| const isolateClearcoatRadiance = cache( clearcoatRadianceContext ); | ||
| const isolateClearcoatRadiance = isolate( clearcoatRadianceContext ); | ||
@@ -123,3 +123,3 @@ clearcoatRadiance.addAssign( isolateClearcoatRadiance ); | ||
| // Mixing the reflection with the normal is more accurate and keeps rough objects from gathering light from behind their tangent plane. | ||
| reflectVec = roughnessNode.mul( roughnessNode ).mix( reflectVec, normalViewNode ).normalize(); | ||
| reflectVec = pow4( roughnessNode ).mix( reflectVec, normalViewNode ).normalize(); | ||
@@ -126,0 +126,0 @@ reflectVec = reflectVec.transformDirection( cameraViewMatrix ); |
| import Node from '../core/Node.js'; | ||
| import { nodeObject, property, vec3 } from '../tsl/TSLBase.js'; | ||
| import { hashArray } from '../core/NodeUtils.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -227,3 +228,3 @@ const sortLights = ( lights ) => { | ||
| console.warn( `LightsNode.setupNodeLights: Light node not found for ${ light.constructor.name }` ); | ||
| warn( `LightsNode.setupNodeLights: Light node not found for ${ light.constructor.name }` ); | ||
| continue; | ||
@@ -372,4 +373,2 @@ | ||
| context.material.transparent = true; | ||
| } | ||
@@ -376,0 +375,0 @@ |
@@ -282,4 +282,10 @@ import ShadowNode from './ShadowNode.js'; | ||
| const currentSceneName = scene.name; | ||
| scene.name = `Point Light Shadow [ ${ light.name || 'ID: ' + light.id } ] - Face ${ vp + 1 }`; | ||
| renderer.render( scene, shadow.camera ); | ||
| scene.name = currentSceneName; | ||
| } | ||
@@ -286,0 +292,0 @@ |
@@ -248,2 +248,4 @@ import { float, vec2, vec4, If, Fn } from '../tsl/TSLBase.js'; | ||
| * | ||
| * @tsl | ||
| * @function | ||
| * @param {Light} light - The light source for which the shadow material is needed. | ||
@@ -250,0 +252,0 @@ * If the light is a point light, a depth node is calculated |
| import ShadowBaseNode, { shadowPositionWorld } from './ShadowBaseNode.js'; | ||
| import { float, vec2, vec3, int, Fn, nodeObject } from '../tsl/TSLBase.js'; | ||
| import { reference } from '../accessors/ReferenceNode.js'; | ||
| import { texture } from '../accessors/TextureNode.js'; | ||
| import { texture, textureLoad } from '../accessors/TextureNode.js'; | ||
| import { normalWorld } from '../accessors/Normal.js'; | ||
@@ -21,2 +21,5 @@ import { mix, sqrt } from '../math/MathNode.js'; | ||
| import ChainMap from '../../renderers/common/ChainMap.js'; | ||
| import { warn } from '../../utils.js'; | ||
| import { textureSize } from '../accessors/TextureSizeNode.js'; | ||
| import { uv } from '../accessors/UV.js'; | ||
@@ -31,2 +34,4 @@ // | ||
| * | ||
| * @tsl | ||
| * @function | ||
| * @param {Renderer} renderer - The renderer. | ||
@@ -273,2 +278,18 @@ * @param {LightShadow} shadow - The light shadow object containing shadow properties. | ||
| /** | ||
| * The current shadow map type of this shadow node. | ||
| * | ||
| * @type {?number} | ||
| * @private | ||
| * @default null | ||
| */ | ||
| this._currentShadowType = null; | ||
| /** | ||
| * A Weak Map holding the current frame ID per camera. Used | ||
| * to control the update of shadow maps. | ||
| * | ||
| * @type {WeakMap<Camera,number>} | ||
| * @private | ||
| */ | ||
| this._cameraFrameId = new WeakMap(); | ||
@@ -411,3 +432,3 @@ | ||
| const { renderer } = builder; | ||
| const { renderer, camera } = builder; | ||
@@ -420,2 +441,3 @@ const { light, shadow } = this; | ||
| shadow.camera.coordinateSystem = camera.coordinateSystem; | ||
| shadow.camera.updateProjectionMatrix(); | ||
@@ -522,4 +544,16 @@ | ||
| return shadowOutput; | ||
| // Shadow Output + Inspector | ||
| const inspectName = `${ this.light.type } Shadow [ ${ this.light.name || 'ID: ' + this.light.id } ]`; | ||
| return shadowOutput.toInspector( `${ inspectName } / Color`, () => { | ||
| return texture( this.shadowMap.texture ); | ||
| } ).toInspector( `${ inspectName } / Depth`, () => { | ||
| return textureLoad( this.shadowMap.depthTexture, uv().mul( textureSize( texture( this.shadowMap.depthTexture ) ) ) ).x.oneMinus(); | ||
| } ); | ||
| } | ||
@@ -540,2 +574,11 @@ | ||
| const currentShadowType = builder.renderer.shadowMap.type; | ||
| if ( this._currentShadowType !== currentShadowType ) { | ||
| this._reset(); | ||
| this._node = null; | ||
| } | ||
| let node = this._node; | ||
@@ -548,2 +591,3 @@ | ||
| this._node = node = this.setupShadow( builder ); | ||
| this._currentShadowType = currentShadowType; | ||
@@ -554,3 +598,3 @@ } | ||
| console.warn( 'THREE.NodeMaterial: ".shadowNode" is deprecated. Use ".castShadowNode" instead.' ); | ||
| warn( 'NodeMaterial: ".shadowNode" is deprecated. Use ".castShadowNode" instead.' ); | ||
@@ -588,4 +632,10 @@ } | ||
| const currentSceneName = scene.name; | ||
| scene.name = `Shadow Map [ ${ light.name || 'ID: ' + light.id } ]`; | ||
| renderer.render( scene, shadow.camera ); | ||
| scene.name = currentSceneName; | ||
| } | ||
@@ -677,5 +727,24 @@ | ||
| this.shadowMap.dispose(); | ||
| this.shadowMap = null; | ||
| this._reset(); | ||
| super.dispose(); | ||
| } | ||
| /** | ||
| * Resets the resouce state of this shadow node. | ||
| * | ||
| * @private | ||
| */ | ||
| _reset() { | ||
| this._currentShadowType = null; | ||
| if ( this.shadowMap ) { | ||
| this.shadowMap.dispose(); | ||
| this.shadowMap = null; | ||
| } | ||
| if ( this.vsmShadowMapVertical !== null ) { | ||
@@ -701,4 +770,2 @@ | ||
| super.dispose(); | ||
| } | ||
@@ -705,0 +772,0 @@ |
| import Node from '../core/Node.js'; | ||
| import { property } from '../core/PropertyNode.js'; | ||
| import { addMethodChaining, nodeProxy } from '../tsl/TSLCore.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -102,5 +103,5 @@ /** | ||
| const condNode = this.condNode.cache(); | ||
| const ifNode = this.ifNode.cache(); | ||
| const elseNode = this.elseNode ? this.elseNode.cache() : null; | ||
| const condNode = this.condNode; | ||
| const ifNode = this.ifNode.isolate(); | ||
| const elseNode = this.elseNode ? this.elseNode.isolate() : null; | ||
@@ -177,3 +178,3 @@ // | ||
| console.warn( 'THREE.TSL: Return statement used in an inline \'Fn()\'. Define a layout struct to allow return values.' ); | ||
| warn( 'TSL: Return statement used in an inline \'Fn()\'. Define a layout struct to allow return values.' ); | ||
@@ -208,3 +209,3 @@ ifSnippet = '// ' + ifSnippet; | ||
| console.warn( 'THREE.TSL: Return statement used in an inline \'Fn()\'. Define a layout struct to allow return values.' ); | ||
| warn( 'TSL: Return statement used in an inline \'Fn()\'. Define a layout struct to allow return values.' ); | ||
@@ -211,0 +212,0 @@ elseSnippet = '// ' + elseSnippet; |
@@ -5,2 +5,3 @@ import TempNode from '../core/TempNode.js'; | ||
| import { WebGLCoordinateSystem, WebGPUCoordinateSystem } from '../../constants.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -294,3 +295,3 @@ /** | ||
| console.warn( `THREE.TSL: '${ method }' is not supported in the ${ builder.shaderStage } stage.` ); | ||
| warn( `TSL: '${ method }' is not supported in the ${ builder.shaderStage } stage.` ); | ||
@@ -420,2 +421,11 @@ method = '/*' + method + '*/'; | ||
| /** | ||
| * Represents PI * 2. Please use the non-deprecated version `TWO_PI`. | ||
| * | ||
| * @tsl | ||
| * @deprecated | ||
| * @type {Node<float>} | ||
| */ | ||
| export const PI2 = /*@__PURE__*/ float( Math.PI * 2 ); // @deprecated r181 | ||
| /** | ||
| * Represents PI * 2. | ||
@@ -426,5 +436,13 @@ * | ||
| */ | ||
| export const PI2 = /*@__PURE__*/ float( Math.PI * 2 ); | ||
| export const TWO_PI = /*@__PURE__*/ float( Math.PI * 2 ); | ||
| /** | ||
| * Represents PI / 2. | ||
| * | ||
| * @tsl | ||
| * @type {Node<float>} | ||
| */ | ||
| export const HALF_PI = /*@__PURE__*/ float( Math.PI * 0.5 ); | ||
| /** | ||
| * Returns `true` if all components of `x` are `true`. | ||
@@ -785,3 +803,3 @@ * | ||
| console.warn( 'THREE.TSL: "equals" is deprecated. Use "equal" inside a vector instead, like: "bvec*( equal( ... ) )"' ); | ||
| warn( 'TSL: "equals" is deprecated. Use "equal" inside a vector instead, like: "bvec*( equal( ... ) )"' ); | ||
| return equal( x, y ); | ||
@@ -1084,3 +1102,3 @@ | ||
| console.warn( 'THREE.TSL: "atan2" is overloaded. Use "atan" instead.' ); | ||
| warn( 'TSL: "atan2" is overloaded. Use "atan" instead.' ); | ||
| return atan( y, x ); | ||
@@ -1087,0 +1105,0 @@ |
| import { WebGLCoordinateSystem } from '../../constants.js'; | ||
| import TempNode from '../core/TempNode.js'; | ||
| import { addMethodChaining, Fn, int, nodeProxyIntent } from '../tsl/TSLCore.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -599,3 +600,3 @@ const _vectorOperators = { | ||
| */ | ||
| export const bitNot = /*@__PURE__*/ nodeProxyIntent( OperatorNode, '~' ).setParameterLength( 2 ).setName( 'bitNot' ); | ||
| export const bitNot = /*@__PURE__*/ nodeProxyIntent( OperatorNode, '~' ).setParameterLength( 1 ).setName( 'bitNot' ); | ||
@@ -746,3 +747,3 @@ /** | ||
| console.warn( 'THREE.TSL: "modInt()" is deprecated. Use "mod( int( ... ) )" instead.' ); | ||
| warn( 'TSL: "modInt()" is deprecated. Use "mod( int( ... ) )" instead.' ); | ||
| return mod( int( a ), int( b ) ); | ||
@@ -749,0 +750,0 @@ |
@@ -9,3 +9,3 @@ // constants | ||
| export { default as BypassNode } from './core/BypassNode.js'; | ||
| export { default as CacheNode } from './core/CacheNode.js'; | ||
| export { default as IsolateNode } from './core/IsolateNode.js'; | ||
| export { default as ConstNode } from './core/ConstNode.js'; | ||
@@ -12,0 +12,0 @@ export { default as ContextNode } from './core/ContextNode.js'; |
@@ -1,3 +0,3 @@ | ||
| import { Fn, int, float, vec2, vec3, vec4, If } from '../tsl/TSLBase.js'; | ||
| import { cos, sin, abs, max, exp2, log2, clamp, fract, mix, floor, normalize, cross } from '../math/MathNode.js'; | ||
| import { Fn, int, uint, float, vec2, vec3, vec4, If } from '../tsl/TSLBase.js'; | ||
| import { cos, sin, abs, max, exp2, log2, clamp, fract, mix, floor, normalize, cross, dot, sqrt } from '../math/MathNode.js'; | ||
| import { mul } from '../math/OperatorNode.js'; | ||
@@ -289,1 +289,116 @@ import { select } from '../math/ConditionalNode.js'; | ||
| } ); | ||
| // GGX VNDF importance sampling functions | ||
| // Van der Corput radical inverse for generating quasi-random sequences | ||
| const radicalInverse_VdC = /*@__PURE__*/ Fn( ( [ bits_immutable ] ) => { | ||
| const bits = uint( bits_immutable ).toVar(); | ||
| bits.assign( bits.shiftLeft( uint( 16 ) ).bitOr( bits.shiftRight( uint( 16 ) ) ) ); | ||
| bits.assign( bits.bitAnd( uint( 0x55555555 ) ).shiftLeft( uint( 1 ) ).bitOr( bits.bitAnd( uint( 0xAAAAAAAA ) ).shiftRight( uint( 1 ) ) ) ); | ||
| bits.assign( bits.bitAnd( uint( 0x33333333 ) ).shiftLeft( uint( 2 ) ).bitOr( bits.bitAnd( uint( 0xCCCCCCCC ) ).shiftRight( uint( 2 ) ) ) ); | ||
| bits.assign( bits.bitAnd( uint( 0x0F0F0F0F ) ).shiftLeft( uint( 4 ) ).bitOr( bits.bitAnd( uint( 0xF0F0F0F0 ) ).shiftRight( uint( 4 ) ) ) ); | ||
| bits.assign( bits.bitAnd( uint( 0x00FF00FF ) ).shiftLeft( uint( 8 ) ).bitOr( bits.bitAnd( uint( 0xFF00FF00 ) ).shiftRight( uint( 8 ) ) ) ); | ||
| return float( bits ).mul( 2.3283064365386963e-10 ); // / 0x100000000 | ||
| } ); | ||
| // Hammersley sequence for quasi-Monte Carlo sampling | ||
| const hammersley = /*@__PURE__*/ Fn( ( [ i, N ] ) => { | ||
| return vec2( float( i ).div( float( N ) ), radicalInverse_VdC( i ) ); | ||
| } ); | ||
| // GGX VNDF importance sampling (Eric Heitz 2018) | ||
| // "Sampling the GGX Distribution of Visible Normals" | ||
| // https://jcgt.org/published/0007/04/01/ | ||
| const importanceSampleGGX_VNDF = /*@__PURE__*/ Fn( ( [ Xi, V_immutable, roughness_immutable ] ) => { | ||
| const V = vec3( V_immutable ).toVar(); | ||
| const roughness = float( roughness_immutable ); | ||
| const alpha = roughness.mul( roughness ).toVar(); | ||
| // Section 3.2: Transform view direction to hemisphere configuration | ||
| const Vh = normalize( vec3( alpha.mul( V.x ), alpha.mul( V.y ), V.z ) ).toVar(); | ||
| // Section 4.1: Orthonormal basis | ||
| const lensq = Vh.x.mul( Vh.x ).add( Vh.y.mul( Vh.y ) ); | ||
| const T1 = select( lensq.greaterThan( 0.0 ), vec3( Vh.y.negate(), Vh.x, 0.0 ).div( sqrt( lensq ) ), vec3( 1.0, 0.0, 0.0 ) ).toVar(); | ||
| const T2 = cross( Vh, T1 ).toVar(); | ||
| // Section 4.2: Parameterization of projected area | ||
| const r = sqrt( Xi.x ); | ||
| const phi = mul( 2.0, 3.14159265359 ).mul( Xi.y ); | ||
| const t1 = r.mul( cos( phi ) ).toVar(); | ||
| const t2 = r.mul( sin( phi ) ).toVar(); | ||
| const s = mul( 0.5, Vh.z.add( 1.0 ) ); | ||
| t2.assign( s.oneMinus().mul( sqrt( t1.mul( t1 ).oneMinus() ) ).add( s.mul( t2 ) ) ); | ||
| // Section 4.3: Reprojection onto hemisphere | ||
| const Nh = T1.mul( t1 ).add( T2.mul( t2 ) ).add( Vh.mul( sqrt( max( 0.0, t1.mul( t1 ).add( t2.mul( t2 ) ).oneMinus() ) ) ) ); | ||
| // Section 3.4: Transform back to ellipsoid configuration | ||
| return normalize( vec3( alpha.mul( Nh.x ), alpha.mul( Nh.y ), max( 0.0, Nh.z ) ) ); | ||
| } ); | ||
| // GGX convolution using VNDF importance sampling | ||
| export const ggxConvolution = /*@__PURE__*/ Fn( ( { roughness, mipInt, envMap, N_immutable, GGX_SAMPLES, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP } ) => { | ||
| const N = vec3( N_immutable ).toVar(); | ||
| const prefilteredColor = vec3( 0.0 ).toVar(); | ||
| const totalWeight = float( 0.0 ).toVar(); | ||
| // For very low roughness, just sample the environment directly | ||
| If( roughness.lessThan( 0.001 ), () => { | ||
| prefilteredColor.assign( bilinearCubeUV( envMap, N, mipInt, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP ) ); | ||
| } ).Else( () => { | ||
| // Tangent space basis for VNDF sampling | ||
| const up = select( abs( N.z ).lessThan( 0.999 ), vec3( 0.0, 0.0, 1.0 ), vec3( 1.0, 0.0, 0.0 ) ); | ||
| const tangent = normalize( cross( up, N ) ).toVar(); | ||
| const bitangent = cross( N, tangent ).toVar(); | ||
| Loop( { start: uint( 0 ), end: GGX_SAMPLES }, ( { i } ) => { | ||
| const Xi = hammersley( i, GGX_SAMPLES ); | ||
| // For PMREM, V = N, so in tangent space V is always (0, 0, 1) | ||
| const H_tangent = importanceSampleGGX_VNDF( Xi, vec3( 0.0, 0.0, 1.0 ), roughness ); | ||
| // Transform H back to world space | ||
| const H = normalize( tangent.mul( H_tangent.x ).add( bitangent.mul( H_tangent.y ) ).add( N.mul( H_tangent.z ) ) ); | ||
| const L = normalize( H.mul( dot( N, H ).mul( 2.0 ) ).sub( N ) ); | ||
| const NdotL = max( dot( N, L ), 0.0 ); | ||
| If( NdotL.greaterThan( 0.0 ), () => { | ||
| // Sample environment at fixed mip level | ||
| // VNDF importance sampling handles the distribution filtering | ||
| const sampleColor = bilinearCubeUV( envMap, L, mipInt, CUBEUV_TEXEL_WIDTH, CUBEUV_TEXEL_HEIGHT, CUBEUV_MAX_MIP ); | ||
| // Weight by NdotL for the split-sum approximation | ||
| // VNDF PDF naturally accounts for the visible microfacet distribution | ||
| prefilteredColor.addAssign( sampleColor.mul( NdotL ) ); | ||
| totalWeight.addAssign( NdotL ); | ||
| } ); | ||
| } ); | ||
| If( totalWeight.greaterThan( 0.0 ), () => { | ||
| prefilteredColor.assign( prefilteredColor.div( totalWeight ) ); | ||
| } ); | ||
| } ); | ||
| return vec4( prefilteredColor, 1.0 ); | ||
| } ); |
@@ -19,3 +19,3 @@ import { Fn, float, select } from '../tsl/TSLBase.js'; | ||
| if ( material.alphaToCoverage && renderer.samples > 1 ) { | ||
| if ( material.alphaToCoverage && renderer.currentSamples > 0 ) { | ||
@@ -22,0 +22,0 @@ const dlen = float( len2.fwidth() ).toVar(); |
+1
-1
@@ -8,3 +8,3 @@ // constants | ||
| export * from './core/BypassNode.js'; | ||
| export * from './core/CacheNode.js'; | ||
| export * from './core/IsolateNode.js'; | ||
| export * from './core/ContextNode.js'; | ||
@@ -11,0 +11,0 @@ export * from './core/IndexNode.js'; |
@@ -0,1 +1,3 @@ | ||
| import { warn } from '../../utils.js'; | ||
| // Non-PURE exports list, side-effects are required here. | ||
@@ -20,3 +22,3 @@ // TSL Base Syntax | ||
| export * from '../gpgpu/ComputeNode.js'; // .compute() | ||
| export * from '../core/CacheNode.js'; // .cache() | ||
| export * from '../core/IsolateNode.js'; // .isolate() | ||
| export * from '../core/BypassNode.js'; // .bypass() | ||
@@ -29,7 +31,8 @@ export * from '../utils/RemapNode.js'; // .remap(), .remapClamp() | ||
| export * from '../core/SubBuildNode.js'; // subBuild() | ||
| export * from '../core/InspectorNode.js'; // inspector(), .toInspector() | ||
| export function addNodeElement( name/*, nodeElement*/ ) { | ||
| console.warn( 'THREE.TSL: AddNodeElement has been removed in favor of tree-shaking. Trying add', name ); | ||
| warn( 'TSL: AddNodeElement has been removed in favor of tree-shaking. Trying add', name ); | ||
| } |
+36
-15
@@ -11,2 +11,3 @@ import Node from '../core/Node.js'; | ||
| import { getValueFromType, getValueType } from '../core/NodeUtils.js'; | ||
| import { warn, error } from '../../utils.js'; | ||
@@ -23,3 +24,3 @@ let currentStack = null; | ||
| console.warn( `THREE.TSL: Redefinition of method chaining '${ name }'.` ); | ||
| warn( `TSL: Redefinition of method chaining '${ name }'.` ); | ||
| return; | ||
@@ -41,3 +42,3 @@ | ||
| return this.isStackNode ? this.add( nodeElement( ...params ) ) : nodeElement( this, ...params ); | ||
| return this.isStackNode ? this.addToStack( nodeElement( ...params ) ) : nodeElement( this, ...params ); | ||
@@ -71,3 +72,3 @@ }; | ||
| console.error( 'THREE.TSL: No stack defined for assign operation. Make sure the assign is inside a Fn().' ); | ||
| error( 'TSL: No stack defined for assign operation. Make sure the assign is inside a Fn().' ); | ||
@@ -82,3 +83,3 @@ } | ||
| return this.add( nodeElement( ...params ) ); | ||
| return this.addToStack( nodeElement( ...params ) ); | ||
@@ -381,3 +382,3 @@ } | ||
| console.error( `THREE.TSL: "${ tslName }" parameter length is less than minimum required.` ); | ||
| error( `TSL: "${ tslName }" parameter length is less than minimum required.` ); | ||
@@ -388,3 +389,3 @@ return params.concat( new Array( minParams - params.length ).fill( 0 ) ); | ||
| console.error( `THREE.TSL: "${ tslName }" parameter length exceeds limit.` ); | ||
| error( `TSL: "${ tslName }" parameter length exceeds limit.` ); | ||
@@ -473,2 +474,8 @@ return params.slice( 0, maxParams ); | ||
| getElementType( builder ) { | ||
| return this.getOutputNode( builder ).getElementType( builder ); | ||
| } | ||
| getMemberType( builder, name ) { | ||
@@ -498,4 +505,6 @@ | ||
| const previousSubBuildFn = builder.subBuildFn; | ||
| const previousFnCall = builder.fnCall; | ||
| builder.subBuildFn = subBuild; | ||
| builder.fnCall = this; | ||
@@ -576,2 +585,3 @@ let result = null; | ||
| builder.subBuildFn = previousSubBuildFn; | ||
| builder.fnCall = previousFnCall; | ||
@@ -620,2 +630,6 @@ if ( shaderNode.once ) { | ||
| const previousFnCall = builder.fnCall; | ||
| builder.fnCall = this; | ||
| if ( buildStage === 'setup' ) { | ||
@@ -668,2 +682,4 @@ | ||
| builder.fnCall = previousFnCall; | ||
| return result; | ||
@@ -802,5 +818,11 @@ | ||
| getLayout() { | ||
| return this.layout; | ||
| } | ||
| call( rawInputs = null ) { | ||
| return nodeObject( new ShaderCallNodeInternal( this, rawInputs ) ); | ||
| return new ShaderCallNodeInternal( this, rawInputs ); | ||
@@ -865,3 +887,3 @@ } | ||
| console.error( `THREE.TSL: Invalid parameter for the type "${ type }".` ); | ||
| error( `TSL: Invalid parameter for the type "${ type }".` ); | ||
@@ -929,3 +951,3 @@ return nodeObject( new ConstNode( 0, type ) ); | ||
| export const nodeImmutable = ( NodeClass, ...params ) => new ShaderNodeImmutable( NodeClass, ...params ); | ||
| export const nodeProxyIntent = ( NodeClass, scope = null, factor = null, settings = {} ) => new ShaderNodeProxy( NodeClass, scope, factor, { intent: true, ...settings } ); | ||
| export const nodeProxyIntent = ( NodeClass, scope = null, factor = null, settings = {} ) => new ShaderNodeProxy( NodeClass, scope, factor, { ...settings, intent: true } ); | ||
@@ -956,3 +978,3 @@ let fnId = 0; | ||
| console.error( 'THREE.TSL: Invalid layout type.' ); | ||
| error( 'TSL: Invalid layout type.' ); | ||
@@ -1041,3 +1063,3 @@ } | ||
| console.error( 'THREE.TSL: "Fn()" was declared but not invoked. Try calling it like "Fn()( ...params )".' ); | ||
| error( 'TSL: "Fn()" was declared but not invoked. Try calling it like "Fn()( ...params )".' ); | ||
@@ -1133,3 +1155,3 @@ return builder.generateConst( type ); | ||
| if ( currentStack ) currentStack.add( node ); | ||
| if ( currentStack ) currentStack.addToStack( node ); | ||
@@ -1215,3 +1237,3 @@ return node; | ||
| console.warn( 'THREE.TSL: append() has been renamed to Stack().' ); | ||
| warn( 'TSL: append() has been renamed to Stack().' ); | ||
| return Stack( node ); | ||
@@ -1223,6 +1245,5 @@ | ||
| console.warn( 'THREE.TSL: .append() has been renamed to .toStack().' ); | ||
| warn( 'TSL: .append() has been renamed to .toStack().' ); | ||
| return Stack( node ); | ||
| } ); | ||
| import TempNode from '../core/TempNode.js'; | ||
| import { addMethodChaining, nodeObject } from '../tsl/TSLCore.js'; | ||
| import { log } from '../../utils.js'; | ||
@@ -59,3 +60,3 @@ class DebugNode extends TempNode { | ||
| console.log( code ); | ||
| log( code ); | ||
@@ -62,0 +63,0 @@ } |
@@ -39,2 +39,10 @@ import Node from '../core/Node.js'; | ||
| } else if ( eventType === EventNode.BEFORE_OBJECT ) { | ||
| this.updateBeforeType = NodeUpdateType.OBJECT; | ||
| } else if ( eventType === EventNode.BEFORE_MATERIAL ) { | ||
| this.updateBeforeType = NodeUpdateType.RENDER; | ||
| } | ||
@@ -50,2 +58,8 @@ | ||
| updateBefore( frame ) { | ||
| this.callback( frame ); | ||
| } | ||
| } | ||
@@ -55,2 +69,4 @@ | ||
| EventNode.MATERIAL = 'material'; | ||
| EventNode.BEFORE_OBJECT = 'beforeObject'; | ||
| EventNode.BEFORE_MATERIAL = 'beforeMaterial'; | ||
@@ -87,1 +103,21 @@ export default EventNode; | ||
| export const OnMaterialUpdate = ( callback ) => createEvent( EventNode.MATERIAL, callback ); | ||
| /** | ||
| * Creates an event that triggers a function before an object (Mesh|Sprite) is updated. | ||
| * | ||
| * The event will be bound to the declared TSL function `Fn()`; it must be declared within a `Fn()` or the JS function call must be inherited from one. | ||
| * | ||
| * @param {Function} callback - The callback function. | ||
| * @returns {EventNode} | ||
| */ | ||
| export const OnBeforeObjectUpdate = ( callback ) => createEvent( EventNode.BEFORE_OBJECT, callback ); | ||
| /** | ||
| * Creates an event that triggers a function before the material is updated. | ||
| * | ||
| * The event will be bound to the declared TSL function `Fn()`; it must be declared within a `Fn()` or the JS function call must be inherited from one. | ||
| * | ||
| * @param {Function} callback - The callback function. | ||
| * @returns {EventNode} | ||
| */ | ||
| export const OnBeforeMaterialUpdate = ( callback ) => createEvent( EventNode.BEFORE_MATERIAL, callback ); |
@@ -49,3 +49,3 @@ import Node from '../core/Node.js'; | ||
| */ | ||
| this._candidateFnCall = null; | ||
| this._candidateFn = null; | ||
@@ -69,18 +69,26 @@ /** | ||
| */ | ||
| getNodeType() { | ||
| getNodeType( builder ) { | ||
| return this.functionNodes[ 0 ].shaderNode.layout.type; | ||
| const candidateFn = this.getCandidateFn( builder ); | ||
| return candidateFn.shaderNode.layout.type; | ||
| } | ||
| setup( builder ) { | ||
| /** | ||
| * Returns the candidate function for the current parameters. | ||
| * | ||
| * @param {NodeBuilder} builder - The current node builder. | ||
| * @return {FunctionNode} The candidate function. | ||
| */ | ||
| getCandidateFn( builder ) { | ||
| const params = this.parametersNodes; | ||
| let candidateFnCall = this._candidateFnCall; | ||
| let candidateFn = this._candidateFn; | ||
| if ( candidateFnCall === null ) { | ||
| if ( candidateFn === null ) { | ||
| let candidateFn = null; | ||
| let candidateScore = - 1; | ||
| let bestCandidateFn = null; | ||
| let bestScore = - 1; | ||
@@ -102,3 +110,3 @@ for ( const functionNode of this.functionNodes ) { | ||
| let score = 0; | ||
| let currentScore = 0; | ||
@@ -112,8 +120,4 @@ for ( let i = 0; i < params.length; i ++ ) { | ||
| score ++; | ||
| currentScore ++; | ||
| } else { | ||
| score = 0; | ||
| } | ||
@@ -123,6 +127,6 @@ | ||
| if ( score > candidateScore ) { | ||
| if ( currentScore > bestScore ) { | ||
| candidateFn = functionNode; | ||
| candidateScore = score; | ||
| bestCandidateFn = functionNode; | ||
| bestScore = currentScore; | ||
@@ -135,10 +139,24 @@ } | ||
| this._candidateFnCall = candidateFnCall = candidateFn( ...params ); | ||
| this._candidateFn = candidateFn = bestCandidateFn; | ||
| } | ||
| return candidateFnCall; | ||
| return candidateFn; | ||
| } | ||
| /** | ||
| * Sets up the node for the current parameters. | ||
| * | ||
| * @param {NodeBuilder} builder - The current node builder. | ||
| * @return {Node} The setup node. | ||
| */ | ||
| setup( builder ) { | ||
| const candidateFn = this.getCandidateFn( builder ); | ||
| return candidateFn( ...this.parametersNodes ); | ||
| } | ||
| } | ||
@@ -145,0 +163,0 @@ |
| import TempNode from '../core/TempNode.js'; | ||
| import { error } from '../../utils.js'; | ||
@@ -73,3 +74,3 @@ /** | ||
| console.error( `THREE.TSL: Length of parameters exceeds maximum length of function '${ type }()' type.` ); | ||
| error( `TSL: Length of parameters exceeds maximum length of function '${ type }()' type.` ); | ||
| break; | ||
@@ -85,3 +86,3 @@ | ||
| console.error( `THREE.TSL: Length of '${ type }()' data exceeds maximum length of output type.` ); | ||
| error( `TSL: Length of '${ type }()' data exceeds maximum length of output type.` ); | ||
@@ -88,0 +89,0 @@ inputTypeLength = maxLength - length; |
| import Node from '../core/Node.js'; | ||
| import { expression } from '../code/ExpressionNode.js'; | ||
| import { nodeObject, nodeArray, Fn } from '../tsl/TSLBase.js'; | ||
| import { nodeArray, Fn } from '../tsl/TSLBase.js'; | ||
| import { error } from '../../utils.js'; | ||
@@ -56,3 +57,3 @@ /** | ||
| super(); | ||
| super( 'void' ); | ||
@@ -103,5 +104,7 @@ this.params = params; | ||
| const stack = builder.addStack(); // TODO: cache() it | ||
| const stack = builder.addStack(); | ||
| properties.returnsNode = this.params[ this.params.length - 1 ]( inputs, builder ); | ||
| const fnCall = this.params[ this.params.length - 1 ]( inputs ); | ||
| properties.returnsNode = fnCall.context( { nodeLoop: fnCall } ); | ||
| properties.stackNode = stack; | ||
@@ -113,4 +116,6 @@ | ||
| properties.updateNode = Fn( this.params[ 0 ].update )( inputs ); | ||
| const fnUpdateCall = Fn( this.params[ 0 ].update )( inputs ); | ||
| properties.updateNode = fnUpdateCall.context( { nodeLoop: fnUpdateCall } ); | ||
| } | ||
@@ -124,22 +129,15 @@ | ||
| /** | ||
| * This method is overwritten since the node type is inferred based on the loop configuration. | ||
| * | ||
| * @param {NodeBuilder} builder - The current node builder. | ||
| * @return {string} The node type. | ||
| */ | ||
| getNodeType( builder ) { | ||
| setup( builder ) { | ||
| const { returnsNode } = this.getProperties( builder ); | ||
| // setup properties | ||
| return returnsNode ? returnsNode.getNodeType( builder ) : 'void'; | ||
| this.getProperties( builder ); | ||
| } | ||
| if ( builder.fnCall ) { | ||
| setup( builder ) { | ||
| const shaderNodeData = builder.getDataFromNode( builder.fnCall.shaderNode ); | ||
| shaderNodeData.hasLoop = true; | ||
| // setup properties | ||
| } | ||
| this.getProperties( builder ); | ||
| } | ||
@@ -274,3 +272,3 @@ | ||
| console.error( 'THREE.TSL: \'Loop( { update: ... } )\' is not a function, string or number.' ); | ||
| error( 'TSL: \'Loop( { update: ... } )\' is not a function, string or number.' ); | ||
@@ -312,3 +310,3 @@ updateSnippet = 'break /* invalid update */'; | ||
| const returnsSnippet = properties.returnsNode ? properties.returnsNode.build( builder ) : ''; | ||
| properties.returnsNode.build( builder, 'void' ); | ||
@@ -325,4 +323,2 @@ builder.removeFlowTab().addFlowCode( '\n' + builder.tab + stackSnippet ); | ||
| return returnsSnippet; | ||
| } | ||
@@ -342,3 +338,3 @@ | ||
| */ | ||
| export const Loop = ( ...params ) => nodeObject( new LoopNode( nodeArray( params, 'int' ) ) ).toStack(); | ||
| export const Loop = ( ...params ) => new LoopNode( nodeArray( params, 'int' ) ).toStack(); | ||
@@ -345,0 +341,0 @@ /** |
| import Node from '../core/Node.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -103,3 +104,3 @@ /** | ||
| console.warn( `THREE.TSL: Member "${ this.property }" does not exist in struct.` ); | ||
| warn( `TSL: Member "${ this.property }" does not exist in struct.` ); | ||
@@ -106,0 +107,0 @@ const type = this.getNodeType( builder ); |
@@ -1,2 +0,2 @@ | ||
| import { abs, cross, float, Fn, normalize, ivec2, sub, vec2, vec3, vec4 } from '../tsl/TSLBase.js'; | ||
| import { abs, cross, float, Fn, normalize, ivec2, sub, vec2, vec3, vec4, fract, dot } from '../tsl/TSLBase.js'; | ||
| import { textureSize } from '../accessors/TextureSizeNode.js'; | ||
@@ -96,1 +96,28 @@ import { textureLoad } from '../accessors/TextureNode.js'; | ||
| } ); | ||
| /** | ||
| * Interleaved Gradient Noise (IGN) from Jimenez 2014. | ||
| * | ||
| * IGN has "low discrepancy" resulting in evenly distributed samples. It's superior compared to | ||
| * default white noise, blue noise or Bayer. | ||
| * | ||
| * References: | ||
| * - {@link https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare/} | ||
| * - {@link https://blog.demofox.org/2022/01/01/interleaved-gradient-noise-a-different-kind-of-low-discrepancy-sequence/} | ||
| * | ||
| * @tsl | ||
| * @function | ||
| * @param {Node<vec2>} position - The input position, usually screen coordinates. | ||
| * @return {Node<float>} The noise value. | ||
| */ | ||
| export const interleavedGradientNoise = Fn( ( [ position ] ) => { | ||
| return fract( float( 52.9829189 ).mul( fract( dot( position, vec2( 0.06711056, 0.00583715 ) ) ) ) ); | ||
| } ).setLayout( { | ||
| name: 'interleavedGradientNoise', | ||
| type: 'float', | ||
| inputs: [ | ||
| { name: 'position', type: 'vec2' } | ||
| ] | ||
| } ); |
@@ -167,2 +167,3 @@ import Node from '../core/Node.js'; | ||
| newNode.gradNode = this.gradNode; | ||
| newNode.offsetNode = this.offsetNode; | ||
| newNode._reflectorBaseNode = this._reflectorBaseNode; | ||
@@ -254,3 +255,3 @@ | ||
| warnOnce( 'THREE.ReflectorNode: The "resolution" parameter has been renamed to "resolutionScale".' ); // @deprecated r180 | ||
| warnOnce( 'ReflectorNode: The "resolution" parameter has been renamed to "resolutionScale".' ); // @deprecated r180 | ||
@@ -556,2 +557,6 @@ this.resolutionScale = parameters.resolution; | ||
| const previousName = scene.name; | ||
| scene.name = ( scene.name || 'Scene' ) + ' [ Reflector ]'; // TODO: Add bounce index | ||
| if ( needsClear ) { | ||
@@ -571,2 +576,4 @@ | ||
| scene.name = previousName; | ||
| renderer.setMRT( currentMRT ); | ||
@@ -593,3 +600,3 @@ renderer.setRenderTarget( currentRenderTarget ); | ||
| warnOnce( 'THREE.ReflectorNode: The "resolution" property has been renamed to "resolutionScale".' ); // @deprecated r180 | ||
| warnOnce( 'ReflectorNode: The "resolution" property has been renamed to "resolutionScale".' ); // @deprecated r180 | ||
@@ -602,3 +609,3 @@ return this.resolutionScale; | ||
| warnOnce( 'THREE.ReflectorNode: The "resolution" property has been renamed to "resolutionScale".' ); // @deprecated r180 | ||
| warnOnce( 'ReflectorNode: The "resolution" property has been renamed to "resolutionScale".' ); // @deprecated r180 | ||
@@ -605,0 +612,0 @@ this.resolutionScale = value; |
@@ -205,4 +205,4 @@ import { nodeObject } from '../tsl/TSLCore.js'; | ||
| const effectiveWidth = size.width * pixelRatio; | ||
| const effectiveHeight = size.height * pixelRatio; | ||
| const effectiveWidth = Math.floor( size.width * pixelRatio ); | ||
| const effectiveHeight = Math.floor( size.height * pixelRatio ); | ||
@@ -221,3 +221,13 @@ if ( effectiveWidth !== this.renderTarget.width || effectiveHeight !== this.renderTarget.height ) { | ||
| let name = 'RTT'; | ||
| if ( this.node.name ) { | ||
| name = this.node.name + ' [ ' + name + ' ]'; | ||
| } | ||
| this._quadMesh.material.fragmentNode = this._rttNode; | ||
| this._quadMesh.name = name; | ||
@@ -224,0 +234,0 @@ // |
@@ -9,2 +9,3 @@ import { Sphere } from '../math/Sphere.js'; | ||
| import { Float32BufferAttribute } from '../core/BufferAttribute.js'; | ||
| import { warn } from '../utils.js'; | ||
@@ -146,3 +147,3 @@ const _vStart = /*@__PURE__*/ new Vector3(); | ||
| console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); | ||
| warn( 'Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); | ||
@@ -149,0 +150,0 @@ } |
| import { Line } from './Line.js'; | ||
| import { Vector3 } from '../math/Vector3.js'; | ||
| import { Float32BufferAttribute } from '../core/BufferAttribute.js'; | ||
| import { warn } from '../utils.js'; | ||
@@ -63,3 +64,3 @@ const _start = /*@__PURE__*/ new Vector3(); | ||
| console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); | ||
| warn( 'LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); | ||
@@ -66,0 +67,0 @@ } |
@@ -9,2 +9,3 @@ import { | ||
| import { generateUUID } from '../math/MathUtils.js'; | ||
| import { warn } from '../utils.js'; | ||
@@ -110,3 +111,3 @@ const _offsetMatrix = /*@__PURE__*/ new Matrix4(); | ||
| console.warn( 'THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.' ); | ||
| warn( 'Skeleton: Number of inverse bone matrices does not match amount of bones.' ); | ||
@@ -329,3 +330,3 @@ this.boneInverses = []; | ||
| console.warn( 'THREE.Skeleton: No bone found with UUID:', uuid ); | ||
| warn( 'Skeleton: No bone found with UUID:', uuid ); | ||
| bone = new Bone(); | ||
@@ -332,0 +333,0 @@ |
@@ -9,2 +9,3 @@ import { Mesh } from './Mesh.js'; | ||
| import { AttachedBindMode, DetachedBindMode } from '../constants.js'; | ||
| import { warn } from '../utils.js'; | ||
@@ -36,2 +37,3 @@ const _basePosition = /*@__PURE__*/ new Vector3(); | ||
| * @augments Mesh | ||
| * @demo scenes/bones-browser.html | ||
| */ | ||
@@ -304,3 +306,3 @@ class SkinnedMesh extends Mesh { | ||
| console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode ); | ||
| warn( 'SkinnedMesh: Unrecognized bindMode: ' + this.bindMode ); | ||
@@ -307,0 +309,0 @@ } |
@@ -10,2 +10,3 @@ import { Vector2 } from '../math/Vector2.js'; | ||
| import { SpriteMaterial } from '../materials/SpriteMaterial.js'; | ||
| import { error } from '../utils.js'; | ||
@@ -133,3 +134,3 @@ let _geometry; | ||
| console.error( 'THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' ); | ||
| error( 'Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' ); | ||
@@ -136,0 +137,0 @@ } |
@@ -12,8 +12,16 @@ | ||
| * | ||
| * @param {Renderer} renderer - A reference to the main renderer. | ||
| * @param {Nodes} nodes - Renderer component for managing nodes related logic. | ||
| * @param {Info} info - Renderer component for managing metrics and monitoring data. | ||
| */ | ||
| constructor( nodes, info ) { | ||
| constructor( renderer, nodes, info ) { | ||
| /** | ||
| * A reference to the main renderer. | ||
| * | ||
| * @type {Renderer} | ||
| */ | ||
| this.renderer = renderer; | ||
| /** | ||
| * Renderer component for managing nodes related logic. | ||
@@ -74,4 +82,8 @@ * | ||
| this.renderer._inspector.begin(); | ||
| if ( this._animationLoop !== null ) this._animationLoop( time, xrFrame ); | ||
| this.renderer._inspector.finish(); | ||
| }; | ||
@@ -78,0 +90,0 @@ |
@@ -7,3 +7,3 @@ let _vector2 = null; | ||
| import { createCanvasElement, warnOnce } from '../../utils.js'; | ||
| import { REVISION } from '../../constants.js'; | ||
| import { REVISION, TimestampQuery } from '../../constants.js'; | ||
@@ -68,4 +68,4 @@ /** | ||
| this.timestampQueryPool = { | ||
| 'render': null, | ||
| 'compute': null | ||
| [ TimestampQuery.RENDER ]: null, | ||
| [ TimestampQuery.COMPUTE ]: null | ||
| }; | ||
@@ -278,18 +278,11 @@ | ||
| /** | ||
| * Creates a GPU sampler for the given texture. | ||
| * Updates a GPU sampler for the given texture. | ||
| * | ||
| * @abstract | ||
| * @param {Texture} texture - The texture to create the sampler for. | ||
| * @param {Texture} texture - The texture to update the sampler for. | ||
| * @return {string} The current sampler key. | ||
| */ | ||
| createSampler( /*texture*/ ) { } | ||
| updateSampler( /*texture*/ ) { } | ||
| /** | ||
| * Destroys the GPU sampler for the given texture. | ||
| * | ||
| * @abstract | ||
| * @param {Texture} texture - The texture to destroy the sampler for. | ||
| */ | ||
| destroySampler( /*texture*/ ) {} | ||
| /** | ||
| * Creates a default texture for the given texture that can be used | ||
@@ -334,4 +327,5 @@ * as a placeholder until the actual texture is ready for usage. | ||
| * @param {Texture} texture - The texture. | ||
| * @param {boolean} [isDefaultTexture=false] - Whether the texture uses a default GPU texture or not. | ||
| */ | ||
| destroyTexture( /*texture*/ ) { } | ||
| destroyTexture( /*texture, isDefaultTexture*/ ) { } | ||
@@ -447,2 +441,29 @@ /** | ||
| /** | ||
| * Updates a unique identifier for the given render context that can be used | ||
| * to allocate resources like occlusion queries or timestamp queries. | ||
| * | ||
| * @param {RenderContext|ComputeNode} abstractRenderContext - The render context. | ||
| */ | ||
| updateTimeStampUID( abstractRenderContext ) { | ||
| const contextData = this.get( abstractRenderContext ); | ||
| const frame = this.renderer.info.frame; | ||
| let prefix; | ||
| if ( abstractRenderContext.isComputeNode === true ) { | ||
| prefix = 'c:' + this.renderer.info.compute.frameCalls; | ||
| } else { | ||
| prefix = 'r:' + this.renderer.info.render.frameCalls; | ||
| } | ||
| contextData.timestampUID = prefix + ':' + abstractRenderContext.id + ':f' + frame; | ||
| } | ||
| /** | ||
| * Returns a unique identifier for the given render context that can be used | ||
@@ -456,12 +477,64 @@ * to allocate resources like occlusion queries or timestamp queries. | ||
| const contextData = this.get( abstractRenderContext ); | ||
| return this.get( abstractRenderContext ).timestampUID; | ||
| let uid = abstractRenderContext.isComputeNode === true ? 'c' : 'r'; | ||
| uid += ':' + contextData.frameCalls + ':' + abstractRenderContext.id; | ||
| } | ||
| return uid; | ||
| /** | ||
| * Returns all timestamp frames for the given type. | ||
| * | ||
| * @param {string} type - The type of the time stamp. | ||
| * @return {Array<number>} The timestamp frames. | ||
| */ | ||
| getTimestampFrames( type ) { | ||
| const queryPool = this.timestampQueryPool[ type ]; | ||
| return queryPool ? queryPool.getTimestampFrames() : []; | ||
| } | ||
| /** | ||
| * Returns the query pool for the given uid. | ||
| * | ||
| * @param {string} uid - The unique identifier. | ||
| * @return {TimestampQueryPool} The query pool. | ||
| */ | ||
| _getQueryPool( uid ) { | ||
| const type = uid.startsWith( 'c:' ) ? TimestampQuery.COMPUTE : TimestampQuery.RENDER; | ||
| const queryPool = this.timestampQueryPool[ type ]; | ||
| return queryPool; | ||
| } | ||
| /** | ||
| * Returns the timestamp for the given uid. | ||
| * | ||
| * @param {string} uid - The unique identifier. | ||
| * @return {number} The timestamp. | ||
| */ | ||
| getTimestamp( uid ) { | ||
| const queryPool = this._getQueryPool( uid ); | ||
| return queryPool.getTimestamp( uid ); | ||
| } | ||
| /** | ||
| * Returns `true` if a timestamp for the given uid is available. | ||
| * | ||
| * @param {string} uid - The unique identifier. | ||
| * @return {boolean} Whether the timestamp is available or not. | ||
| */ | ||
| hasTimestamp( uid ) { | ||
| const queryPool = this._getQueryPool( uid ); | ||
| return queryPool.hasTimestamp( uid ); | ||
| } | ||
| /** | ||
| * Returns `true` if the given 3D object is fully occluded by other | ||
@@ -496,5 +569,5 @@ * 3D objects in the scene. Backends must implement this method by using | ||
| const queryPool = this.timestampQueryPool[ type ]; | ||
| if ( ! queryPool ) { | ||
| warnOnce( `WebGPURenderer: No timestamp query pool for type '${type}' found.` ); | ||
| return; | ||
@@ -513,12 +586,2 @@ | ||
| /** | ||
| * Can be used to synchronize CPU operations with GPU tasks. So when this method is called, | ||
| * the CPU waits for the GPU to complete its operation (e.g. a compute task). | ||
| * | ||
| * @async | ||
| * @abstract | ||
| * @return {Promise} A Promise that resolves when synchronization has been finished. | ||
| */ | ||
| async waitForGPU() {} | ||
| /** | ||
| * This method performs a readback operation by moving buffer data from | ||
@@ -525,0 +588,0 @@ * a storage buffer attribute from the GPU to the CPU. |
@@ -9,2 +9,3 @@ import DataMap from './DataMap.js'; | ||
| import { BackSide } from '../../constants.js'; | ||
| import { error } from '../../utils.js'; | ||
@@ -152,3 +153,3 @@ const _clearColor = /*@__PURE__*/ new Color4(); | ||
| console.error( 'THREE.Renderer: Unsupported background configuration.', background ); | ||
| error( 'Renderer: Unsupported background configuration.', background ); | ||
@@ -155,0 +156,0 @@ } |
@@ -157,2 +157,36 @@ import DataMap from './DataMap.js'; | ||
| /** | ||
| * Deletes the bindings for the given compute node. | ||
| * | ||
| * @param {Node} computeNode - The compute node. | ||
| */ | ||
| deleteForCompute( computeNode ) { | ||
| const bindings = this.nodes.getForCompute( computeNode ).bindings; | ||
| for ( const bindGroup of bindings ) { | ||
| this.delete( bindGroup ); | ||
| } | ||
| } | ||
| /** | ||
| * Deletes the bindings for the given renderObject node. | ||
| * | ||
| * @param {RenderObject} renderObject - The renderObject. | ||
| */ | ||
| deleteForRender( renderObject ) { | ||
| const bindings = renderObject.getBindings(); | ||
| for ( const bindGroup of bindings ) { | ||
| this.delete( bindGroup ); | ||
| } | ||
| } | ||
| /** | ||
| * Updates the given array of bindings. | ||
@@ -185,2 +219,6 @@ * | ||
| } else if ( binding.isSampler ) { | ||
| this.textures.updateSampler( binding.texture ); | ||
| } else if ( binding.isStorageBuffer ) { | ||
@@ -291,3 +329,3 @@ | ||
| if ( texture.isStorageTexture === true ) { | ||
| if ( texture.isStorageTexture === true && texture.mipmapsAutoUpdate === true ) { | ||
@@ -312,4 +350,20 @@ const textureData = this.get( texture ); | ||
| binding.update(); | ||
| const updated = binding.update(); | ||
| if ( updated ) { | ||
| const samplerKey = this.textures.updateSampler( binding.texture ); | ||
| if ( binding.samplerKey !== samplerKey ) { | ||
| binding.samplerKey = samplerKey; | ||
| needsBindingsUpdate = true; | ||
| cacheBindings = false; | ||
| } | ||
| } | ||
| } | ||
@@ -316,0 +370,0 @@ |
| import NodeMaterial from '../../../materials/nodes/NodeMaterial.js'; | ||
| import { getDirection, blur } from '../../../nodes/pmrem/PMREMUtils.js'; | ||
| import { getDirection, blur, ggxConvolution } from '../../../nodes/pmrem/PMREMUtils.js'; | ||
| import { equirectUV } from '../../../nodes/utils/EquirectUV.js'; | ||
@@ -8,3 +8,3 @@ import { uniform } from '../../../nodes/core/UniformNode.js'; | ||
| import { cubeTexture } from '../../../nodes/accessors/CubeTextureNode.js'; | ||
| import { float, vec3 } from '../../../nodes/tsl/TSLBase.js'; | ||
| import { float, uint, vec3 } from '../../../nodes/tsl/TSLBase.js'; | ||
| import { uv } from '../../../nodes/accessors/UV.js'; | ||
@@ -34,9 +34,8 @@ import { attribute } from '../../../nodes/core/AttributeNode.js'; | ||
| } from '../../../constants.js'; | ||
| import { warn, error, warnOnce } from '../../../utils.js'; | ||
| const LOD_MIN = 4; | ||
| // The standard deviations (radians) associated with the extra mips. These are | ||
| // chosen to approximate a Trowbridge-Reitz distribution function times the | ||
| // geometric shadowing function. These sigma values squared must match the | ||
| // variance #defines in cube_uv_reflection_fragment.glsl.js. | ||
| // The standard deviations (radians) associated with the extra mips. | ||
| // Used for scene blur in fromScene() method. | ||
| const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ]; | ||
@@ -46,4 +45,8 @@ | ||
| // samples and exit early, but not recompile the shader. | ||
| // Used for scene blur in fromScene() method. | ||
| const MAX_SAMPLES = 20; | ||
| // GGX VNDF importance sampling configuration | ||
| const GGX_SAMPLES = 512; | ||
| const _flatCamera = /*@__PURE__*/ new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); | ||
@@ -56,21 +59,2 @@ const _cubeCamera = /*@__PURE__*/ new PerspectiveCamera( 90, 1 ); | ||
| // Golden Ratio | ||
| const PHI = ( 1 + Math.sqrt( 5 ) ) / 2; | ||
| const INV_PHI = 1 / PHI; | ||
| // Vertices of a dodecahedron (except the opposites, which represent the | ||
| // same axis), used as axis directions evenly spread on a sphere. | ||
| const _axisDirections = [ | ||
| /*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ), | ||
| /*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ), | ||
| /*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ), | ||
| /*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ), | ||
| /*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ), | ||
| /*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ), | ||
| /*@__PURE__*/ new Vector3( - 1, 1, - 1 ), | ||
| /*@__PURE__*/ new Vector3( 1, 1, - 1 ), | ||
| /*@__PURE__*/ new Vector3( - 1, 1, 1 ), | ||
| /*@__PURE__*/ new Vector3( 1, 1, 1 ) | ||
| ]; | ||
| const _origin = /*@__PURE__*/ new Vector3(); | ||
@@ -102,5 +86,7 @@ | ||
| * | ||
| * Paper: Fast, Accurate Image-Based Lighting: | ||
| * {@link https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view} | ||
| */ | ||
| * The prefiltering uses GGX VNDF (Visible Normal Distribution Function) | ||
| * importance sampling based on "Sampling the GGX Distribution of Visible Normals" | ||
| * (Heitz, 2018) to generate environment maps that accurately match the GGX BRDF | ||
| * used in material rendering for physically-based image-based lighting. | ||
| */ | ||
| class PMREMGenerator { | ||
@@ -120,3 +106,2 @@ | ||
| this._cubeSize = 0; | ||
| this._lodPlanes = []; | ||
| this._sizeLods = []; | ||
@@ -127,2 +112,4 @@ this._sigmas = []; | ||
| this._blurMaterial = null; | ||
| this._ggxMaterial = null; | ||
| this._cubemapMaterial = null; | ||
@@ -155,3 +142,3 @@ this._equirectMaterial = null; | ||
| * @return {RenderTarget} The resulting PMREM. | ||
| * @see {@link PMREMGenerator#fromSceneAsync} | ||
| * @see {@link PMREMGenerator#fromScene} | ||
| */ | ||
@@ -170,3 +157,3 @@ fromScene( scene, sigma = 0, near = 0.1, far = 100, options = {} ) { | ||
| console.warn( 'THREE.PMREMGenerator: .fromScene() called before the backend is initialized. Try using .fromSceneAsync() instead.' ); | ||
| warn( 'PMREMGenerator: ".fromScene()" called before the backend is initialized. Try using "await renderer.init()" instead.' ); | ||
@@ -215,2 +202,3 @@ const cubeUVRenderTarget = renderTarget || this._allocateTarget(); | ||
| * | ||
| * @deprecated | ||
| * @param {Scene} scene - The scene to be captured. | ||
@@ -229,4 +217,6 @@ * @param {number} [sigma=0] - The blur radius in radians. | ||
| if ( this._hasInitialized === false ) await this._renderer.init(); | ||
| warnOnce( 'PMREMGenerator: ".fromSceneAsync()" is deprecated. Use "await renderer.init()" instead.' ); // @deprecated r181 | ||
| await this._renderer.init(); | ||
| return this.fromScene( scene, sigma, near, far, options ); | ||
@@ -250,3 +240,3 @@ | ||
| console.warn( 'THREE.PMREMGenerator: .fromEquirectangular() called before the backend is initialized. Try using .fromEquirectangularAsync() instead.' ); | ||
| warn( 'PMREMGenerator: .fromEquirectangular() called before the backend is initialized. Try using "await renderer.init()" instead.' ); | ||
@@ -272,2 +262,3 @@ this._setSizeFromTexture( equirectangular ); | ||
| * | ||
| * @deprecated | ||
| * @param {Texture} equirectangular - The equirectangular texture to be converted. | ||
@@ -280,4 +271,6 @@ * @param {?RenderTarget} [renderTarget=null] - The render target to use. | ||
| if ( this._hasInitialized === false ) await this._renderer.init(); | ||
| warnOnce( 'PMREMGenerator: ".fromEquirectangularAsync()" is deprecated. Use "await renderer.init()" instead.' ); // @deprecated r181 | ||
| await this._renderer.init(); | ||
| return this._fromTexture( equirectangular, renderTarget ); | ||
@@ -301,3 +294,3 @@ | ||
| console.warn( 'THREE.PMREMGenerator: .fromCubemap() called before the backend is initialized. Try using .fromCubemapAsync() instead.' ); | ||
| warn( 'PMREMGenerator: .fromCubemap() called before the backend is initialized. Try using .fromCubemapAsync() instead.' ); | ||
@@ -323,2 +316,3 @@ this._setSizeFromTexture( cubemap ); | ||
| * | ||
| * @deprecated | ||
| * @param {Texture} cubemap - The cubemap texture to be converted. | ||
@@ -331,4 +325,6 @@ * @param {?RenderTarget} [renderTarget=null] - The render target to use. | ||
| if ( this._hasInitialized === false ) await this._renderer.init(); | ||
| warnOnce( 'PMREMGenerator: ".fromCubemapAsync()" is deprecated. Use "await renderer.init()" instead.' ); // @deprecated r181 | ||
| await this._renderer.init(); | ||
| return this._fromTexture( cubemap, renderTarget ); | ||
@@ -418,8 +414,9 @@ | ||
| if ( this._blurMaterial !== null ) this._blurMaterial.dispose(); | ||
| if ( this._ggxMaterial !== null ) this._ggxMaterial.dispose(); | ||
| if ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose(); | ||
| for ( let i = 0; i < this._lodPlanes.length; i ++ ) { | ||
| for ( let i = 0; i < this._lodMeshes.length; i ++ ) { | ||
| this._lodPlanes[ i ].dispose(); | ||
| this._lodMeshes[ i ].geometry.dispose(); | ||
@@ -480,3 +477,3 @@ } | ||
| const { _lodMax } = this; | ||
| ( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas, lodMeshes: this._lodMeshes } = _createPlanes( _lodMax ) ); | ||
| ( { lodMeshes: this._lodMeshes, sizeLods: this._sizeLods, sigmas: this._sigmas } = _createPlanes( _lodMax ) ); | ||
@@ -491,4 +488,4 @@ this._blurMaterial = _getBlurShader( _lodMax, renderTarget.width, renderTarget.height ); | ||
| const tmpMesh = new Mesh( this._lodPlanes[ 0 ], material ); | ||
| await this._renderer.compile( tmpMesh, _flatCamera ); | ||
| const mesh = new Mesh( new BufferGeometry(), material ); | ||
| await this._renderer.compile( mesh, _flatCamera ); | ||
@@ -515,18 +512,21 @@ } | ||
| let backgroundBox = this._backgroundBox; | ||
| if ( this._backgroundBox === null ) { | ||
| if ( backgroundBox === null ) { | ||
| this._backgroundBox = new Mesh( | ||
| new BoxGeometry(), | ||
| new MeshBasicMaterial( { | ||
| name: 'PMREM.Background', | ||
| side: BackSide, | ||
| depthWrite: false, | ||
| depthTest: false, | ||
| } ) | ||
| ); | ||
| const backgroundMaterial = new MeshBasicMaterial( { | ||
| name: 'PMREM.Background', | ||
| side: BackSide, | ||
| depthWrite: false, | ||
| depthTest: false | ||
| } ); | ||
| } | ||
| backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial ); | ||
| const backgroundBox = this._backgroundBox; | ||
| const backgroundMaterial = backgroundBox.material; | ||
| } | ||
| let useSolidColor = false; | ||
| let useSolidColor = false; | ||
| const background = scene.background; | ||
@@ -538,3 +538,3 @@ | ||
| backgroundBox.material.color.copy( background ); | ||
| backgroundMaterial.color.copy( background ); | ||
| scene.background = null; | ||
@@ -547,3 +547,3 @@ useSolidColor = true; | ||
| backgroundBox.material.color.copy( _clearColor ); | ||
| backgroundMaterial.color.copy( _clearColor ); | ||
| useSolidColor = true; | ||
@@ -646,16 +646,80 @@ | ||
| renderer.autoClear = false; | ||
| const n = this._lodPlanes.length; | ||
| const n = this._lodMeshes.length; | ||
| // Use GGX VNDF importance sampling | ||
| for ( let i = 1; i < n; i ++ ) { | ||
| const sigma = Math.sqrt( this._sigmas[ i ] * this._sigmas[ i ] - this._sigmas[ i - 1 ] * this._sigmas[ i - 1 ] ); | ||
| this._applyGGXFilter( cubeUVRenderTarget, i - 1, i ); | ||
| const poleAxis = _axisDirections[ ( n - i - 1 ) % _axisDirections.length ]; | ||
| } | ||
| this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis ); | ||
| renderer.autoClear = autoClear; | ||
| } | ||
| /** | ||
| * Applies GGX VNDF importance sampling filter to generate a prefiltered environment map. | ||
| * Uses Monte Carlo integration with VNDF importance sampling to accurately represent the | ||
| * GGX BRDF for physically-based rendering. Reads from the previous LOD level and | ||
| * applies incremental roughness filtering to avoid over-blurring. | ||
| * | ||
| * @private | ||
| * @param {RenderTarget} cubeUVRenderTarget | ||
| * @param {number} lodIn - Source LOD level to read from | ||
| * @param {number} lodOut - Target LOD level to write to | ||
| */ | ||
| _applyGGXFilter( cubeUVRenderTarget, lodIn, lodOut ) { | ||
| const renderer = this._renderer; | ||
| const pingPongRenderTarget = this._pingPongRenderTarget; | ||
| // Lazy create GGX material only when first used | ||
| if ( this._ggxMaterial === null ) { | ||
| this._ggxMaterial = _getGGXShader( this._lodMax, this._pingPongRenderTarget.width, this._pingPongRenderTarget.height ); | ||
| } | ||
| renderer.autoClear = autoClear; | ||
| const ggxMaterial = this._ggxMaterial; | ||
| const ggxMesh = this._lodMeshes[ lodOut ]; | ||
| ggxMesh.material = ggxMaterial; | ||
| const ggxUniforms = _uniformsMap.get( ggxMaterial ); | ||
| // Calculate incremental roughness between LOD levels | ||
| const targetRoughness = lodOut / ( this._lodMeshes.length - 1 ); | ||
| const sourceRoughness = lodIn / ( this._lodMeshes.length - 1 ); | ||
| const incrementalRoughness = Math.sqrt( targetRoughness * targetRoughness - sourceRoughness * sourceRoughness ); | ||
| // Apply blur strength mapping for better quality across the roughness range | ||
| const blurStrength = 0.05 + targetRoughness * 0.95; | ||
| const adjustedRoughness = incrementalRoughness * blurStrength; | ||
| // Calculate viewport position based on output LOD level | ||
| const { _lodMax } = this; | ||
| const outputSize = this._sizeLods[ lodOut ]; | ||
| const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 ); | ||
| const y = 4 * ( this._cubeSize - outputSize ); | ||
| // Read from previous LOD with incremental roughness | ||
| cubeUVRenderTarget.texture.frame = ( cubeUVRenderTarget.texture.frame || 0 ) + 1; | ||
| ggxUniforms.envMap.value = cubeUVRenderTarget.texture; | ||
| ggxUniforms.roughness.value = adjustedRoughness; | ||
| ggxUniforms.mipInt.value = _lodMax - lodIn; // Sample from input LOD | ||
| _setViewport( pingPongRenderTarget, x, y, 3 * outputSize, 2 * outputSize ); | ||
| renderer.setRenderTarget( pingPongRenderTarget ); | ||
| renderer.render( ggxMesh, _flatCamera ); | ||
| // Copy from pingPong back to cubeUV (simple direct copy) | ||
| pingPongRenderTarget.texture.frame = ( pingPongRenderTarget.texture.frame || 0 ) + 1; | ||
| ggxUniforms.envMap.value = pingPongRenderTarget.texture; | ||
| ggxUniforms.roughness.value = 0.0; // Direct copy | ||
| ggxUniforms.mipInt.value = _lodMax - lodOut; // Read from the level we just wrote | ||
| _setViewport( cubeUVRenderTarget, x, y, 3 * outputSize, 2 * outputSize ); | ||
| renderer.setRenderTarget( cubeUVRenderTarget ); | ||
| renderer.render( ggxMesh, _flatCamera ); | ||
| } | ||
@@ -670,2 +734,4 @@ | ||
| * | ||
| * Used for initial scene blur in fromScene() method when sigma > 0. | ||
| * | ||
| * @private | ||
@@ -709,3 +775,3 @@ * @param {RenderTarget} cubeUVRenderTarget - The cubemap render target. | ||
| console.error( 'blur direction must be either latitudinal or longitudinal!' ); | ||
| error( 'blur direction must be either latitudinal or longitudinal!' ); | ||
@@ -729,3 +795,3 @@ } | ||
| console.warn( `sigmaRadians, ${ | ||
| warn( `sigmaRadians, ${ | ||
| sigmaRadians}, is too large and will clip, as it requested ${ | ||
@@ -794,3 +860,2 @@ samples} samples when the maximum is set to ${MAX_SAMPLES}` ); | ||
| const lodPlanes = []; | ||
| const sizeLods = []; | ||
@@ -862,3 +927,2 @@ const sigmas = []; | ||
| planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) ); | ||
| lodPlanes.push( planes ); | ||
| lodMeshes.push( new Mesh( planes, null ) ); | ||
@@ -874,3 +938,3 @@ | ||
| return { lodPlanes, sizeLods, sigmas, lodMeshes }; | ||
| return { lodMeshes, sizeLods, sigmas }; | ||
@@ -927,3 +991,3 @@ } | ||
| const samples = uniform( 1 ); // int | ||
| const envMap = texture( null ); | ||
| const envMap = texture(); | ||
| const mipInt = uniform( 0 ); // int | ||
@@ -958,2 +1022,33 @@ const CUBEUV_TEXEL_WIDTH = float( 1 / width ); | ||
| function _getGGXShader( lodMax, width, height ) { | ||
| const envMap = texture(); | ||
| const roughness = uniform( 0 ); | ||
| const mipInt = uniform( 0 ); | ||
| const CUBEUV_TEXEL_WIDTH = float( 1 / width ); | ||
| const CUBEUV_TEXEL_HEIGHT = float( 1 / height ); | ||
| const CUBEUV_MAX_MIP = float( lodMax ); | ||
| const materialUniforms = { | ||
| envMap, | ||
| roughness, | ||
| mipInt, | ||
| CUBEUV_TEXEL_WIDTH, | ||
| CUBEUV_TEXEL_HEIGHT, | ||
| CUBEUV_MAX_MIP | ||
| }; | ||
| const material = _getMaterial( 'ggx' ); | ||
| material.fragmentNode = ggxConvolution( { | ||
| ...materialUniforms, | ||
| N_immutable: _outputDirection, | ||
| GGX_SAMPLES: uint( GGX_SAMPLES ) | ||
| } ); | ||
| _uniformsMap.set( material, materialUniforms ); | ||
| return material; | ||
| } | ||
| function _getCubemapMaterial( envTexture ) { | ||
@@ -960,0 +1055,0 @@ |
@@ -120,2 +120,10 @@ import DataMap from './DataMap.js'; | ||
| /** | ||
| * Stores the event listeners attached to geometries. | ||
| * | ||
| * @private | ||
| * @type {Map<BufferGeometry,Function>} | ||
| */ | ||
| this._geometryDisposeListeners = new Map(); | ||
| } | ||
@@ -193,2 +201,4 @@ | ||
| this._geometryDisposeListeners.delete( geometry ); | ||
| }; | ||
@@ -198,2 +208,6 @@ | ||
| // see #31798 why tracking separate remove listeners is required right now | ||
| // TODO: Re-evaluate how onDispose() is managed in this component | ||
| this._geometryDisposeListeners.set( geometry, onDispose ); | ||
| } | ||
@@ -345,4 +359,16 @@ | ||
| dispose() { | ||
| for ( const [ geometry, onDispose ] of this._geometryDisposeListeners.entries() ) { | ||
| geometry.removeEventListener( 'dispose', onDispose ); | ||
| } | ||
| this._geometryDisposeListeners.clear(); | ||
| } | ||
| } | ||
| export default Geometries; |
@@ -0,1 +1,3 @@ | ||
| import { error } from '../../utils.js'; | ||
| /** | ||
@@ -55,3 +57,3 @@ * This renderer module provides a series of statistical information | ||
| * @property {number} lines - The number of rendered line primitives of the current frame. | ||
| * @property {number} timestamp - The timestamp of the frame when using `renderer.renderAsync()`. | ||
| * @property {number} timestamp - The timestamp of the frame. | ||
| */ | ||
@@ -127,3 +129,3 @@ this.render = { | ||
| console.error( 'THREE.WebGPUInfo: Unknown object type.' ); | ||
| error( 'WebGPUInfo: Unknown object type.' ); | ||
@@ -130,0 +132,0 @@ } |
@@ -0,1 +1,3 @@ | ||
| import { warn } from '../../../utils.js'; | ||
| /** | ||
@@ -157,3 +159,3 @@ * The purpose of a node library is to assign node implementations | ||
| console.warn( `Redefinition of node ${ type }` ); | ||
| warn( `Redefinition of node ${ type }` ); | ||
| return; | ||
@@ -181,3 +183,3 @@ | ||
| console.warn( `Redefinition of node ${ baseClass.name }` ); | ||
| warn( `Redefinition of node ${ baseClass.name }` ); | ||
| return; | ||
@@ -184,0 +186,0 @@ |
| import DataMap from '../DataMap.js'; | ||
| import ChainMap from '../ChainMap.js'; | ||
| import NodeBuilderState from './NodeBuilderState.js'; | ||
| import NodeMaterial from '../../../materials/nodes/NodeMaterial.js'; | ||
| import { cubeMapNode } from '../../../nodes/utils/CubeMapNode.js'; | ||
@@ -11,2 +12,3 @@ import { NodeFrame } from '../../../nodes/Nodes.js'; | ||
| import { hashArray } from '../../../nodes/core/NodeUtils.js'; | ||
| import { error } from '../../../utils.js'; | ||
@@ -197,19 +199,38 @@ const _outputNodeMap = new WeakMap(); | ||
| const nodeBuilder = this.backend.createNodeBuilder( renderObject.object, this.renderer ); | ||
| nodeBuilder.scene = renderObject.scene; | ||
| nodeBuilder.material = renderObject.material; | ||
| nodeBuilder.camera = renderObject.camera; | ||
| nodeBuilder.context.material = renderObject.material; | ||
| nodeBuilder.lightsNode = renderObject.lightsNode; | ||
| nodeBuilder.environmentNode = this.getEnvironmentNode( renderObject.scene ); | ||
| nodeBuilder.fogNode = this.getFogNode( renderObject.scene ); | ||
| nodeBuilder.clippingContext = renderObject.clippingContext; | ||
| if ( this.renderer.getOutputRenderTarget() ? this.renderer.getOutputRenderTarget().multiview : false ) { | ||
| const createNodeBuilder = ( material ) => { | ||
| nodeBuilder.enableMultiview(); | ||
| const nodeBuilder = this.backend.createNodeBuilder( renderObject.object, this.renderer ); | ||
| nodeBuilder.scene = renderObject.scene; | ||
| nodeBuilder.material = material; | ||
| nodeBuilder.camera = renderObject.camera; | ||
| nodeBuilder.context.material = material; | ||
| nodeBuilder.lightsNode = renderObject.lightsNode; | ||
| nodeBuilder.environmentNode = this.getEnvironmentNode( renderObject.scene ); | ||
| nodeBuilder.fogNode = this.getFogNode( renderObject.scene ); | ||
| nodeBuilder.clippingContext = renderObject.clippingContext; | ||
| if ( this.renderer.getOutputRenderTarget() ? this.renderer.getOutputRenderTarget().multiview : false ) { | ||
| nodeBuilder.enableMultiview(); | ||
| } | ||
| return nodeBuilder; | ||
| }; | ||
| let nodeBuilder = createNodeBuilder( renderObject.material ); | ||
| try { | ||
| nodeBuilder.build(); | ||
| } catch ( e ) { | ||
| nodeBuilder = createNodeBuilder( new NodeMaterial() ); | ||
| nodeBuilder.build(); | ||
| error( 'TSL: ' + e ); | ||
| } | ||
| nodeBuilder.build(); | ||
| nodeBuilderState = this._createNodeBuilderState( nodeBuilder ); | ||
@@ -417,2 +438,3 @@ | ||
| _cacheKeyValues.push( this.renderer.shadowMap.enabled ? 1 : 0 ); | ||
| _cacheKeyValues.push( this.renderer.shadowMap.type ); | ||
@@ -495,3 +517,3 @@ cacheKeyData.callId = callId; | ||
| console.error( 'WebGPUNodes: Unsupported background configuration.', background ); | ||
| error( 'WebGPUNodes: Unsupported background configuration.', background ); | ||
@@ -578,3 +600,3 @@ } | ||
| console.error( 'THREE.Renderer: Unsupported fog configuration.', sceneFog ); | ||
| error( 'Renderer: Unsupported fog configuration.', sceneFog ); | ||
@@ -626,3 +648,3 @@ } | ||
| console.error( 'Nodes: Unsupported environment configuration.', environment ); | ||
| error( 'Nodes: Unsupported environment configuration.', environment ); | ||
@@ -629,0 +651,0 @@ } |
@@ -41,7 +41,19 @@ import Sampler from '../Sampler.js'; | ||
| * Updates the texture value of this sampler. | ||
| * | ||
| * @return {boolean} Whether the sampler needs an update or not. | ||
| */ | ||
| update() { | ||
| this.texture = this.textureNode.value; | ||
| const { textureNode } = this; | ||
| if ( this.texture !== textureNode.value ) { | ||
| this.texture = textureNode.value; | ||
| return true; | ||
| } | ||
| return super.update(); | ||
| } | ||
@@ -48,0 +60,0 @@ |
@@ -6,2 +6,3 @@ import NodeMaterial from '../../materials/nodes/NodeMaterial.js'; | ||
| import QuadMesh from '../../renderers/common/QuadMesh.js'; | ||
| import { warnOnce } from '../../utils.js'; | ||
@@ -86,2 +87,3 @@ /** | ||
| this._quadMesh = new QuadMesh( material ); | ||
| this._quadMesh.name = 'Post-Processing'; | ||
@@ -211,2 +213,3 @@ /** | ||
| * @async | ||
| * @deprecated | ||
| * @return {Promise} A Promise that resolves when the render has been finished. | ||
@@ -216,30 +219,8 @@ */ | ||
| this._update(); | ||
| warnOnce( 'PostProcessing: "renderAsync()" has been deprecated. Use "render()" and "await renderer.init();" when creating the renderer.' ); // @deprecated r181 | ||
| if ( this._context.onBeforePostProcessing !== null ) this._context.onBeforePostProcessing(); | ||
| await this.renderer.init(); | ||
| const renderer = this.renderer; | ||
| this.render(); | ||
| const toneMapping = renderer.toneMapping; | ||
| const outputColorSpace = renderer.outputColorSpace; | ||
| renderer.toneMapping = NoToneMapping; | ||
| renderer.outputColorSpace = ColorManagement.workingColorSpace; | ||
| // | ||
| const currentXR = renderer.xr.enabled; | ||
| renderer.xr.enabled = false; | ||
| await this._quadMesh.renderAsync( renderer ); | ||
| renderer.xr.enabled = currentXR; | ||
| // | ||
| renderer.toneMapping = toneMapping; | ||
| renderer.outputColorSpace = outputColorSpace; | ||
| if ( this._context.onAfterPostProcessing !== null ) this._context.onAfterPostProcessing(); | ||
| } | ||
@@ -246,0 +227,0 @@ |
@@ -5,2 +5,3 @@ import { BufferGeometry } from '../../core/BufferGeometry.js'; | ||
| import { OrthographicCamera } from '../../cameras/OrthographicCamera.js'; | ||
| import { warnOnce } from '../../utils.js'; | ||
@@ -85,2 +86,3 @@ const _camera = /*@__PURE__*/ new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); | ||
| * @async | ||
| * @deprecated | ||
| * @param {Renderer} renderer - The renderer. | ||
@@ -91,4 +93,8 @@ * @return {Promise} A Promise that resolves when the render has been finished. | ||
| return renderer.renderAsync( this, _camera ); | ||
| warnOnce( 'QuadMesh: "renderAsync()" has been deprecated. Use "render()" and "await renderer.init();" when creating the renderer.' ); // @deprecated r181 | ||
| await renderer.init(); | ||
| renderer.render( this, _camera ); | ||
| } | ||
@@ -95,0 +101,0 @@ |
@@ -8,2 +8,3 @@ import { Color } from '../../math/Color.js'; | ||
| * | ||
| * @private | ||
| * @function | ||
@@ -40,2 +41,3 @@ * @param {Renderer} renderer - The renderer. | ||
| * | ||
| * @private | ||
| * @function | ||
@@ -62,2 +64,3 @@ * @param {Renderer} renderer - The renderer. | ||
| * | ||
| * @private | ||
| * @function | ||
@@ -87,2 +90,3 @@ * @param {Renderer} renderer - The renderer. | ||
| * | ||
| * @private | ||
| * @function | ||
@@ -109,2 +113,3 @@ * @param {Scene} scene - The scene. | ||
| * | ||
| * @private | ||
| * @function | ||
@@ -130,2 +135,3 @@ * @param {Scene} scene - The scene. | ||
| * | ||
| * @private | ||
| * @function | ||
@@ -148,2 +154,3 @@ * @param {Scene} scene - The scene. | ||
| * | ||
| * @private | ||
| * @function | ||
@@ -170,2 +177,3 @@ * @param {Renderer} renderer - The renderer. | ||
| * | ||
| * @private | ||
| * @function | ||
@@ -189,2 +197,3 @@ * @param {Renderer} renderer - The renderer. | ||
| * | ||
| * @private | ||
| * @function | ||
@@ -191,0 +200,0 @@ * @param {Renderer} renderer - The renderer. |
@@ -75,3 +75,3 @@ import { DoubleSide } from '../../constants.js'; | ||
| const hasTransmission = material.transmission > 0 || material.transmissionNode; | ||
| const hasTransmission = material.transmission > 0 || ( material.transmissionNode && material.transmissionNode.isNode ); | ||
@@ -287,3 +287,5 @@ return hasTransmission && material.side === DoubleSide && material.forceSinglePass === false; | ||
| if ( material.transparent === true || material.transmission > 0 ) { | ||
| if ( material.transparent === true || material.transmission > 0 || | ||
| ( material.transmissionNode && material.transmissionNode.isNode ) || | ||
| ( material.backdropNode && material.backdropNode.isNode ) ) { | ||
@@ -318,3 +320,5 @@ if ( needsDoublePass( material ) ) this.transparentDoublePass.push( renderItem ); | ||
| if ( material.transparent === true || material.transmission > 0 ) { | ||
| if ( material.transparent === true || material.transmission > 0 || | ||
| ( material.transmissionNode && material.transmissionNode.isNode ) || | ||
| ( material.backdropNode && material.backdropNode.isNode ) ) { | ||
@@ -321,0 +325,0 @@ if ( needsDoublePass( material ) ) this.transparentDoublePass.unshift( renderItem ); |
@@ -773,3 +773,3 @@ import { hash, hashString } from '../../nodes/core/NodeUtils.js'; | ||
| if ( object.isInstancedMesh || object.count > 1 ) { | ||
| if ( object.isInstancedMesh || object.count > 1 || Array.isArray( object.morphTargetInfluences ) ) { | ||
@@ -873,2 +873,4 @@ // TODO: https://github.com/mrdoob/three.js/pull/29066#issuecomment-2269400850 | ||
| cacheKey = hash( cacheKey, this.camera.id ); | ||
| return cacheKey; | ||
@@ -875,0 +877,0 @@ |
@@ -188,3 +188,3 @@ import ChainMap from './ChainMap.js'; | ||
| this.pipelines.delete( renderObject ); | ||
| this.bindings.delete( renderObject ); | ||
| this.bindings.deleteForRender( renderObject ); | ||
| this.nodes.delete( renderObject ); | ||
@@ -191,0 +191,0 @@ |
@@ -39,2 +39,10 @@ import Sampler from './Sampler.js'; | ||
| /** | ||
| * The mip level to bind for storage textures. | ||
| * | ||
| * @type {number} | ||
| * @default 0 | ||
| */ | ||
| this.mipLevel = 0; | ||
| /** | ||
| * This flag can be used for type testing. | ||
@@ -41,0 +49,0 @@ * |
@@ -24,4 +24,21 @@ import Binding from './Binding.js'; | ||
| * | ||
| * @private | ||
| * @type {?Texture} | ||
| */ | ||
| this._texture = null; | ||
| /** | ||
| * An event listener which is added to {@link texture}'s dispose event. | ||
| * | ||
| * @private | ||
| * @type {Function} | ||
| */ | ||
| this._onTextureDispose = () => { | ||
| this.generation = null; | ||
| this.version = 0; | ||
| }; | ||
| // Assignment to the texture via a setter must occur after "_onTextureDispose" is initialized. | ||
| this.texture = texture; | ||
@@ -46,2 +63,10 @@ | ||
| /** | ||
| * The binding's sampler key. | ||
| * | ||
| * @type {string} | ||
| * @default '' | ||
| */ | ||
| this.samplerKey = ''; | ||
| /** | ||
| * This flag can be used for type testing. | ||
@@ -59,3 +84,4 @@ * | ||
| * Sets the texture of this sampler. | ||
| * @param {?Texture} value - The texture to set. | ||
| * | ||
| * @param {Texture} value - The texture to set. | ||
| */ | ||
@@ -66,13 +92,5 @@ set texture( value ) { | ||
| const onDispose = () => { | ||
| this._texture = null; | ||
| this.generation = null; | ||
| this.version = 0; | ||
| }; | ||
| if ( this._texture ) { | ||
| this._texture.removeEventListener( 'dispose', onDispose ); | ||
| this._texture.removeEventListener( 'dispose', this._onTextureDispose ); | ||
@@ -88,3 +106,3 @@ } | ||
| this._texture.addEventListener( 'dispose', onDispose ); | ||
| this._texture.addEventListener( 'dispose', this._onTextureDispose ); | ||
@@ -136,2 +154,10 @@ } | ||
| clonedSampler._texture = null; | ||
| clonedSampler._onTextureDispose = () => { | ||
| clonedSampler.generation = null; | ||
| clonedSampler.version = 0; | ||
| }; | ||
| clonedSampler.texture = this.texture; | ||
@@ -138,0 +164,0 @@ |
@@ -55,4 +55,12 @@ import { Texture } from '../../textures/Texture.js'; | ||
| /** | ||
| * When `true`, mipmaps will be auto-generated after compute writes. | ||
| * When `false`, mipmaps must be written manually via compute shaders. | ||
| * | ||
| * @type {boolean} | ||
| * @default true | ||
| */ | ||
| this.mipmapsAutoUpdate = true; | ||
| } | ||
| /** | ||
@@ -59,0 +67,0 @@ * Sets the size of the storage texture. |
@@ -7,2 +7,3 @@ import DataMap from './DataMap.js'; | ||
| import { ColorManagement } from '../../math/ColorManagement.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -88,2 +89,3 @@ const _size = /*@__PURE__*/ new Vector3(); | ||
| depthTexture.image.depth = size.depth; | ||
| depthTexture.renderTarget = renderTarget; | ||
| depthTexture.isArrayTexture = renderTarget.multiview === true && size.depth > 1; | ||
@@ -167,24 +169,9 @@ | ||
| const onDispose = () => { | ||
| renderTargetData.onDispose = () => { | ||
| renderTarget.removeEventListener( 'dispose', onDispose ); | ||
| this._destroyRenderTarget( renderTarget ); | ||
| for ( let i = 0; i < textures.length; i ++ ) { | ||
| this._destroyTexture( textures[ i ] ); | ||
| } | ||
| if ( depthTexture ) { | ||
| this._destroyTexture( depthTexture ); | ||
| } | ||
| this.delete( renderTarget ); | ||
| this.backend.delete( renderTarget ); | ||
| }; | ||
| renderTarget.addEventListener( 'dispose', onDispose ); | ||
| renderTarget.addEventListener( 'dispose', renderTargetData.onDispose ); | ||
@@ -215,3 +202,2 @@ } | ||
| backend.destroySampler( texture ); | ||
| backend.destroyTexture( texture ); | ||
@@ -259,3 +245,2 @@ | ||
| backend.createSampler( texture ); | ||
| backend.createTexture( texture, options ); | ||
@@ -267,6 +252,2 @@ | ||
| const needsCreate = textureData.initialized !== true; | ||
| if ( needsCreate ) backend.createSampler( texture ); | ||
| if ( texture.version > 0 ) { | ||
@@ -278,7 +259,7 @@ | ||
| console.warn( 'THREE.Renderer: Texture marked for update but image is undefined.' ); | ||
| warn( 'Renderer: Texture marked for update but image is undefined.' ); | ||
| } else if ( image.complete === false ) { | ||
| console.warn( 'THREE.Renderer: Texture marked for update but image is incomplete.' ); | ||
| warn( 'Renderer: Texture marked for update but image is incomplete.' ); | ||
@@ -316,4 +297,10 @@ } else { | ||
| if ( options.needsMipmaps && texture.mipmaps.length === 0 ) backend.generateMipmaps( texture ); | ||
| const skipAutoGeneration = texture.isStorageTexture === true && texture.mipmapsAutoUpdate === false; | ||
| if ( options.needsMipmaps && texture.mipmaps.length === 0 && ! skipAutoGeneration ) { | ||
| backend.generateMipmaps( texture ); | ||
| } | ||
| if ( texture.onUpdate ) texture.onUpdate( texture ); | ||
@@ -351,3 +338,3 @@ | ||
| console.warn( 'WebGPURenderer: Video textures must use a color space with a sRGB transfer function, e.g. SRGBColorSpace.' ); | ||
| warn( 'WebGPURenderer: Video textures must use a color space with a sRGB transfer function, e.g. SRGBColorSpace.' ); | ||
@@ -358,6 +345,4 @@ } | ||
| const onDispose = () => { | ||
| textureData.onDispose = () => { | ||
| texture.removeEventListener( 'dispose', onDispose ); | ||
| this._destroyTexture( texture ); | ||
@@ -367,3 +352,3 @@ | ||
| texture.addEventListener( 'dispose', onDispose ); | ||
| texture.addEventListener( 'dispose', textureData.onDispose ); | ||
@@ -379,2 +364,20 @@ } | ||
| /** | ||
| * Updates the sampler for the given texture. This method has no effect | ||
| * for the WebGL backend since it has no concept of samplers. Texture | ||
| * parameters are configured with the `texParameter()` command for each | ||
| * texture. | ||
| * | ||
| * In WebGPU, samplers are objects like textures and it's possible to share | ||
| * them when the texture parameters match. | ||
| * | ||
| * @param {Texture} texture - The texture to update the sampler for. | ||
| * @return {string} The current sampler key. | ||
| */ | ||
| updateSampler( texture ) { | ||
| return this.backend.updateSampler( texture ); | ||
| } | ||
| /** | ||
| * Computes the size of the given texture and writes the result | ||
@@ -405,3 +408,3 @@ * into the target vector. This vector is also returned by the | ||
| } else if ( image instanceof VideoFrame ) { | ||
| } else if ( ( typeof VideoFrame !== 'undefined' ) && ( image instanceof VideoFrame ) ) { | ||
@@ -481,2 +484,42 @@ target.width = image.displayWidth || 1; | ||
| /** | ||
| * Frees internal resources when the given render target isn't | ||
| * required anymore. | ||
| * | ||
| * @param {RenderTarget} renderTarget - The render target to destroy. | ||
| */ | ||
| _destroyRenderTarget( renderTarget ) { | ||
| if ( this.has( renderTarget ) === true ) { | ||
| const renderTargetData = this.get( renderTarget ); | ||
| const textures = renderTargetData.textures; | ||
| const depthTexture = renderTargetData.depthTexture; | ||
| // | ||
| renderTarget.removeEventListener( 'dispose', renderTargetData.onDispose ); | ||
| // | ||
| for ( let i = 0; i < textures.length; i ++ ) { | ||
| this._destroyTexture( textures[ i ] ); | ||
| } | ||
| if ( depthTexture ) { | ||
| this._destroyTexture( depthTexture ); | ||
| } | ||
| this.delete( renderTarget ); | ||
| this.backend.delete( renderTarget ); | ||
| } | ||
| } | ||
| /** | ||
| * Frees internal resource when the given texture isn't | ||
@@ -491,5 +534,16 @@ * required anymore. | ||
| this.backend.destroySampler( texture ); | ||
| this.backend.destroyTexture( texture ); | ||
| const textureData = this.get( texture ); | ||
| // | ||
| texture.removeEventListener( 'dispose', textureData.onDispose ); | ||
| // if a texture is not ready for use, it falls back to a default texture so it's possible | ||
| // to use it for rendering. If a texture in this state is disposed, it's important to | ||
| // not destroy/delete the underlying GPU texture object since it is cached and shared with | ||
| // other textures. | ||
| const isDefaultTexture = textureData.isDefaultTexture; | ||
| this.backend.destroyTexture( texture, isDefaultTexture ); | ||
| this.delete( texture ); | ||
@@ -496,0 +550,0 @@ |
@@ -0,1 +1,3 @@ | ||
| import { warn } from '../../utils.js'; | ||
| /** | ||
@@ -63,2 +65,9 @@ * Abstract base class of a timestamp query pool. | ||
| /** | ||
| * Stores all timestamp frames. | ||
| * | ||
| * @type {Array<number>} | ||
| */ | ||
| this.frames = []; | ||
| /** | ||
| * TODO | ||
@@ -71,5 +80,57 @@ * | ||
| /** | ||
| * Stores the latest timestamp for each render context. | ||
| * | ||
| * @type {Map<string, number>} | ||
| */ | ||
| this.timestamps = new Map(); | ||
| } | ||
| /** | ||
| * Returns all timestamp frames. | ||
| * | ||
| * @return {Array<number>} The timestamp frames. | ||
| */ | ||
| getTimestampFrames() { | ||
| return this.frames; | ||
| } | ||
| /** | ||
| * Returns the timestamp for a given render context. | ||
| * | ||
| * @param {string} uid - A unique identifier for the render context. | ||
| * @return {?number} The timestamp, or undefined if not available. | ||
| */ | ||
| getTimestamp( uid ) { | ||
| let timestamp = this.timestamps.get( uid ); | ||
| if ( timestamp === undefined ) { | ||
| warn( `TimestampQueryPool: No timestamp available for uid ${ uid }.` ); | ||
| timestamp = 0; | ||
| } | ||
| return timestamp; | ||
| } | ||
| /** | ||
| * Returns whether a timestamp is available for a given render context. | ||
| * | ||
| * @param {string} uid - A unique identifier for the render context. | ||
| * @return {boolean} True if a timestamp is available, false otherwise. | ||
| */ | ||
| hasTimestamp( uid ) { | ||
| return this.timestamps.has( uid ); | ||
| } | ||
| /** | ||
| * Allocate queries for a specific uid. | ||
@@ -79,5 +140,6 @@ * | ||
| * @param {string} uid - A unique identifier for the render context. | ||
| * @param {number} frameId - The current frame identifier. | ||
| * @returns {?number} | ||
| */ | ||
| allocateQueriesForContext( /* uid */ ) {} | ||
| allocateQueriesForContext( /* uid, frameId */ ) {} | ||
@@ -84,0 +146,0 @@ /** |
| import UniformBuffer from './UniformBuffer.js'; | ||
| import { GPU_CHUNK_BYTES } from './Constants.js'; | ||
| import { error } from '../../utils.js'; | ||
@@ -211,3 +212,3 @@ /** | ||
| console.error( 'THREE.WebGPUUniformsGroup: Unsupported uniform type.', uniform ); | ||
| error( 'WebGPUUniformsGroup: Unsupported uniform type.', uniform ); | ||
@@ -214,0 +215,0 @@ } |
@@ -19,2 +19,3 @@ import { ArrayCamera } from '../../cameras/ArrayCamera.js'; | ||
| import { Mesh } from '../../objects/Mesh.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -510,3 +511,3 @@ const _cameraLPos = /*@__PURE__*/ new Vector3(); | ||
| console.warn( 'THREE.XRManager: Cannot change framebuffer scale while presenting.' ); | ||
| warn( 'XRManager: Cannot change framebuffer scale while presenting.' ); | ||
@@ -541,3 +542,3 @@ } | ||
| console.warn( 'THREE.XRManager: Cannot change reference space type while presenting.' ); | ||
| warn( 'XRManager: Cannot change reference space type while presenting.' ); | ||
@@ -1046,3 +1047,3 @@ } | ||
| const layerInit = { | ||
| antialias: renderer.samples > 0, | ||
| antialias: renderer.currentSamples > 0, | ||
| alpha: true, | ||
@@ -1387,2 +1388,5 @@ depth: renderer.depth, | ||
| this._xrRenderTarget = null; | ||
| this._glBinding = null; | ||
| this._glBaseLayer = null; | ||
| this._glProjLayer = null; | ||
@@ -1389,0 +1393,0 @@ // switch layers back to emulated |
@@ -76,14 +76,2 @@ export default /* glsl */` | ||
| mat3 transposeMat3( const in mat3 m ) { | ||
| mat3 tmp; | ||
| tmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x ); | ||
| tmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y ); | ||
| tmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z ); | ||
| return tmp; | ||
| } | ||
| bool isPerspectiveMatrix( mat4 m ) { | ||
@@ -90,0 +78,0 @@ |
@@ -13,4 +13,4 @@ export default /* glsl */` | ||
| #endif | ||
| #endif | ||
| `; |
@@ -29,3 +29,3 @@ export default /* glsl */` | ||
| // Mixing the reflection with the normal is more accurate and keeps rough objects from gathering light from behind their tangent plane. | ||
| reflectVec = normalize( mix( reflectVec, normal, roughness * roughness) ); | ||
| reflectVec = normalize( mix( reflectVec, normal, pow4( roughness ) ) ); | ||
@@ -32,0 +32,0 @@ reflectVec = inverseTransformDirection( reflectVec, viewMatrix ); |
| export default /* glsl */` | ||
| uniform sampler2D dfgLUT; | ||
| struct PhysicalMaterial { | ||
@@ -263,3 +265,3 @@ | ||
| // compute transform | ||
| mat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) ); | ||
| mat3 mat = mInv * transpose( mat3( T1, T2, N ) ); | ||
@@ -374,22 +376,12 @@ // transform rect | ||
| // Analytical approximation of the DFG LUT, one half of the | ||
| // split-sum approximation used in indirect specular lighting. | ||
| // via 'environmentBRDF' from "Physically Based Shading on Mobile" | ||
| // https://www.unrealengine.com/blog/physically-based-shading-on-mobile | ||
| // DFG LUT sampling for physically-based rendering. | ||
| // Uses a precomputed lookup table for the split-sum approximation | ||
| // used in indirect specular lighting. | ||
| // Reference: "Real Shading in Unreal Engine 4" by Brian Karis | ||
| vec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) { | ||
| float dotNV = saturate( dot( normal, viewDir ) ); | ||
| vec2 uv = vec2( roughness, dotNV ); | ||
| return texture2D( dfgLUT, uv ).rg; | ||
| const vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 ); | ||
| const vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 ); | ||
| vec4 r = roughness * c0 + c1; | ||
| float a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y; | ||
| vec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw; | ||
| return fab; | ||
| } | ||
@@ -439,2 +431,44 @@ | ||
| // GGX BRDF with multi-scattering energy compensation for direct lighting | ||
| // Based on "Practical Multiple Scattering Compensation for Microfacet Models" | ||
| // https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf | ||
| vec3 BRDF_GGX_Multiscatter( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) { | ||
| // Single-scattering BRDF (standard GGX) | ||
| vec3 singleScatter = BRDF_GGX( lightDir, viewDir, normal, material ); | ||
| // Multi-scattering compensation | ||
| float dotNL = saturate( dot( normal, lightDir ) ); | ||
| float dotNV = saturate( dot( normal, viewDir ) ); | ||
| // Precomputed DFG values for view and light directions | ||
| vec2 dfgV = DFGApprox( vec3(0.0, 0.0, 1.0), vec3(sqrt(1.0 - dotNV * dotNV), 0.0, dotNV), material.roughness ); | ||
| vec2 dfgL = DFGApprox( vec3(0.0, 0.0, 1.0), vec3(sqrt(1.0 - dotNL * dotNL), 0.0, dotNL), material.roughness ); | ||
| // Single-scattering energy for view and light | ||
| vec3 FssEss_V = material.specularColor * dfgV.x + material.specularF90 * dfgV.y; | ||
| vec3 FssEss_L = material.specularColor * dfgL.x + material.specularF90 * dfgL.y; | ||
| float Ess_V = dfgV.x + dfgV.y; | ||
| float Ess_L = dfgL.x + dfgL.y; | ||
| // Energy lost to multiple scattering | ||
| float Ems_V = 1.0 - Ess_V; | ||
| float Ems_L = 1.0 - Ess_L; | ||
| // Average Fresnel reflectance | ||
| vec3 Favg = material.specularColor + ( 1.0 - material.specularColor ) * 0.047619; // 1/21 | ||
| // Multiple scattering contribution | ||
| vec3 Fms = FssEss_V * FssEss_L * Favg / ( 1.0 - Ems_V * Ems_L * Favg * Favg + EPSILON ); | ||
| // Energy compensation factor | ||
| float compensationFactor = Ems_V * Ems_L; | ||
| vec3 multiScatter = Fms * compensationFactor; | ||
| return singleScatter + multiScatter; | ||
| } | ||
| #if NUM_RECT_AREA_LIGHTS > 0 | ||
@@ -504,3 +538,3 @@ | ||
| reflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material ); | ||
| reflectedLight.directSpecular += irradiance * BRDF_GGX_Multiscatter( directLight.direction, geometryViewDir, geometryNormal, material ); | ||
@@ -507,0 +541,0 @@ reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); |
@@ -38,2 +38,3 @@ import { Color } from '../../math/Color.js'; | ||
| refractionRatio: { value: 0.98 }, // basic, lambert, phong | ||
| dfgLUT: { value: null } // DFG LUT for physically-based rendering | ||
@@ -40,0 +41,0 @@ }, |
| import { ColorManagement } from '../../math/ColorManagement.js'; | ||
| import { warn } from '../../utils.js'; | ||
| // Uniform Utilities | ||
| /** | ||
| * Provides utility functions for managing uniforms. | ||
| * | ||
| * @module UniformsUtils | ||
| */ | ||
| /** | ||
| * Clones the given uniform definitions by performing a deep-copy. That means | ||
| * if the value of a uniform refers to an object like a Vector3 or Texture, | ||
| * the cloned uniform will refer to a new object reference. | ||
| * | ||
| * @param {Object} src - An object representing uniform definitions. | ||
| * @return {Object} The cloned uniforms. | ||
| */ | ||
| export function cloneUniforms( src ) { | ||
@@ -24,3 +37,3 @@ | ||
| console.warn( 'UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().' ); | ||
| warn( 'UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().' ); | ||
| dst[ u ][ p ] = null; | ||
@@ -52,2 +65,10 @@ | ||
| /** | ||
| * Merges the given uniform definitions into a single object. Since the | ||
| * method internally uses cloneUniforms(), it performs a deep-copy when | ||
| * producing the merged uniform definitions. | ||
| * | ||
| * @param {Array} uniforms - An array of objects containing uniform definitions. | ||
| * @return {Object} The merged uniforms. | ||
| */ | ||
| export function mergeUniforms( uniforms ) { | ||
@@ -54,0 +75,0 @@ |
@@ -1,2 +0,2 @@ | ||
| import { GLSLNodeParser, NodeBuilder, TextureNode, vectorComponents } from '../../../nodes/Nodes.js'; | ||
| import { GLSLNodeParser, NodeBuilder, TextureNode, vectorComponents, CodeNode } from '../../../nodes/Nodes.js'; | ||
@@ -10,3 +10,9 @@ import NodeUniformBuffer from '../../common/nodes/NodeUniformBuffer.js'; | ||
| import { DataTexture } from '../../../textures/DataTexture.js'; | ||
| import { error } from '../../../utils.js'; | ||
| const glslPolyfills = { | ||
| bitcast_int_uint: new CodeNode( /* glsl */'uint tsl_bitcast_uint_to_int ( int x ) { return floatBitsToInt( uintBitsToFloat( x ) ); }' ), | ||
| bitcast_uint_int: new CodeNode( /* glsl */'uint tsl_bitcast_int_to_uint ( int x ) { return floatBitsToUint( intBitsToFloat ( x ) ); }' ) | ||
| }; | ||
| const glslMethods = { | ||
@@ -19,2 +25,4 @@ textureDimensions: 'textureSize', | ||
| bitcast_float_uint: 'floatBitsToUint', | ||
| bitcast_uint_int: 'tsl_bitcast_uint_to_int', | ||
| bitcast_int_uint: 'tsl_bitcast_int_to_uint' | ||
| }; | ||
@@ -132,2 +140,21 @@ | ||
| /** | ||
| * Includes the given method name into the current | ||
| * function node. | ||
| * | ||
| * @private | ||
| * @param {string} name - The method name to include. | ||
| * @return {CodeNode} The respective code node. | ||
| */ | ||
| _include( name ) { | ||
| const codeNode = glslPolyfills[ name ]; | ||
| codeNode.build( this ); | ||
| this.addInclude( codeNode ); | ||
| return codeNode; | ||
| } | ||
| /** | ||
| * Returns the native shader method name for a given generic name. | ||
@@ -140,2 +167,8 @@ * | ||
| if ( glslPolyfills[ method ] !== undefined ) { | ||
| this._include( method ); | ||
| } | ||
| return glslMethods[ method ] || method; | ||
@@ -154,3 +187,3 @@ | ||
| return glslMethods[ `bitcast_${ inputType }_${ type }` ]; | ||
| return this.getMethod( `bitcast_${ inputType }_${ type }` ); | ||
@@ -375,3 +408,3 @@ } | ||
| const snippet = this.generateTextureLoad( null, textureName, uvSnippet, null, null, '0' ); | ||
| const snippet = this.generateTextureLoad( null, textureName, uvSnippet, '0', null, null ); | ||
@@ -409,9 +442,11 @@ // | ||
| * @param {string} uvIndexSnippet - A GLSL snippet that represents texture coordinates used for sampling. | ||
| * @param {?string} levelSnippet - A GLSL snippet that represents the mip level, with level 0 containing a full size version of the texture. | ||
| * @param {?string} depthSnippet - A GLSL snippet that represents the 0-based texture array index to sample. | ||
| * @param {?string} offsetSnippet - A GLSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. | ||
| * @param {string} [levelSnippet='0u'] - A GLSL snippet that represents the mip level, with level 0 containing a full size version of the texture. | ||
| * @return {string} The GLSL snippet. | ||
| */ | ||
| generateTextureLoad( texture, textureProperty, uvIndexSnippet, depthSnippet, offsetSnippet, levelSnippet = '0' ) { | ||
| generateTextureLoad( texture, textureProperty, uvIndexSnippet, levelSnippet, depthSnippet, offsetSnippet ) { | ||
| if ( levelSnippet === null ) levelSnippet = '0'; | ||
| let snippet; | ||
@@ -588,3 +623,3 @@ | ||
| console.error( `WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${ shaderStage } shader.` ); | ||
| error( `WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${ shaderStage } shader.` ); | ||
@@ -971,3 +1006,4 @@ } | ||
| /** | ||
| * Returns the instance index builtin. | ||
| * Contextually returns either the vertex stage instance index builtin | ||
| * or the linearized index of an compute invocation within a grid of workgroups. | ||
| * | ||
@@ -983,3 +1019,3 @@ * @return {string} The instance index. | ||
| /** | ||
| * Returns the invocation local index builtin. | ||
| * Returns a builtin representing the index of an invocation within its workgroup. | ||
| * | ||
@@ -999,2 +1035,29 @@ * @return {string} The invocation local index. | ||
| /** | ||
| * Returns a builtin representing the size of a subgroup within the current shader. | ||
| */ | ||
| getSubgroupSize() { | ||
| error( 'GLSLNodeBuilder: WebGLBackend does not support the subgroupSize node' ); | ||
| } | ||
| /** | ||
| * Returns a builtin representing the index of an invocation within its subgroup. | ||
| */ | ||
| getInvocationSubgroupIndex() { | ||
| error( 'GLSLNodeBuilder: WebGLBackend does not support the invocationSubgroupIndex node' ); | ||
| } | ||
| /** | ||
| * Returns a builtin representing the index of the current invocation's subgroup within its workgroup. | ||
| */ | ||
| getSubgroupIndex() { | ||
| error( 'GLSLNodeBuilder: WebGLBackend does not support the subgroupIndex node' ); | ||
| } | ||
| /** | ||
| * Returns the draw index builtin. | ||
@@ -1330,2 +1393,5 @@ * | ||
| // structs | ||
| ${shaderData.structs} | ||
| // uniforms | ||
@@ -1340,5 +1406,2 @@ ${shaderData.uniforms} | ||
| // structs | ||
| ${shaderData.structs} | ||
| void main() { | ||
@@ -1345,0 +1408,0 @@ |
@@ -8,5 +8,4 @@ export const GLFeatureName = { | ||
| 'WEBGL_compressed_texture_pvrtc': 'texture-compression-pvrtc', | ||
| 'WEBKIT_WEBGL_compressed_texture_pvrtc': 'texture-compression-pvrtc', | ||
| 'WEBGL_compressed_texture_s3tc': 'texture-compression-bc', | ||
| 'EXT_texture_compression_bptc': 'texture-compression-bptc', | ||
| 'WEBGL_compressed_texture_s3tc': 'texture-compression-s3tc', | ||
| 'EXT_texture_compression_bptc': 'texture-compression-bc', | ||
| 'EXT_disjoint_timer_query_webgl2': 'timestamp-query', | ||
@@ -13,0 +12,0 @@ 'OVR_multiview2': 'OVR_multiview2' |
@@ -10,2 +10,3 @@ import { | ||
| import { Vector4 } from '../../../math/Vector4.js'; | ||
| import { error } from '../../../utils.js'; | ||
@@ -347,3 +348,3 @@ let equationToGL, factorToGL; | ||
| default: | ||
| console.error( 'THREE.WebGLState: Invalid blending: ', blending ); | ||
| error( 'WebGLState: Invalid blending: ', blending ); | ||
| break; | ||
@@ -366,11 +367,11 @@ | ||
| case SubtractiveBlending: | ||
| console.error( 'THREE.WebGLState: SubtractiveBlending requires material.premultipliedAlpha = true' ); | ||
| error( 'WebGLState: SubtractiveBlending requires material.premultipliedAlpha = true' ); | ||
| break; | ||
| case MultiplyBlending: | ||
| console.error( 'THREE.WebGLState: MultiplyBlending requires material.premultipliedAlpha = true' ); | ||
| error( 'WebGLState: MultiplyBlending requires material.premultipliedAlpha = true' ); | ||
| break; | ||
| default: | ||
| console.error( 'THREE.WebGLState: Invalid blending: ', blending ); | ||
| error( 'WebGLState: Invalid blending: ', blending ); | ||
| break; | ||
@@ -760,3 +761,3 @@ | ||
| material.alphaToCoverage === true && this.backend.renderer.samples > 1 | ||
| material.alphaToCoverage === true && this.backend.renderer.currentSamples > 0 | ||
| ? this.enable( gl.SAMPLE_ALPHA_TO_COVERAGE ) | ||
@@ -763,0 +764,0 @@ : this.disable( gl.SAMPLE_ALPHA_TO_COVERAGE ); |
| import { LinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, NearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, FloatType, MirroredRepeatWrapping, ClampToEdgeWrapping, RepeatWrapping, NeverCompare, AlwaysCompare, LessCompare, LessEqualCompare, EqualCompare, GreaterEqualCompare, GreaterCompare, NotEqualCompare, NoColorSpace, LinearTransfer, SRGBTransfer } from '../../../constants.js'; | ||
| import { ColorManagement } from '../../../math/ColorManagement.js'; | ||
| import { getByteLength } from '../../../extras/TextureUtils.js'; | ||
| import { warn } from '../../../utils.js'; | ||
@@ -51,2 +52,20 @@ let initialized = false, wrappingToGL, filterToGL, compareToGL; | ||
| /** | ||
| * A scratch framebuffer used for attaching the source texture in | ||
| * {@link copyTextureToTexture}. | ||
| * | ||
| * @private | ||
| * @type {?WebGLFramebuffer} | ||
| */ | ||
| this._srcFramebuffer = null; | ||
| /** | ||
| * A scratch framebuffer used for attaching the destination texture in | ||
| * {@link copyTextureToTexture}. | ||
| * | ||
| * @private | ||
| * @type {?WebGLFramebuffer} | ||
| */ | ||
| this._dstFramebuffer = null; | ||
| if ( initialized === false ) { | ||
@@ -155,3 +174,3 @@ | ||
| console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' ); | ||
| warn( 'WebGLBackend: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' ); | ||
@@ -395,4 +414,3 @@ } | ||
| textureGPU, | ||
| glTextureType, | ||
| isDefault: true | ||
| glTextureType | ||
| } ); | ||
@@ -486,3 +504,3 @@ | ||
| // gl.bindFramebuffer( gl.FRAMEBUFFER, null ); | ||
| // console.log( readout ); | ||
| // log( readout ); | ||
@@ -530,3 +548,3 @@ } | ||
| console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' ); | ||
| warn( 'WebGLBackend: Attempt to load unsupported compressed texture format in .uploadTexture()' ); | ||
@@ -549,3 +567,3 @@ } | ||
| console.warn( 'Unsupported compressed texture format' ); | ||
| warn( 'WebGLBackend: Unsupported compressed texture format' ); | ||
@@ -731,4 +749,5 @@ } | ||
| * @param {Texture} texture - The texture. | ||
| * @param {boolean} [isDefaultTexture=false] - Whether the texture uses a default GPU texture or not. | ||
| */ | ||
| destroyTexture( texture ) { | ||
| destroyTexture( texture, isDefaultTexture = false ) { | ||
@@ -739,4 +758,9 @@ const { gl, backend } = this; | ||
| this.deallocateRenderBuffers( renderTarget ); | ||
| gl.deleteTexture( textureGPU ); | ||
| if ( isDefaultTexture === false ) { | ||
| gl.deleteTexture( textureGPU ); | ||
| } | ||
| backend.delete( texture ); | ||
@@ -819,3 +843,2 @@ | ||
| gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY ); | ||
@@ -839,5 +862,7 @@ gl.pixelStorei( gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha ); | ||
| // set up the src texture | ||
| const isSrc3D = srcTexture.isDataArrayTexture || srcTexture.isData3DTexture || dstTexture.isArrayTexture; | ||
| const isDst3D = dstTexture.isDataArrayTexture || dstTexture.isData3DTexture || dstTexture.isArrayTexture; | ||
| if ( srcTexture.isRenderTargetTexture || srcTexture.isDepthTexture ) { | ||
| if ( srcTexture.isDepthTexture ) { | ||
| const srcTextureData = backend.get( srcTexture ); | ||
@@ -855,11 +880,75 @@ const dstTextureData = backend.get( dstTexture ); | ||
| let mask = gl.COLOR_BUFFER_BIT; | ||
| for ( let i = 0; i < depth; i ++ ) { | ||
| if ( srcTexture.isDepthTexture ) mask = gl.DEPTH_BUFFER_BIT; | ||
| // if the source or destination are a 3d target then a layer needs to be bound | ||
| if ( isSrc3D ) { | ||
| gl.blitFramebuffer( minX, minY, width, height, dstX, dstY, width, height, mask, gl.NEAREST ); | ||
| gl.framebufferTextureLayer( gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, srcTextureData.textureGPU, srcLevel, minZ + i ); | ||
| gl.framebufferTextureLayer( gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, dstTextureGPU, dstLevel, dstZ + i ); | ||
| } | ||
| gl.blitFramebuffer( minX, minY, width, height, dstX, dstY, width, height, gl.DEPTH_BUFFER_BIT, gl.NEAREST ); | ||
| } | ||
| state.bindFramebuffer( gl.READ_FRAMEBUFFER, null ); | ||
| state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null ); | ||
| } else if ( srcLevel !== 0 || srcTexture.isRenderTargetTexture || backend.has( srcTexture ) ) { | ||
| // get the appropriate frame buffers | ||
| const srcTextureData = backend.get( srcTexture ); | ||
| if ( this._srcFramebuffer === null ) this._srcFramebuffer = gl.createFramebuffer(); | ||
| if ( this._dstFramebuffer === null ) this._dstFramebuffer = gl.createFramebuffer(); | ||
| // bind the frame buffer targets | ||
| state.bindFramebuffer( gl.READ_FRAMEBUFFER, this._srcFramebuffer ); | ||
| state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, this._dstFramebuffer ); | ||
| for ( let i = 0; i < depth; i ++ ) { | ||
| // assign the correct layers and mip maps to the frame buffers | ||
| if ( isSrc3D ) { | ||
| gl.framebufferTextureLayer( gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, srcTextureData.textureGPU, srcLevel, minZ + i ); | ||
| } else { | ||
| gl.framebufferTexture2D( gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, srcTextureData.textureGPU, srcLevel ); | ||
| } | ||
| if ( isDst3D ) { | ||
| gl.framebufferTextureLayer( gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, dstTextureGPU, dstLevel, dstZ + i ); | ||
| } else { | ||
| gl.framebufferTexture2D( gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, dstTextureGPU, dstLevel ); | ||
| } | ||
| // copy the data using the fastest function that can achieve the copy | ||
| if ( srcLevel !== 0 ) { | ||
| gl.blitFramebuffer( minX, minY, width, height, dstX, dstY, width, height, gl.COLOR_BUFFER_BIT, gl.NEAREST ); | ||
| } else if ( isDst3D ) { | ||
| gl.copyTexSubImage3D( glTextureType, dstLevel, dstX, dstY, dstZ + i, minX, minY, width, height ); | ||
| } else { | ||
| gl.copyTexSubImage2D( glTextureType, dstLevel, dstX, dstY, minX, minY, width, height ); | ||
| } | ||
| } | ||
| // unbind read, draw buffers | ||
| state.bindFramebuffer( gl.READ_FRAMEBUFFER, null ); | ||
| state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null ); | ||
| } else { | ||
@@ -889,11 +978,11 @@ | ||
| gl.texSubImage2D( glTextureType, dstLevel, dstX, dstY, width, height, glFormat, glType, image.data ); | ||
| gl.texSubImage2D( gl.TEXTURE_2D, dstLevel, dstX, dstY, width, height, glFormat, glType, image.data ); | ||
| } else if ( srcTexture.isCompressedTexture ) { | ||
| gl.compressedTexSubImage2D( glTextureType, dstLevel, dstX, dstY, image.width, image.height, glFormat, image.data ); | ||
| gl.compressedTexSubImage2D( gl.TEXTURE_2D, dstLevel, dstX, dstY, image.width, image.height, glFormat, image.data ); | ||
| } else { | ||
| gl.texSubImage2D( glTextureType, dstLevel, dstX, dstY, width, height, glFormat, glType, image ); | ||
| gl.texSubImage2D( gl.TEXTURE_2D, dstLevel, dstX, dstY, width, height, glFormat, glType, image ); | ||
@@ -1199,2 +1288,14 @@ } | ||
| /** | ||
| * Frees the internal resources. | ||
| */ | ||
| dispose() { | ||
| const { gl } = this; | ||
| if ( this._srcFramebuffer !== null ) gl.deleteFramebuffer( this._srcFramebuffer ); | ||
| if ( this._dstFramebuffer !== null ) gl.deleteFramebuffer( this._dstFramebuffer ); | ||
| } | ||
| } | ||
@@ -1201,0 +1302,0 @@ |
@@ -1,2 +0,2 @@ | ||
| import { warnOnce } from '../../../utils.js'; | ||
| import { warnOnce, warn } from '../../../utils.js'; | ||
| import TimestampQueryPool from '../../common/TimestampQueryPool.js'; | ||
@@ -32,3 +32,3 @@ | ||
| console.warn( 'EXT_disjoint_timer_query not supported; timestamps will be disabled.' ); | ||
| warn( 'EXT_disjoint_timer_query not supported; timestamps will be disabled.' ); | ||
| this.trackTimestamp = false; | ||
@@ -128,3 +128,3 @@ return; | ||
| console.error( 'Error in beginQuery:', error ); | ||
| error( 'Error in beginQuery:', error ); | ||
| this.activeQuery = null; | ||
@@ -172,3 +172,3 @@ this.queryStates.set( baseOffset, 'inactive' ); | ||
| console.error( 'Error in endQuery:', error ); | ||
| error( 'Error in endQuery:', error ); | ||
| // Reset state on error | ||
@@ -201,10 +201,12 @@ this.queryStates.set( baseOffset, 'inactive' ); | ||
| // Wait for all ended queries to complete | ||
| const resolvePromises = []; | ||
| const resolvePromises = new Map(); | ||
| for ( const [ baseOffset, state ] of this.queryStates ) { | ||
| for ( const [ uid, baseOffset ] of this.queryOffsets ) { | ||
| const state = this.queryStates.get( baseOffset ); | ||
| if ( state === 'ended' ) { | ||
| const query = this.queries[ baseOffset ]; | ||
| resolvePromises.push( this.resolveQuery( query ) ); | ||
| resolvePromises.set( uid, this.resolveQuery( query ) ); | ||
@@ -215,3 +217,3 @@ } | ||
| if ( resolvePromises.length === 0 ) { | ||
| if ( resolvePromises.size === 0 ) { | ||
@@ -222,7 +224,35 @@ return this.lastValue; | ||
| const results = await Promise.all( resolvePromises ); | ||
| const totalDuration = results.reduce( ( acc, val ) => acc + val, 0 ); | ||
| // | ||
| const framesDuration = {}; | ||
| const frames = []; | ||
| for ( const [ uid, promise ] of resolvePromises ) { | ||
| const match = uid.match( /^(.*):f(\d+)$/ ); | ||
| const frame = parseInt( match[ 2 ] ); | ||
| if ( frames.includes( frame ) === false ) { | ||
| frames.push( frame ); | ||
| } | ||
| if ( framesDuration[ frame ] === undefined ) framesDuration[ frame ] = 0; | ||
| const duration = await promise; | ||
| this.timestamps.set( uid, duration ); | ||
| framesDuration[ frame ] += duration; | ||
| } | ||
| // Return the total duration of the last frame | ||
| const totalDuration = framesDuration[ frames[ frames.length - 1 ] ]; | ||
| // Store the last valid result | ||
| this.lastValue = totalDuration; | ||
| this.frames = frames; | ||
@@ -239,3 +269,3 @@ // Reset states | ||
| console.error( 'Error resolving queries:', error ); | ||
| error( 'Error resolving queries:', error ); | ||
| return this.lastValue; | ||
@@ -328,3 +358,3 @@ | ||
| console.error( 'Error checking query:', error ); | ||
| error( 'Error checking query:', error ); | ||
| resolve( this.lastValue ); | ||
@@ -331,0 +361,0 @@ |
| import { FloatType, HalfFloatType, RGBAFormat, UnsignedByteType } from '../../constants.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -89,3 +90,3 @@ function WebGLCapabilities( gl, extensions, parameters, utils ) { | ||
| console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' ); | ||
| warn( 'WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' ); | ||
| precision = maxPrecision; | ||
@@ -92,0 +93,0 @@ |
@@ -15,27 +15,4 @@ import { warnOnce } from '../../utils.js'; | ||
| let extension; | ||
| const extension = gl.getExtension( name ); | ||
| switch ( name ) { | ||
| case 'WEBGL_depth_texture': | ||
| extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' ); | ||
| break; | ||
| case 'EXT_texture_filter_anisotropic': | ||
| extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); | ||
| break; | ||
| case 'WEBGL_compressed_texture_s3tc': | ||
| extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' ); | ||
| break; | ||
| case 'WEBGL_compressed_texture_pvrtc': | ||
| extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' ); | ||
| break; | ||
| default: | ||
| extension = gl.getExtension( name ); | ||
| } | ||
| extensions[ name ] = extension; | ||
@@ -72,3 +49,3 @@ | ||
| warnOnce( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); | ||
| warnOnce( 'WebGLRenderer: ' + name + ' extension not supported.' ); | ||
@@ -75,0 +52,0 @@ } |
@@ -0,1 +1,3 @@ | ||
| import { error } from '../../utils.js'; | ||
| function WebGLInfo( gl ) { | ||
@@ -43,3 +45,3 @@ | ||
| default: | ||
| console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode ); | ||
| error( 'WebGLInfo: Unknown draw mode:', mode ); | ||
| break; | ||
@@ -46,0 +48,0 @@ |
@@ -8,2 +8,3 @@ import { WebGLUniforms } from './WebGLUniforms.js'; | ||
| import { Matrix3 } from '../../math/Matrix3.js'; | ||
| import { warn, error } from '../../utils.js'; | ||
@@ -51,3 +52,3 @@ // From https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/ | ||
| default: | ||
| console.warn( 'THREE.WebGLProgram: Unsupported color space: ', colorSpace ); | ||
| warn( 'WebGLProgram: Unsupported color space: ', colorSpace ); | ||
| return [ encodingMatrix, 'LinearTransferOETF' ]; | ||
@@ -72,3 +73,3 @@ | ||
| // --enable-privileged-webgl-extension | ||
| // console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); | ||
| // log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); | ||
@@ -137,3 +138,3 @@ const errorLine = parseInt( errorMatches[ 1 ] ); | ||
| default: | ||
| console.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping ); | ||
| warn( 'WebGLProgram: Unsupported toneMapping:', toneMapping ); | ||
| toneMappingName = 'Linear'; | ||
@@ -216,3 +217,3 @@ | ||
| // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i ); | ||
| // log( 'WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i ); | ||
@@ -287,3 +288,3 @@ attributes[ name ] = { | ||
| string = ShaderChunk[ newInclude ]; | ||
| console.warn( 'THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.', include, newInclude ); | ||
| warn( 'WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.', include, newInclude ); | ||
@@ -484,3 +485,3 @@ } else { | ||
| // TODO Send this event to Three.js DevTools | ||
| // console.log( 'WebGLProgram', cacheKey ); | ||
| // log( 'WebGLProgram', cacheKey ); | ||
@@ -901,4 +902,4 @@ const gl = renderer.getContext(); | ||
| // console.log( '*VERTEX*', vertexGlsl ); | ||
| // console.log( '*FRAGMENT*', fragmentGlsl ); | ||
| // log( '*VERTEX*', vertexGlsl ); | ||
| // log( '*FRAGMENT*', fragmentGlsl ); | ||
@@ -957,3 +958,3 @@ const glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl ); | ||
| console.error( | ||
| error( | ||
| 'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' + | ||
@@ -972,3 +973,3 @@ 'VALIDATE_STATUS ' + gl.getProgramParameter( program, gl.VALIDATE_STATUS ) + '\n\n' + | ||
| console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog ); | ||
| warn( 'WebGLProgram: Program Info Log:', programLog ); | ||
@@ -975,0 +976,0 @@ } else if ( vertexLog === '' || fragmentLog === '' ) { |
@@ -8,2 +8,3 @@ import { BackSide, DoubleSide, CubeUVReflectionMapping, ObjectSpaceNormalMap, TangentSpaceNormalMap, NoToneMapping, NormalBlending, LinearSRGBColorSpace, SRGBTransfer } from '../../constants.js'; | ||
| import { ColorManagement } from '../../math/ColorManagement.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -70,3 +71,3 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ) { | ||
| console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' ); | ||
| warn( 'WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' ); | ||
@@ -73,0 +74,0 @@ } |
@@ -14,2 +14,3 @@ import { FrontSide, BackSide, DoubleSide, NearestFilter, PCFShadowMap, VSMShadowMap, RGBADepthPacking, NoBlending } from '../../constants.js'; | ||
| import * as vsm from '../shaders/ShaderLib/vsm.glsl.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -116,3 +117,3 @@ function WebGLShadowMap( renderer, objects, capabilities ) { | ||
| console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' ); | ||
| warn( 'WebGLShadowMap:', light, 'has no shadow.' ); | ||
| continue; | ||
@@ -119,0 +120,0 @@ |
| import { NotEqualDepth, GreaterDepth, GreaterEqualDepth, EqualDepth, LessEqualDepth, LessDepth, AlwaysDepth, NeverDepth, CullFaceFront, CullFaceBack, CullFaceNone, DoubleSide, BackSide, CustomBlending, MultiplyBlending, SubtractiveBlending, AdditiveBlending, NoBlending, NormalBlending, AddEquation, SubtractEquation, ReverseSubtractEquation, MinEquation, MaxEquation, ZeroFactor, OneFactor, SrcColorFactor, SrcAlphaFactor, SrcAlphaSaturateFactor, DstColorFactor, DstAlphaFactor, OneMinusSrcColorFactor, OneMinusSrcAlphaFactor, OneMinusDstColorFactor, OneMinusDstAlphaFactor, ConstantColorFactor, OneMinusConstantColorFactor, ConstantAlphaFactor, OneMinusConstantAlphaFactor } from '../../constants.js'; | ||
| import { Color } from '../../math/Color.js'; | ||
| import { Vector4 } from '../../math/Vector4.js'; | ||
| import { error } from '../../utils.js'; | ||
@@ -674,3 +675,3 @@ const reversedFuncs = { | ||
| default: | ||
| console.error( 'THREE.WebGLState: Invalid blending: ', blending ); | ||
| error( 'WebGLState: Invalid blending: ', blending ); | ||
| break; | ||
@@ -693,11 +694,11 @@ | ||
| case SubtractiveBlending: | ||
| console.error( 'THREE.WebGLState: SubtractiveBlending requires material.premultipliedAlpha = true' ); | ||
| error( 'WebGLState: SubtractiveBlending requires material.premultipliedAlpha = true' ); | ||
| break; | ||
| case MultiplyBlending: | ||
| console.error( 'THREE.WebGLState: MultiplyBlending requires material.premultipliedAlpha = true' ); | ||
| error( 'WebGLState: MultiplyBlending requires material.premultipliedAlpha = true' ); | ||
| break; | ||
| default: | ||
| console.error( 'THREE.WebGLState: Invalid blending: ', blending ); | ||
| error( 'WebGLState: Invalid blending: ', blending ); | ||
| break; | ||
@@ -989,3 +990,3 @@ | ||
| console.error( 'THREE.WebGLState:', error ); | ||
| error( 'WebGLState:', error ); | ||
@@ -1004,3 +1005,3 @@ } | ||
| console.error( 'THREE.WebGLState:', error ); | ||
| error( 'WebGLState:', error ); | ||
@@ -1019,3 +1020,3 @@ } | ||
| console.error( 'THREE.WebGLState:', error ); | ||
| error( 'WebGLState:', error ); | ||
@@ -1034,3 +1035,3 @@ } | ||
| console.error( 'THREE.WebGLState:', error ); | ||
| error( 'WebGLState:', error ); | ||
@@ -1049,3 +1050,3 @@ } | ||
| console.error( 'THREE.WebGLState:', error ); | ||
| error( 'WebGLState:', error ); | ||
@@ -1064,3 +1065,3 @@ } | ||
| console.error( 'THREE.WebGLState:', error ); | ||
| error( 'WebGLState:', error ); | ||
@@ -1079,3 +1080,3 @@ } | ||
| console.error( 'THREE.WebGLState:', error ); | ||
| error( 'WebGLState:', error ); | ||
@@ -1094,3 +1095,3 @@ } | ||
| console.error( 'THREE.WebGLState:', error ); | ||
| error( 'WebGLState:', error ); | ||
@@ -1109,3 +1110,3 @@ } | ||
| console.error( 'THREE.WebGLState:', error ); | ||
| error( 'WebGLState:', error ); | ||
@@ -1124,3 +1125,3 @@ } | ||
| console.error( 'THREE.WebGLState:', error ); | ||
| error( 'WebGLState:', error ); | ||
@@ -1127,0 +1128,0 @@ } |
@@ -0,1 +1,3 @@ | ||
| import { error, warn } from '../../utils.js'; | ||
| function WebGLUniformsGroups( gl, info, capabilities, state ) { | ||
@@ -83,3 +85,3 @@ | ||
| console.error( 'THREE.WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached.' ); | ||
| error( 'WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached.' ); | ||
@@ -339,7 +341,7 @@ return 0; | ||
| console.warn( 'THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.' ); | ||
| warn( 'WebGLRenderer: Texture samplers can not be part of an uniforms group.' ); | ||
| } else { | ||
| console.warn( 'THREE.WebGLRenderer: Unsupported uniform value type.', value ); | ||
| warn( 'WebGLRenderer: Unsupported uniform value type.', value ); | ||
@@ -346,0 +348,0 @@ } |
@@ -20,2 +20,3 @@ import NodeUniformsGroup from '../../common/nodes/NodeUniformsGroup.js'; | ||
| import { FloatType, RepeatWrapping, ClampToEdgeWrapping, MirroredRepeatWrapping, NearestFilter } from '../../../constants.js'; | ||
| import { warn, error } from '../../../utils.js'; | ||
@@ -325,3 +326,3 @@ // GPUShaderStage is not defined in browsers not supporting WebGPU | ||
| console.warn( `WebGPURenderer: Unsupported texture wrap type "${ wrap }" for vertex shader.` ); | ||
| warn( `WebGPURenderer: Unsupported texture wrap type "${ wrap }" for vertex shader.` ); | ||
@@ -502,3 +503,3 @@ } | ||
| return this.generateTextureLoad( texture, textureProperty, coordSnippet, depthSnippet, null, levelSnippet ); | ||
| return this.generateTextureLoad( texture, textureProperty, coordSnippet, levelSnippet, depthSnippet, null ); | ||
@@ -513,10 +514,10 @@ } | ||
| * @param {string} uvIndexSnippet - A WGSL snippet that represents texture coordinates used for sampling. | ||
| * @param {?string} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. | ||
| * @param {?string} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. | ||
| * @param {?string} offsetSnippet - A WGSL snippet that represents the offset that will be applied to the unnormalized texture coordinate before sampling the texture. | ||
| * @param {string} [levelSnippet='0u'] - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. | ||
| * @return {string} The WGSL snippet. | ||
| */ | ||
| generateTextureLoad( texture, textureProperty, uvIndexSnippet, depthSnippet, offsetSnippet, levelSnippet = '0u' ) { | ||
| generateTextureLoad( texture, textureProperty, uvIndexSnippet, levelSnippet, depthSnippet, offsetSnippet ) { | ||
| let snippet; | ||
| if ( levelSnippet === null ) levelSnippet = '0u'; | ||
@@ -529,2 +530,4 @@ if ( offsetSnippet ) { | ||
| let snippet; | ||
| if ( depthSnippet ) { | ||
@@ -661,3 +664,3 @@ | ||
| console.error( `WebGPURenderer: THREE.TextureNode.gradient() does not support ${ shaderStage } shader.` ); | ||
| error( `WebGPURenderer: THREE.TextureNode.gradient() does not support ${ shaderStage } shader.` ); | ||
@@ -707,3 +710,3 @@ } | ||
| console.error( `WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${ shaderStage } shader.` ); | ||
| error( `WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${ shaderStage } shader.` ); | ||
@@ -776,3 +779,3 @@ } | ||
| console.error( `WebGPURenderer: THREE.TextureNode.biasNode does not support ${ shaderStage } shader.` ); | ||
| error( `WebGPURenderer: THREE.TextureNode.biasNode does not support ${ shaderStage } shader.` ); | ||
@@ -877,3 +880,3 @@ } | ||
| console.warn( 'WebGPURenderer: Atomic operations are only supported in compute shaders.' ); | ||
| warn( 'WebGPURenderer: Atomic operations are only supported in compute shaders.' ); | ||
@@ -961,2 +964,3 @@ return NodeAccess.READ_WRITE; | ||
| texture.store = node.isStorageTextureNode === true; | ||
| texture.mipLevel = texture.store ? node.mipLevel : 0; | ||
| texture.setVisibility( gpuShaderStageLib[ shaderStage ] ); | ||
@@ -1125,3 +1129,4 @@ | ||
| /** | ||
| * Returns the instance index builtin. | ||
| * Contextually returns either the vertex stage instance index builtin | ||
| * or the linearized index of an compute invocation within a grid of workgroups. | ||
| * | ||
@@ -1142,4 +1147,5 @@ * @return {string} The instance index. | ||
| /** | ||
| * Returns the invocation local index builtin. | ||
| * Returns a builtin representing the index of a compute invocation within the scope of a workgroup load. | ||
| * | ||
@@ -1155,3 +1161,3 @@ * @return {string} The invocation local index. | ||
| /** | ||
| * Returns the subgroup size builtin. | ||
| * Returns a builtin representing the size of a subgroup within the current shader. | ||
| * | ||
@@ -1169,3 +1175,3 @@ * @return {string} The subgroup size. | ||
| /** | ||
| * Returns the invocation subgroup index builtin. | ||
| * Returns a builtin representing the index of a compute invocation within the scope of a subgroup. | ||
| * | ||
@@ -1183,3 +1189,3 @@ * @return {string} The invocation subgroup index. | ||
| /** | ||
| * Returns the subgroup index builtin. | ||
| * Returns a builtin representing the index of a compute invocation's subgroup within its workgroup. | ||
| * | ||
@@ -2081,8 +2087,4 @@ * @return {string} The subgroup index. | ||
| if ( this.currentFunctionNode !== null ) { | ||
| this.addInclude( codeNode ); | ||
| this.currentFunctionNode.includes.push( codeNode ); | ||
| } | ||
| return codeNode; | ||
@@ -2089,0 +2091,0 @@ |
| import { GPUInputStepMode } from './WebGPUConstants.js'; | ||
| import { Float16BufferAttribute } from '../../../core/BufferAttribute.js'; | ||
| import { error } from '../../../utils.js'; | ||
@@ -409,3 +410,3 @@ const typedArraysToVertexFormatPrefix = new Map( [ | ||
| console.error( 'THREE.WebGPUAttributeUtils: Vertex format not supported yet.' ); | ||
| error( 'WebGPUAttributeUtils: Vertex format not supported yet.' ); | ||
@@ -412,0 +413,0 @@ } |
@@ -8,2 +8,3 @@ import { | ||
| import { NodeAccess } from '../../../nodes/core/constants.js'; | ||
| import { error } from '../../../utils.js'; | ||
@@ -226,3 +227,3 @@ /** | ||
| console.error( `WebGPUBindingUtils: Unsupported binding "${ binding }".` ); | ||
| error( `WebGPUBindingUtils: Unsupported binding "${ binding }".` ); | ||
@@ -419,2 +420,3 @@ } | ||
| const mipLevelCount = binding.store ? 1 : textureData.texture.mipLevelCount; | ||
| const baseMipLevel = binding.store ? binding.mipLevel : 0; | ||
| let propertyName = `view-${ textureData.texture.width }-${ textureData.texture.height }`; | ||
@@ -428,3 +430,3 @@ | ||
| propertyName += `-${ mipLevelCount }`; | ||
| propertyName += `-${ mipLevelCount }-${ baseMipLevel }`; | ||
@@ -457,3 +459,3 @@ resourceGPU = textureData[ propertyName ]; | ||
| resourceGPU = textureData[ propertyName ] = textureData.texture.createView( { aspect: aspectGPU, dimension: dimensionViewGPU, mipLevelCount } ); | ||
| resourceGPU = textureData[ propertyName ] = textureData.texture.createView( { aspect: aspectGPU, dimension: dimensionViewGPU, mipLevelCount, baseMipLevel } ); | ||
@@ -460,0 +462,0 @@ } |
@@ -340,1 +340,6 @@ export const GPUPrimitiveTopology = { | ||
| }; | ||
| export const GPUFeatureMap = { | ||
| 'texture-compression-s3tc': 'texture-compression-bc', | ||
| 'texture-compression-etc1': 'texture-compression-etc2' | ||
| }; |
@@ -18,2 +18,4 @@ import { BlendColorFactor, OneMinusBlendColorFactor, } from '../../common/Constants.js'; | ||
| import { error } from '../../../utils.js'; | ||
| /** | ||
@@ -233,3 +235,6 @@ * A WebGPU backend utility module for managing pipelines. | ||
| // create pipeline | ||
| device.pushErrorScope( 'validation' ); | ||
| if ( promises === null ) { | ||
@@ -239,13 +244,36 @@ | ||
| device.popErrorScope().then( ( err ) => { | ||
| if ( err !== null ) { | ||
| pipelineData.error = true; | ||
| error( err.message ); | ||
| } | ||
| } ); | ||
| } else { | ||
| const p = new Promise( ( resolve /*, reject*/ ) => { | ||
| const p = new Promise( async ( resolve /*, reject*/ ) => { | ||
| device.createRenderPipelineAsync( pipelineDescriptor ).then( pipeline => { | ||
| try { | ||
| pipelineData.pipeline = pipeline; | ||
| resolve(); | ||
| pipelineData.pipeline = await device.createRenderPipelineAsync( pipelineDescriptor ); | ||
| } ); | ||
| } catch ( err ) { } | ||
| const errorScope = await device.popErrorScope(); | ||
| if ( errorScope !== null ) { | ||
| pipelineData.error = true; | ||
| error( errorScope.message ); | ||
| } | ||
| resolve(); | ||
| } ); | ||
@@ -272,8 +300,8 @@ | ||
| const depthStencilFormat = utils.getCurrentDepthStencilFormat( renderContext ); | ||
| const colorFormat = utils.getCurrentColorFormat( renderContext ); | ||
| const colorFormats = utils.getCurrentColorFormats( renderContext ); | ||
| const sampleCount = this._getSampleCount( renderContext ); | ||
| const descriptor = { | ||
| label: label, | ||
| colorFormats: [ colorFormat ], | ||
| label, | ||
| colorFormats, | ||
| depthStencilFormat, | ||
@@ -414,7 +442,7 @@ sampleCount | ||
| case SubtractiveBlending: | ||
| console.error( 'THREE.WebGPURenderer: SubtractiveBlending requires material.premultipliedAlpha = true' ); | ||
| error( 'WebGPURenderer: SubtractiveBlending requires material.premultipliedAlpha = true' ); | ||
| break; | ||
| case MultiplyBlending: | ||
| console.error( 'THREE.WebGPURenderer: MultiplyBlending requires material.premultipliedAlpha = true' ); | ||
| error( 'WebGPURenderer: MultiplyBlending requires material.premultipliedAlpha = true' ); | ||
| break; | ||
@@ -434,3 +462,3 @@ | ||
| console.error( 'THREE.WebGPURenderer: Invalid blending: ', blending ); | ||
| error( 'WebGPURenderer: Invalid blending: ', blending ); | ||
@@ -506,3 +534,3 @@ } | ||
| default: | ||
| console.error( 'THREE.WebGPURenderer: Blend factor not supported.', blend ); | ||
| error( 'WebGPURenderer: Blend factor not supported.', blend ); | ||
@@ -563,3 +591,3 @@ } | ||
| default: | ||
| console.error( 'THREE.WebGPURenderer: Invalid stencil function.', stencilFunc ); | ||
| error( 'WebGPURenderer: Invalid stencil function.', stencilFunc ); | ||
@@ -618,3 +646,3 @@ } | ||
| default: | ||
| console.error( 'THREE.WebGPURenderer: Invalid stencil operation.', stencilOperation ); | ||
| error( 'WebGPURenderer: Invalid stencil operation.', stencilOperation ); | ||
@@ -661,3 +689,3 @@ } | ||
| default: | ||
| console.error( 'THREE.WebGPUPipelineUtils: Blend equation not supported.', blendEquation ); | ||
| error( 'WebGPUPipelineUtils: Blend equation not supported.', blendEquation ); | ||
@@ -778,3 +806,3 @@ } | ||
| default: | ||
| console.error( 'THREE.WebGPUPipelineUtils: Invalid depth function.', depthFunc ); | ||
| error( 'WebGPUPipelineUtils: Invalid depth function.', depthFunc ); | ||
@@ -781,0 +809,0 @@ } |
@@ -313,10 +313,10 @@ import DataMap from '../../common/DataMap.js'; | ||
| * @param {number} [baseArrayLayer=0] - The index of the first array layer accessible to the texture view. | ||
| * @param {?GPUCommandEncoder} [encoder=null] - An optional command encoder used to generate mipmaps. | ||
| */ | ||
| generateMipmaps( textureGPU, textureGPUDescriptor, baseArrayLayer = 0 ) { | ||
| generateMipmaps( textureGPU, textureGPUDescriptor, baseArrayLayer = 0, encoder = null ) { | ||
| const textureData = this.get( textureGPU ); | ||
| if ( textureData.useCount === undefined ) { | ||
| if ( textureData.layers === undefined ) { | ||
| textureData.useCount = 0; | ||
| textureData.layers = []; | ||
@@ -328,12 +328,10 @@ | ||
| const commandEncoder = this.device.createCommandEncoder( {} ); | ||
| const commandEncoder = encoder || this.device.createCommandEncoder( { label: 'mipmapEncoder' } ); | ||
| this._mipmapRunBundles( commandEncoder, passes ); | ||
| this.device.queue.submit( [ commandEncoder.finish() ] ); | ||
| if ( encoder === null ) this.device.queue.submit( [ commandEncoder.finish() ] ); | ||
| if ( textureData.useCount !== 0 ) textureData.layers[ baseArrayLayer ] = passes; | ||
| textureData.layers[ baseArrayLayer ] = passes; | ||
| textureData.useCount ++; | ||
| } | ||
@@ -340,0 +338,0 @@ |
@@ -20,4 +20,4 @@ import { | ||
| import { CubeTexture } from '../../../textures/CubeTexture.js'; | ||
| import { DepthTexture } from '../../../textures/DepthTexture.js'; | ||
| import { Texture } from '../../../textures/Texture.js'; | ||
| import { warn, error } from '../../../utils.js'; | ||
@@ -91,17 +91,8 @@ const _compareToWebGPU = { | ||
| /** | ||
| * Represents the color attachment of the default framebuffer. | ||
| * A cache of shared texture samplers. | ||
| * | ||
| * @type {?GPUTexture} | ||
| * @default null | ||
| * @type {Map<string, Object>} | ||
| */ | ||
| this.colorBuffer = null; | ||
| this._samplerCache = new Map(); | ||
| /** | ||
| * Represents the depth attachment of the default framebuffer. | ||
| * | ||
| * @type {DepthTexture} | ||
| */ | ||
| this.depthTexture = new DepthTexture(); | ||
| this.depthTexture.name = 'depthBuffer'; | ||
| } | ||
@@ -113,35 +104,77 @@ | ||
| * @param {Texture} texture - The texture to create the sampler for. | ||
| * @return {string} The current sampler key. | ||
| */ | ||
| createSampler( texture ) { | ||
| updateSampler( texture ) { | ||
| const backend = this.backend; | ||
| const device = backend.device; | ||
| const textureGPU = backend.get( texture ); | ||
| const samplerKey = texture.minFilter + '-' + texture.magFilter + '-' + | ||
| texture.wrapS + '-' + texture.wrapT + '-' + ( texture.wrapR || '0' ) + '-' + | ||
| texture.anisotropy + '-' + ( texture.compareFunction || 0 ); | ||
| const samplerDescriptorGPU = { | ||
| addressModeU: this._convertAddressMode( texture.wrapS ), | ||
| addressModeV: this._convertAddressMode( texture.wrapT ), | ||
| addressModeW: this._convertAddressMode( texture.wrapR ), | ||
| magFilter: this._convertFilterMode( texture.magFilter ), | ||
| minFilter: this._convertFilterMode( texture.minFilter ), | ||
| mipmapFilter: this._convertFilterMode( texture.minFilter ), | ||
| maxAnisotropy: 1 | ||
| }; | ||
| let samplerData = this._samplerCache.get( samplerKey ); | ||
| // anisotropy can only be used when all filter modes are set to linear. | ||
| if ( samplerData === undefined ) { | ||
| if ( samplerDescriptorGPU.magFilter === GPUFilterMode.Linear && samplerDescriptorGPU.minFilter === GPUFilterMode.Linear && samplerDescriptorGPU.mipmapFilter === GPUFilterMode.Linear ) { | ||
| const samplerDescriptorGPU = { | ||
| addressModeU: this._convertAddressMode( texture.wrapS ), | ||
| addressModeV: this._convertAddressMode( texture.wrapT ), | ||
| addressModeW: this._convertAddressMode( texture.wrapR ), | ||
| magFilter: this._convertFilterMode( texture.magFilter ), | ||
| minFilter: this._convertFilterMode( texture.minFilter ), | ||
| mipmapFilter: this._convertFilterMode( texture.minFilter ), | ||
| maxAnisotropy: 1 | ||
| }; | ||
| samplerDescriptorGPU.maxAnisotropy = texture.anisotropy; | ||
| // anisotropy can only be used when all filter modes are set to linear. | ||
| if ( samplerDescriptorGPU.magFilter === GPUFilterMode.Linear && samplerDescriptorGPU.minFilter === GPUFilterMode.Linear && samplerDescriptorGPU.mipmapFilter === GPUFilterMode.Linear ) { | ||
| samplerDescriptorGPU.maxAnisotropy = texture.anisotropy; | ||
| } | ||
| if ( texture.isDepthTexture && texture.compareFunction !== null ) { | ||
| samplerDescriptorGPU.compare = _compareToWebGPU[ texture.compareFunction ]; | ||
| } | ||
| const sampler = backend.device.createSampler( samplerDescriptorGPU ); | ||
| samplerData = { sampler, usedTimes: 0 }; | ||
| this._samplerCache.set( samplerKey, samplerData ); | ||
| } | ||
| if ( texture.isDepthTexture && texture.compareFunction !== null ) { | ||
| const textureData = backend.get( texture ); | ||
| samplerDescriptorGPU.compare = _compareToWebGPU[ texture.compareFunction ]; | ||
| if ( textureData.sampler !== samplerData.sampler ) { | ||
| // check if previous sampler is unused so it can be deleted | ||
| if ( textureData.sampler !== undefined ) { | ||
| const oldSamplerData = this._samplerCache.get( textureData.samplerKey ); | ||
| oldSamplerData.usedTimes --; | ||
| if ( oldSamplerData.usedTimes === 0 ) { | ||
| this._samplerCache.delete( textureData.samplerKey ); | ||
| } | ||
| } | ||
| // update to new sampler data | ||
| textureData.samplerKey = samplerKey; | ||
| textureData.sampler = samplerData.sampler; | ||
| samplerData.usedTimes ++; | ||
| } | ||
| textureGPU.sampler = device.createSampler( samplerDescriptorGPU ); | ||
| return samplerKey; | ||
@@ -261,3 +294,3 @@ } | ||
| console.warn( 'WebGPURenderer: Texture format not supported.' ); | ||
| warn( 'WebGPURenderer: Texture format not supported.' ); | ||
@@ -299,4 +332,5 @@ this.createDefaultTexture( texture ); | ||
| * @param {Texture} texture - The texture. | ||
| * @param {boolean} [isDefaultTexture=false] - Whether the texture uses a default GPU texture or not. | ||
| */ | ||
| destroyTexture( texture ) { | ||
| destroyTexture( texture, isDefaultTexture = false ) { | ||
@@ -306,3 +340,3 @@ const backend = this.backend; | ||
| if ( textureData.texture !== undefined ) textureData.texture.destroy(); | ||
| if ( textureData.texture !== undefined && isDefaultTexture === false ) textureData.texture.destroy(); | ||
@@ -316,21 +350,8 @@ if ( textureData.msaaTexture !== undefined ) textureData.msaaTexture.destroy(); | ||
| /** | ||
| * Destroys the GPU sampler for the given texture. | ||
| * | ||
| * @param {Texture} texture - The texture to destroy the sampler for. | ||
| */ | ||
| destroySampler( texture ) { | ||
| const backend = this.backend; | ||
| const textureData = backend.get( texture ); | ||
| delete textureData.sampler; | ||
| } | ||
| /** | ||
| * Generates mipmaps for the given texture. | ||
| * | ||
| * @param {Texture} texture - The texture. | ||
| * @param {?GPUCommandEncoder} [encoder=null] - An optional command encoder used to generate mipmaps. | ||
| */ | ||
| generateMipmaps( texture ) { | ||
| generateMipmaps( texture, encoder = null ) { | ||
@@ -343,3 +364,3 @@ const textureData = this.backend.get( texture ); | ||
| this._generateMipmaps( textureData.texture, textureData.textureDescriptorGPU, i ); | ||
| this._generateMipmaps( textureData.texture, textureData.textureDescriptorGPU, i, encoder ); | ||
@@ -354,3 +375,3 @@ } | ||
| this._generateMipmaps( textureData.texture, textureData.textureDescriptorGPU, i ); | ||
| this._generateMipmaps( textureData.texture, textureData.textureDescriptorGPU, i, encoder ); | ||
@@ -371,8 +392,23 @@ } | ||
| if ( this.colorBuffer ) this.colorBuffer.destroy(); | ||
| const backend = this.backend; | ||
| const canvasTarget = backend.renderer.getCanvasTarget(); | ||
| const { width, height } = backend.getDrawingBufferSize(); | ||
| const samples = backend.renderer.currentSamples; | ||
| this.colorBuffer = backend.device.createTexture( { | ||
| const colorTexture = canvasTarget.colorTexture; | ||
| const colorTextureData = backend.get( colorTexture ); | ||
| if ( colorTexture.width === width && colorTexture.height === height && colorTexture.samples === samples ) { | ||
| return colorTextureData.texture; | ||
| } | ||
| // recreate | ||
| let colorBuffer = colorTextureData.texture; | ||
| if ( colorBuffer ) colorBuffer.destroy(); | ||
| colorBuffer = backend.device.createTexture( { | ||
| label: 'colorBuffer', | ||
@@ -384,3 +420,3 @@ size: { | ||
| }, | ||
| sampleCount: backend.utils.getSampleCount( backend.renderer.samples ), | ||
| sampleCount: backend.utils.getSampleCount( backend.renderer.currentSamples ), | ||
| format: backend.utils.getPreferredCanvasFormat(), | ||
@@ -390,4 +426,12 @@ usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC | ||
| return this.colorBuffer; | ||
| // | ||
| colorTexture.source.width = width; | ||
| colorTexture.source.height = height; | ||
| colorTexture.samples = samples; | ||
| colorTextureData.texture = colorBuffer; | ||
| return colorBuffer; | ||
| } | ||
@@ -406,5 +450,20 @@ | ||
| const backend = this.backend; | ||
| const canvasTarget = backend.renderer.getCanvasTarget(); | ||
| const { width, height } = backend.getDrawingBufferSize(); | ||
| const samples = backend.renderer.currentSamples; | ||
| const depthTexture = this.depthTexture; | ||
| const depthTexture = canvasTarget.depthTexture; | ||
| if ( depthTexture.width === width && | ||
| depthTexture.height === height && | ||
| depthTexture.samples === samples && | ||
| depthTexture.depth === depth && | ||
| depthTexture.stencil === stencil ) { | ||
| return backend.get( depthTexture ).texture; | ||
| } | ||
| // | ||
| const depthTextureGPU = backend.get( depthTexture ).texture; | ||
@@ -428,3 +487,3 @@ | ||
| if ( depthTexture.image.width === width && depthTexture.image.height === height && depthTexture.format === format && depthTexture.type === type ) { | ||
| if ( depthTexture.image.width === width && depthTexture.image.height === height && depthTexture.format === format && depthTexture.type === type && depthTexture.samples === samples ) { | ||
@@ -439,2 +498,4 @@ return depthTextureGPU; | ||
| // recreate | ||
| depthTexture.name = 'depthBuffer'; | ||
@@ -445,2 +506,3 @@ depthTexture.format = format; | ||
| depthTexture.image.height = height; | ||
| depthTexture.samples = samples; | ||
@@ -595,2 +657,11 @@ this.createTexture( depthTexture, { width, height } ); | ||
| /** | ||
| * Frees all internal resources. | ||
| */ | ||
| dispose() { | ||
| this._samplerCache.clear(); | ||
| } | ||
| /** | ||
| * Returns the default GPU texture for the given format. | ||
@@ -764,6 +835,7 @@ * | ||
| * @param {number} [baseArrayLayer=0] - The index of the first array layer accessible to the texture view. | ||
| * @param {?GPUCommandEncoder} [encoder=null] - An optional command encoder used to generate mipmaps. | ||
| */ | ||
| _generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer = 0 ) { | ||
| _generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer = 0, encoder = null ) { | ||
| this._getPassUtils().generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer ); | ||
| this._getPassUtils().generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer, encoder ); | ||
@@ -1249,3 +1321,3 @@ } | ||
| default: | ||
| console.error( 'WebGPURenderer: Unsupported texture format.', format ); | ||
| error( 'WebGPURenderer: Unsupported texture format.', format ); | ||
@@ -1294,3 +1366,3 @@ } | ||
| default: | ||
| console.error( 'WebGPURenderer: Unsupported texture type with RGBAFormat.', type ); | ||
| error( 'WebGPURenderer: Unsupported texture type with RGBAFormat.', type ); | ||
@@ -1314,3 +1386,3 @@ } | ||
| default: | ||
| console.error( 'WebGPURenderer: Unsupported texture type with RGBFormat.', type ); | ||
| error( 'WebGPURenderer: Unsupported texture type with RGBFormat.', type ); | ||
@@ -1358,3 +1430,3 @@ } | ||
| default: | ||
| console.error( 'WebGPURenderer: Unsupported texture type with RedFormat.', type ); | ||
| error( 'WebGPURenderer: Unsupported texture type with RedFormat.', type ); | ||
@@ -1402,3 +1474,3 @@ } | ||
| default: | ||
| console.error( 'WebGPURenderer: Unsupported texture type with RGFormat.', type ); | ||
| error( 'WebGPURenderer: Unsupported texture type with RGFormat.', type ); | ||
@@ -1426,3 +1498,3 @@ } | ||
| default: | ||
| console.error( 'WebGPURenderer: Unsupported texture type with DepthFormat.', type ); | ||
| error( 'WebGPURenderer: Unsupported texture type with DepthFormat.', type ); | ||
@@ -1445,3 +1517,3 @@ } | ||
| console.error( 'WebGPURenderer: Depth textures with DepthStencilFormat + FloatType can only be used with the "depth32float-stencil8" GPU feature.' ); | ||
| error( 'WebGPURenderer: Depth textures with DepthStencilFormat + FloatType can only be used with the "depth32float-stencil8" GPU feature.' ); | ||
@@ -1455,3 +1527,3 @@ } | ||
| default: | ||
| console.error( 'WebGPURenderer: Unsupported texture type with DepthStencilFormat.', type ); | ||
| error( 'WebGPURenderer: Unsupported texture type with DepthStencilFormat.', type ); | ||
@@ -1475,3 +1547,3 @@ } | ||
| default: | ||
| console.error( 'WebGPURenderer: Unsupported texture type with RedIntegerFormat.', type ); | ||
| error( 'WebGPURenderer: Unsupported texture type with RedIntegerFormat.', type ); | ||
@@ -1495,3 +1567,3 @@ } | ||
| default: | ||
| console.error( 'WebGPURenderer: Unsupported texture type with RGIntegerFormat.', type ); | ||
| error( 'WebGPURenderer: Unsupported texture type with RGIntegerFormat.', type ); | ||
@@ -1515,3 +1587,3 @@ } | ||
| default: | ||
| console.error( 'WebGPURenderer: Unsupported texture type with RGBAIntegerFormat.', type ); | ||
| error( 'WebGPURenderer: Unsupported texture type with RGBAIntegerFormat.', type ); | ||
@@ -1523,3 +1595,3 @@ } | ||
| default: | ||
| console.error( 'WebGPURenderer: Unsupported texture format.', format ); | ||
| error( 'WebGPURenderer: Unsupported texture format.', format ); | ||
@@ -1526,0 +1598,0 @@ } |
@@ -67,2 +67,3 @@ import { warnOnce } from '../../../utils.js'; | ||
| this.queryOffsets.set( uid, baseOffset ); | ||
| return baseOffset; | ||
@@ -181,16 +182,38 @@ | ||
| // | ||
| const times = new BigUint64Array( this.resultBuffer.getMappedRange( 0, bytesUsed ) ); | ||
| let totalDuration = 0; | ||
| const framesDuration = {}; | ||
| for ( const [ , baseOffset ] of currentOffsets ) { | ||
| const frames = []; | ||
| for ( const [ uid, baseOffset ] of currentOffsets ) { | ||
| const match = uid.match( /^(.*):f(\d+)$/ ); | ||
| const frame = parseInt( match[ 2 ] ); | ||
| if ( frames.includes( frame ) === false ) { | ||
| frames.push( frame ); | ||
| } | ||
| if ( framesDuration[ frame ] === undefined ) framesDuration[ frame ] = 0; | ||
| const startTime = times[ baseOffset ]; | ||
| const endTime = times[ baseOffset + 1 ]; | ||
| const duration = Number( endTime - startTime ) / 1e6; | ||
| totalDuration += duration; | ||
| this.timestamps.set( uid, duration ); | ||
| framesDuration[ frame ] += duration; | ||
| } | ||
| // Return the total duration of the last frame | ||
| const totalDuration = framesDuration[ frames[ frames.length - 1 ] ]; | ||
| this.resultBuffer.unmap(); | ||
| this.lastValue = totalDuration; | ||
| this.frames = frames; | ||
@@ -201,3 +224,3 @@ return totalDuration; | ||
| console.error( 'Error resolving queries:', error ); | ||
| error( 'Error resolving queries:', error ); | ||
| if ( this.resultBuffer.mapState === 'mapped' ) { | ||
@@ -240,3 +263,3 @@ | ||
| console.error( 'Error waiting for pending resolve:', error ); | ||
| error( 'Error waiting for pending resolve:', error ); | ||
@@ -256,3 +279,3 @@ } | ||
| console.error( 'Error unmapping buffer:', error ); | ||
| error( 'Error unmapping buffer:', error ); | ||
@@ -259,0 +282,0 @@ } |
@@ -86,3 +86,3 @@ import { HalfFloatType, UnsignedByteType } from '../../../constants.js'; | ||
| samples = renderTarget ? renderTarget.samples : renderer.samples; | ||
| samples = renderTarget ? renderTarget.samples : renderer.currentSamples; | ||
@@ -129,2 +129,22 @@ } else if ( texture.renderTarget ) { | ||
| /** | ||
| * Returns the GPU formats of all color attachments of the current render context. | ||
| * | ||
| * @param {RenderContext} renderContext - The render context. | ||
| * @return {Array<string>} The GPU texture formats of all color attachments. | ||
| */ | ||
| getCurrentColorFormats( renderContext ) { | ||
| if ( renderContext.textures !== null ) { | ||
| return renderContext.textures.map( t => this.getTextureFormatGPU( t ) ); | ||
| } else { | ||
| return [ this.getPreferredCanvasFormat() ]; // default context format | ||
| } | ||
| } | ||
| /** | ||
| * Returns the output color space of the current render context. | ||
@@ -191,3 +211,3 @@ * | ||
| return this.getSampleCount( this.backend.renderer.samples ); | ||
| return this.getSampleCount( this.backend.renderer.currentSamples ); | ||
@@ -194,0 +214,0 @@ } |
@@ -5,2 +5,3 @@ import Renderer from '../common/Renderer.js'; | ||
| import StandardNodeLibrary from './nodes/StandardNodeLibrary.js'; | ||
| import { warn } from '../../utils.js'; | ||
| /* | ||
@@ -12,3 +13,3 @@ const debugHandler = { | ||
| // Add |update | ||
| if ( /^(create|destroy)/.test( name ) ) console.log( 'WebGPUBackend.' + name ); | ||
| if ( /^(create|destroy)/.test( name ) ) log( 'WebGPUBackend.' + name ); | ||
@@ -67,3 +68,3 @@ return target[ name ]; | ||
| console.warn( 'THREE.WebGPURenderer: WebGPU is not available, running under WebGL2 backend.' ); | ||
| warn( 'WebGPURenderer: WebGPU is not available, running under WebGL2 backend.' ); | ||
@@ -70,0 +71,0 @@ return new WebGLBackend( parameters ); |
@@ -5,2 +5,3 @@ import Renderer from '../common/Renderer.js'; | ||
| import BasicNodeLibrary from './nodes/BasicNodeLibrary.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -35,3 +36,3 @@ /** | ||
| console.warn( 'THREE.WebGPURenderer: WebGPU is not available, running under WebGL2 backend.' ); | ||
| warn( 'WebGPURenderer: WebGPU is not available, running under WebGL2 backend.' ); | ||
@@ -38,0 +39,0 @@ return new WebGLBackend( parameters ); |
@@ -15,2 +15,3 @@ import { ArrayCamera } from '../../cameras/ArrayCamera.js'; | ||
| import { WebXRDepthSensing } from './WebXRDepthSensing.js'; | ||
| import { warn } from '../../utils.js'; | ||
@@ -282,3 +283,3 @@ /** | ||
| console.warn( 'THREE.WebXRManager: Cannot change framebuffer scale while presenting.' ); | ||
| warn( 'WebXRManager: Cannot change framebuffer scale while presenting.' ); | ||
@@ -305,3 +306,3 @@ } | ||
| console.warn( 'THREE.WebXRManager: Cannot change reference space type while presenting.' ); | ||
| warn( 'WebXRManager: Cannot change reference space type while presenting.' ); | ||
@@ -308,0 +309,0 @@ } |
| import { ImageUtils } from '../extras/ImageUtils.js'; | ||
| import { generateUUID } from '../math/MathUtils.js'; | ||
| import { warn } from '../utils.js'; | ||
@@ -220,3 +221,3 @@ let _sourceId = 0; | ||
| console.warn( 'THREE.Texture: Unable to serialize Texture.' ); | ||
| warn( 'Texture: Unable to serialize Texture.' ); | ||
| return {}; | ||
@@ -223,0 +224,0 @@ |
@@ -18,2 +18,3 @@ import { EventDispatcher } from '../core/EventDispatcher.js'; | ||
| import { Source } from './Source.js'; | ||
| import { warn } from '../utils.js'; | ||
@@ -525,3 +526,3 @@ let _textureId = 0; | ||
| console.warn( `THREE.Texture.setValues(): parameter '${ key }' has value of undefined.` ); | ||
| warn( `Texture.setValues(): parameter '${ key }' has value of undefined.` ); | ||
| continue; | ||
@@ -535,3 +536,3 @@ | ||
| console.warn( `THREE.Texture.setValues(): property '${ key }' does not exist.` ); | ||
| warn( `Texture.setValues(): property '${ key }' does not exist.` ); | ||
| continue; | ||
@@ -538,0 +539,0 @@ |
@@ -117,2 +117,4 @@ import { LinearFilter } from '../constants.js'; | ||
| this._requestVideoFrameCallbackId = 0; | ||
| } | ||
@@ -119,0 +121,0 @@ |
| import { REVISION } from './constants.js'; | ||
| import { warn } from './utils.js'; | ||
@@ -160,3 +161,3 @@ export { WebGLArrayRenderTarget } from './renderers/WebGLArrayRenderTarget.js'; | ||
| export { TextureUtils } from './extras/TextureUtils.js'; | ||
| export { createCanvasElement } from './utils.js'; | ||
| export { createCanvasElement, setConsoleFunction, getConsoleFunction, log, warn, error, warnOnce } from './utils.js'; | ||
| export * from './constants.js'; | ||
@@ -177,3 +178,3 @@ export * from './Three.Legacy.js'; | ||
| console.warn( 'WARNING: Multiple instances of Three.js being imported.' ); | ||
| warn( 'WARNING: Multiple instances of Three.js being imported.' ); | ||
@@ -180,0 +181,0 @@ } else { |
+7
-1
@@ -27,2 +27,4 @@ import { TSL } from 'three/webgpu'; | ||
| export const PI2 = TSL.PI2; | ||
| export const TWO_PI = TSL.TWO_PI; | ||
| export const HALF_PI = TSL.HALF_PI; | ||
| export const PointShadowFilter = TSL.PointShadowFilter; | ||
@@ -200,2 +202,3 @@ export const Return = TSL.Return; | ||
| export const getNormalFromDepth = TSL.getNormalFromDepth; | ||
| export const interleavedGradientNoise = TSL.interleavedGradientNoise; | ||
| export const getParallaxCorrectNormal = TSL.getParallaxCorrectNormal; | ||
@@ -401,2 +404,4 @@ export const getRoughness = TSL.getRoughness; | ||
| export const objectWorldMatrix = TSL.objectWorldMatrix; | ||
| export const OnBeforeObjectUpdate = TSL.OnBeforeObjectUpdate; | ||
| export const OnBeforeMaterialUpdate = TSL.OnBeforeMaterialUpdate; | ||
| export const OnObjectUpdate = TSL.OnObjectUpdate; | ||
@@ -553,2 +558,3 @@ export const OnMaterialUpdate = TSL.OnMaterialUpdate; | ||
| export const textureSize = TSL.textureSize; | ||
| export const textureLevel = TSL.textureLevel; | ||
| export const textureStore = TSL.textureStore; | ||
@@ -630,3 +636,3 @@ export const thickness = TSL.thickness; | ||
| console.log( code ); | ||
| log( code ); | ||
| //*/ |
@@ -23,2 +23,4 @@ export * from './Three.Core.js'; | ||
| export { default as NodeMaterialLoader } from './loaders/nodes/NodeMaterialLoader.js'; | ||
| export { default as InspectorBase } from './renderers/common/InspectorBase.js'; | ||
| export { default as CanvasTarget } from './renderers/common/CanvasTarget.js'; | ||
| export { ClippingGroup } from './objects/ClippingGroup.js'; | ||
@@ -25,0 +27,0 @@ export * from './nodes/Nodes.js'; |
@@ -21,2 +21,4 @@ export * from './Three.Core.js'; | ||
| export { default as NodeMaterialLoader } from './loaders/nodes/NodeMaterialLoader.js'; | ||
| export { default as InspectorBase } from './renderers/common/InspectorBase.js'; | ||
| export { default as CanvasTarget } from './renderers/common/CanvasTarget.js'; | ||
| export { ClippingGroup } from './objects/ClippingGroup.js'; | ||
@@ -23,0 +25,0 @@ export * from './nodes/Nodes.js'; |
+67
-3
@@ -81,4 +81,68 @@ function arrayMin( array ) { | ||
| function warnOnce( message ) { | ||
| let _setConsoleFunction = null; | ||
| function setConsoleFunction( fn ) { | ||
| _setConsoleFunction = fn; | ||
| } | ||
| function getConsoleFunction() { | ||
| return _setConsoleFunction; | ||
| } | ||
| function log( ...params ) { | ||
| const message = 'THREE.' + params.shift(); | ||
| if ( _setConsoleFunction ) { | ||
| _setConsoleFunction( 'log', message, ...params ); | ||
| } else { | ||
| console.log( message, ...params ); | ||
| } | ||
| } | ||
| function warn( ...params ) { | ||
| const message = 'THREE.' + params.shift(); | ||
| if ( _setConsoleFunction ) { | ||
| _setConsoleFunction( 'warn', message, ...params ); | ||
| } else { | ||
| console.warn( message, ...params ); | ||
| } | ||
| } | ||
| function error( ...params ) { | ||
| const message = 'THREE.' + params.shift(); | ||
| if ( _setConsoleFunction ) { | ||
| _setConsoleFunction( 'error', message, ...params ); | ||
| } else { | ||
| console.error( message, ...params ); | ||
| } | ||
| } | ||
| function warnOnce( ...params ) { | ||
| const message = params.join( ' ' ); | ||
| if ( message in _cache ) return; | ||
@@ -88,3 +152,3 @@ | ||
| console.warn( message ); | ||
| warn( ...params ); | ||
@@ -154,2 +218,2 @@ } | ||
| export { arrayMin, arrayMax, arrayNeedsUint32, getTypedArray, createElementNS, createCanvasElement, warnOnce, probeAsync, toNormalizedProjectionMatrix, toReversedProjectionMatrix }; | ||
| export { arrayMin, arrayMax, arrayNeedsUint32, getTypedArray, createElementNS, createCanvasElement, setConsoleFunction, getConsoleFunction, log, warn, error, warnOnce, probeAsync, toNormalizedProjectionMatrix, toReversedProjectionMatrix }; |
| import Node from './Node.js'; | ||
| import { addMethodChaining, nodeObject } from '../tsl/TSLCore.js'; | ||
| /** | ||
| * This node can be used as a cache management component for another node. | ||
| * Caching is in general used by default in {@link NodeBuilder} but this node | ||
| * allows the usage of a shared parent cache during the build process. | ||
| * | ||
| * @augments Node | ||
| */ | ||
| class CacheNode extends Node { | ||
| static get type() { | ||
| return 'CacheNode'; | ||
| } | ||
| /** | ||
| * Constructs a new cache node. | ||
| * | ||
| * @param {Node} node - The node that should be cached. | ||
| * @param {boolean} [parent=true] - Whether this node refers to a shared parent cache or not. | ||
| */ | ||
| constructor( node, parent = true ) { | ||
| super(); | ||
| /** | ||
| * The node that should be cached. | ||
| * | ||
| * @type {Node} | ||
| */ | ||
| this.node = node; | ||
| /** | ||
| * Whether this node refers to a shared parent cache or not. | ||
| * | ||
| * @type {boolean} | ||
| * @default true | ||
| */ | ||
| this.parent = parent; | ||
| /** | ||
| * This flag can be used for type testing. | ||
| * | ||
| * @type {boolean} | ||
| * @readonly | ||
| * @default true | ||
| */ | ||
| this.isCacheNode = true; | ||
| } | ||
| getNodeType( builder ) { | ||
| const previousCache = builder.getCache(); | ||
| const cache = builder.getCacheFromNode( this, this.parent ); | ||
| builder.setCache( cache ); | ||
| const nodeType = this.node.getNodeType( builder ); | ||
| builder.setCache( previousCache ); | ||
| return nodeType; | ||
| } | ||
| build( builder, ...params ) { | ||
| const previousCache = builder.getCache(); | ||
| const cache = builder.getCacheFromNode( this, this.parent ); | ||
| builder.setCache( cache ); | ||
| const data = this.node.build( builder, ...params ); | ||
| builder.setCache( previousCache ); | ||
| return data; | ||
| } | ||
| } | ||
| export default CacheNode; | ||
| /** | ||
| * TSL function for creating a cache node. | ||
| * | ||
| * @tsl | ||
| * @function | ||
| * @param {Node} node - The node that should be cached. | ||
| * @param {boolean} [parent] - Whether this node refers to a shared parent cache or not. | ||
| * @returns {CacheNode} | ||
| */ | ||
| export const cache = ( node, parent ) => nodeObject( new CacheNode( nodeObject( node ), parent ) ); | ||
| addMethodChaining( 'cache', cache ); |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 2 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 2 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
35828142
16.46%17
-19.05%1141
2.15%501078
2.27%883
1.73%