Buckets:
| import { hash, hashString } from '../../nodes/core/NodeUtils.js'; | |
| let _id = 0; | |
| function getKeys( obj ) { | |
| const keys = Object.keys( obj ); | |
| let proto = Object.getPrototypeOf( obj ); | |
| while ( proto ) { | |
| const descriptors = Object.getOwnPropertyDescriptors( proto ); | |
| for ( const key in descriptors ) { | |
| if ( descriptors[ key ] !== undefined ) { | |
| const descriptor = descriptors[ key ]; | |
| if ( descriptor && typeof descriptor.get === 'function' ) { | |
| keys.push( key ); | |
| } | |
| } | |
| } | |
| proto = Object.getPrototypeOf( proto ); | |
| } | |
| return keys; | |
| } | |
| /** | |
| * A render object is the renderer's representation of single entity that gets drawn | |
| * with a draw command. There is no unique mapping of render objects to 3D objects in the | |
| * scene since render objects also depend from the used material, the current render context | |
| * and the current scene's lighting. | |
| * | |
| * In general, the basic process of the renderer is: | |
| * | |
| * - Analyze the 3D objects in the scene and generate render lists containing render items. | |
| * - Process the render lists by calling one or more render commands for each render item. | |
| * - For each render command, request a render object and perform the draw. | |
| * | |
| * The module provides an interface to get data required for the draw command like the actual | |
| * draw parameters or vertex buffers. It also holds a series of caching related methods since | |
| * creating render objects should only be done when necessary. | |
| * | |
| * @private | |
| */ | |
| class RenderObject { | |
| /** | |
| * Constructs a new render object. | |
| * | |
| * @param {Nodes} nodes - Renderer component for managing nodes related logic. | |
| * @param {Geometries} geometries - Renderer component for managing geometries. | |
| * @param {Renderer} renderer - The renderer. | |
| * @param {Object3D} object - The 3D object. | |
| * @param {Material} material - The 3D object's material. | |
| * @param {Scene} scene - The scene the 3D object belongs to. | |
| * @param {Camera} camera - The camera the object should be rendered with. | |
| * @param {LightsNode} lightsNode - The lights node. | |
| * @param {RenderContext} renderContext - The render context. | |
| * @param {ClippingContext} clippingContext - The clipping context. | |
| */ | |
| constructor( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext ) { | |
| this.id = _id ++; | |
| /** | |
| * Renderer component for managing nodes related logic. | |
| * | |
| * @type {Nodes} | |
| * @private | |
| */ | |
| this._nodes = nodes; | |
| /** | |
| * Renderer component for managing geometries. | |
| * | |
| * @type {Geometries} | |
| * @private | |
| */ | |
| this._geometries = geometries; | |
| /** | |
| * The renderer. | |
| * | |
| * @type {Renderer} | |
| */ | |
| this.renderer = renderer; | |
| /** | |
| * The 3D object. | |
| * | |
| * @type {Object3D} | |
| */ | |
| this.object = object; | |
| /** | |
| * The 3D object's material. | |
| * | |
| * @type {Material} | |
| */ | |
| this.material = material; | |
| /** | |
| * The scene the 3D object belongs to. | |
| * | |
| * @type {Scene} | |
| */ | |
| this.scene = scene; | |
| /** | |
| * The camera the 3D object should be rendered with. | |
| * | |
| * @type {Camera} | |
| */ | |
| this.camera = camera; | |
| /** | |
| * The lights node. | |
| * | |
| * @type {LightsNode} | |
| */ | |
| this.lightsNode = lightsNode; | |
| /** | |
| * The render context. | |
| * | |
| * @type {RenderContext} | |
| */ | |
| this.context = renderContext; | |
| /** | |
| * The 3D object's geometry. | |
| * | |
| * @type {BufferGeometry} | |
| */ | |
| this.geometry = object.geometry; | |
| /** | |
| * The render object's version. | |
| * | |
| * @type {number} | |
| */ | |
| this.version = material.version; | |
| /** | |
| * The draw range of the geometry. | |
| * | |
| * @type {?Object} | |
| * @default null | |
| */ | |
| this.drawRange = null; | |
| /** | |
| * An array holding the buffer attributes | |
| * of the render object. This entails attribute | |
| * definitions on geometry and node level. | |
| * | |
| * @type {?Array<BufferAttribute>} | |
| * @default null | |
| */ | |
| this.attributes = null; | |
| /** | |
| * A reference to a render pipeline the render | |
| * object is processed with. | |
| * | |
| * @type {RenderPipeline} | |
| * @default null | |
| */ | |
| this.pipeline = null; | |
| /** | |
| * Only relevant for objects using | |
| * multiple materials. This represents a group entry | |
| * from the respective `BufferGeometry`. | |
| * | |
| * @type {?{start: number, count: number}} | |
| * @default null | |
| */ | |
| this.group = null; | |
| /** | |
| * An array holding the vertex buffers which can | |
| * be buffer attributes but also interleaved buffers. | |
| * | |
| * @type {?Array<BufferAttribute|InterleavedBuffer>} | |
| * @default null | |
| */ | |
| this.vertexBuffers = null; | |
| /** | |
| * The parameters for the draw command. | |
| * | |
| * @type {?Object} | |
| * @default null | |
| */ | |
| this.drawParams = null; | |
| /** | |
| * If this render object is used inside a render bundle, | |
| * this property points to the respective bundle group. | |
| * | |
| * @type {?BundleGroup} | |
| * @default null | |
| */ | |
| this.bundle = null; | |
| /** | |
| * The clipping context. | |
| * | |
| * @type {ClippingContext} | |
| */ | |
| this.clippingContext = clippingContext; | |
| /** | |
| * The clipping context's cache key. | |
| * | |
| * @type {string} | |
| */ | |
| this.clippingContextCacheKey = clippingContext !== null ? clippingContext.cacheKey : ''; | |
| /** | |
| * The initial node cache key. | |
| * | |
| * @type {number} | |
| */ | |
| this.initialNodesCacheKey = this.getDynamicCacheKey(); | |
| /** | |
| * The initial cache key. | |
| * | |
| * @type {number} | |
| */ | |
| this.initialCacheKey = this.getCacheKey(); | |
| /** | |
| * The node builder state. | |
| * | |
| * @type {?NodeBuilderState} | |
| * @private | |
| * @default null | |
| */ | |
| this._nodeBuilderState = null; | |
| /** | |
| * An array of bindings. | |
| * | |
| * @type {?Array<BindGroup>} | |
| * @private | |
| * @default null | |
| */ | |
| this._bindings = null; | |
| /** | |
| * Reference to the node material observer. | |
| * | |
| * @type {?NodeMaterialObserver} | |
| * @private | |
| * @default null | |
| */ | |
| this._monitor = null; | |
| /** | |
| * An event listener which is defined by `RenderObjects`. It performs | |
| * clean up tasks when `dispose()` on this render object. | |
| * | |
| * @method | |
| */ | |
| this.onDispose = null; | |
| /** | |
| * This flag can be used for type testing. | |
| * | |
| * @type {boolean} | |
| * @readonly | |
| * @default true | |
| */ | |
| this.isRenderObject = true; | |
| /** | |
| * An event listener which is executed when `dispose()` is called on | |
| * the render object's material. | |
| * | |
| * @method | |
| */ | |
| this.onMaterialDispose = () => { | |
| this.dispose(); | |
| }; | |
| this.material.addEventListener( 'dispose', this.onMaterialDispose ); | |
| } | |
| /** | |
| * Updates the clipping context. | |
| * | |
| * @param {ClippingContext} context - The clipping context to set. | |
| */ | |
| updateClipping( context ) { | |
| this.clippingContext = context; | |
| } | |
| /** | |
| * Whether the clipping requires an update or not. | |
| * | |
| * @type {boolean} | |
| * @readonly | |
| */ | |
| get clippingNeedsUpdate() { | |
| if ( this.clippingContext === null || this.clippingContext.cacheKey === this.clippingContextCacheKey ) return false; | |
| this.clippingContextCacheKey = this.clippingContext.cacheKey; | |
| return true; | |
| } | |
| /** | |
| * The number of clipping planes defined in context of hardware clipping. | |
| * | |
| * @type {number} | |
| * @readonly | |
| */ | |
| get hardwareClippingPlanes() { | |
| return this.material.hardwareClipping === true ? this.clippingContext.unionClippingCount : 0; | |
| } | |
| /** | |
| * Returns the node builder state of this render object. | |
| * | |
| * @return {NodeBuilderState} The node builder state. | |
| */ | |
| getNodeBuilderState() { | |
| return this._nodeBuilderState || ( this._nodeBuilderState = this._nodes.getForRender( this ) ); | |
| } | |
| /** | |
| * Returns the node material observer of this render object. | |
| * | |
| * @return {NodeMaterialObserver} The node material observer. | |
| */ | |
| getMonitor() { | |
| return this._monitor || ( this._monitor = this.getNodeBuilderState().observer ); | |
| } | |
| /** | |
| * Returns an array of bind groups of this render object. | |
| * | |
| * @return {Array<BindGroup>} The bindings. | |
| */ | |
| getBindings() { | |
| return this._bindings || ( this._bindings = this.getNodeBuilderState().createBindings() ); | |
| } | |
| /** | |
| * Returns a binding group by group name of this render object. | |
| * | |
| * @param {string} name - The name of the binding group. | |
| * @return {?BindGroup} The bindings. | |
| */ | |
| getBindingGroup( name ) { | |
| for ( const bindingGroup of this.getBindings() ) { | |
| if ( bindingGroup.name === name ) { | |
| return bindingGroup; | |
| } | |
| } | |
| } | |
| /** | |
| * Returns the index of the render object's geometry. | |
| * | |
| * @return {?BufferAttribute} The index. Returns `null` for non-indexed geometries. | |
| */ | |
| getIndex() { | |
| return this._geometries.getIndex( this ); | |
| } | |
| /** | |
| * Returns the indirect buffer attribute. | |
| * | |
| * @return {?BufferAttribute} The indirect attribute. `null` if no indirect drawing is used. | |
| */ | |
| getIndirect() { | |
| return this._geometries.getIndirect( this ); | |
| } | |
| /** | |
| * Returns an array that acts as a key for identifying the render object in a chain map. | |
| * | |
| * @return {Array<Object>} An array with object references. | |
| */ | |
| getChainArray() { | |
| return [ this.object, this.material, this.context, this.lightsNode ]; | |
| } | |
| /** | |
| * This method is used when the geometry of a 3D object has been exchanged and the | |
| * respective render object now requires an update. | |
| * | |
| * @param {BufferGeometry} geometry - The geometry to set. | |
| */ | |
| setGeometry( geometry ) { | |
| this.geometry = geometry; | |
| this.attributes = null; | |
| } | |
| /** | |
| * Returns the buffer attributes of the render object. The returned array holds | |
| * attribute definitions on geometry and node level. | |
| * | |
| * @return {Array<BufferAttribute>} An array with buffer attributes. | |
| */ | |
| getAttributes() { | |
| if ( this.attributes !== null ) return this.attributes; | |
| const nodeAttributes = this.getNodeBuilderState().nodeAttributes; | |
| const geometry = this.geometry; | |
| const attributes = []; | |
| const vertexBuffers = new Set(); | |
| for ( const nodeAttribute of nodeAttributes ) { | |
| const attribute = nodeAttribute.node && nodeAttribute.node.attribute ? nodeAttribute.node.attribute : geometry.getAttribute( nodeAttribute.name ); | |
| if ( attribute === undefined ) continue; | |
| attributes.push( attribute ); | |
| const bufferAttribute = attribute.isInterleavedBufferAttribute ? attribute.data : attribute; | |
| vertexBuffers.add( bufferAttribute ); | |
| } | |
| this.attributes = attributes; | |
| this.vertexBuffers = Array.from( vertexBuffers.values() ); | |
| return attributes; | |
| } | |
| /** | |
| * Returns the vertex buffers of the render object. | |
| * | |
| * @return {Array<BufferAttribute|InterleavedBuffer>} An array with buffer attribute or interleaved buffers. | |
| */ | |
| getVertexBuffers() { | |
| if ( this.vertexBuffers === null ) this.getAttributes(); | |
| return this.vertexBuffers; | |
| } | |
| /** | |
| * Returns the draw parameters for the render object. | |
| * | |
| * @return {?{vertexCount: number, firstVertex: number, instanceCount: number, firstInstance: number}} The draw parameters. | |
| */ | |
| getDrawParameters() { | |
| const { object, material, geometry, group, drawRange } = this; | |
| const drawParams = this.drawParams || ( this.drawParams = { | |
| vertexCount: 0, | |
| firstVertex: 0, | |
| instanceCount: 0, | |
| firstInstance: 0 | |
| } ); | |
| const index = this.getIndex(); | |
| const hasIndex = ( index !== null ); | |
| let instanceCount = 1; | |
| if ( geometry.isInstancedBufferGeometry === true ) { | |
| instanceCount = geometry.instanceCount; | |
| } else if ( object.count !== undefined ) { | |
| instanceCount = Math.max( 0, object.count ); | |
| } | |
| if ( instanceCount === 0 ) return null; | |
| drawParams.instanceCount = instanceCount; | |
| if ( object.isBatchedMesh === true ) return drawParams; | |
| let rangeFactor = 1; | |
| if ( material.wireframe === true && ! object.isPoints && ! object.isLineSegments && ! object.isLine && ! object.isLineLoop ) { | |
| rangeFactor = 2; | |
| } | |
| let firstVertex = drawRange.start * rangeFactor; | |
| let lastVertex = ( drawRange.start + drawRange.count ) * rangeFactor; | |
| if ( group !== null ) { | |
| firstVertex = Math.max( firstVertex, group.start * rangeFactor ); | |
| lastVertex = Math.min( lastVertex, ( group.start + group.count ) * rangeFactor ); | |
| } | |
| const position = geometry.attributes.position; | |
| let itemCount = Infinity; | |
| if ( hasIndex ) { | |
| itemCount = index.count; | |
| } else if ( position !== undefined && position !== null ) { | |
| itemCount = position.count; | |
| } | |
| firstVertex = Math.max( firstVertex, 0 ); | |
| lastVertex = Math.min( lastVertex, itemCount ); | |
| const count = lastVertex - firstVertex; | |
| if ( count < 0 || count === Infinity ) return null; | |
| drawParams.vertexCount = count; | |
| drawParams.firstVertex = firstVertex; | |
| return drawParams; | |
| } | |
| /** | |
| * Returns the render object's geometry cache key. | |
| * | |
| * The geometry cache key is part of the material cache key. | |
| * | |
| * @return {string} The geometry cache key. | |
| */ | |
| getGeometryCacheKey() { | |
| const { geometry } = this; | |
| let cacheKey = ''; | |
| for ( const name of Object.keys( geometry.attributes ).sort() ) { | |
| const attribute = geometry.attributes[ name ]; | |
| cacheKey += name + ','; | |
| if ( attribute.data ) cacheKey += attribute.data.stride + ','; | |
| if ( attribute.offset ) cacheKey += attribute.offset + ','; | |
| if ( attribute.itemSize ) cacheKey += attribute.itemSize + ','; | |
| if ( attribute.normalized ) cacheKey += 'n,'; | |
| } | |
| // structural equality isn't sufficient for morph targets since the | |
| // data are maintained in textures. only if the targets are all equal | |
| // the texture and thus the instance of `MorphNode` can be shared. | |
| for ( const name of Object.keys( geometry.morphAttributes ).sort() ) { | |
| const targets = geometry.morphAttributes[ name ]; | |
| cacheKey += 'morph-' + name + ','; | |
| for ( let i = 0, l = targets.length; i < l; i ++ ) { | |
| const attribute = targets[ i ]; | |
| cacheKey += attribute.id + ','; | |
| } | |
| } | |
| if ( geometry.index ) { | |
| cacheKey += 'index,'; | |
| } | |
| return cacheKey; | |
| } | |
| /** | |
| * Returns the render object's material cache key. | |
| * | |
| * The material cache key is part of the render object cache key. | |
| * | |
| * @return {number} The material cache key. | |
| */ | |
| getMaterialCacheKey() { | |
| const { object, material } = this; | |
| let cacheKey = material.customProgramCacheKey(); | |
| for ( const property of getKeys( material ) ) { | |
| if ( /^(is[A-Z]|_)|^(visible|version|uuid|name|opacity|userData)$/.test( property ) ) continue; | |
| const value = material[ property ]; | |
| let valueKey; | |
| if ( value !== null ) { | |
| // some material values require a formatting | |
| const type = typeof value; | |
| if ( type === 'number' ) { | |
| valueKey = value !== 0 ? '1' : '0'; // Convert to on/off, important for clearcoat, transmission, etc | |
| } else if ( type === 'object' ) { | |
| valueKey = '{'; | |
| if ( value.isTexture ) { | |
| valueKey += value.mapping; | |
| } | |
| valueKey += '}'; | |
| } else { | |
| valueKey = String( value ); | |
| } | |
| } else { | |
| valueKey = String( value ); | |
| } | |
| cacheKey += /*property + ':' +*/ valueKey + ','; | |
| } | |
| cacheKey += this.clippingContextCacheKey + ','; | |
| if ( object.geometry ) { | |
| cacheKey += this.getGeometryCacheKey(); | |
| } | |
| if ( object.skeleton ) { | |
| cacheKey += object.skeleton.bones.length + ','; | |
| } | |
| if ( object.isBatchedMesh ) { | |
| cacheKey += object._matricesTexture.uuid + ','; | |
| if ( object._colorsTexture !== null ) { | |
| cacheKey += object._colorsTexture.uuid + ','; | |
| } | |
| } | |
| if ( object.count > 1 ) { | |
| // TODO: https://github.com/mrdoob/three.js/pull/29066#issuecomment-2269400850 | |
| cacheKey += object.uuid + ','; | |
| } | |
| cacheKey += object.receiveShadow + ','; | |
| return hashString( cacheKey ); | |
| } | |
| /** | |
| * Whether the geometry requires an update or not. | |
| * | |
| * @type {boolean} | |
| * @readonly | |
| */ | |
| get needsGeometryUpdate() { | |
| return this.geometry.id !== this.object.geometry.id; | |
| } | |
| /** | |
| * Whether the render object requires an update or not. | |
| * | |
| * Note: There are two distinct places where render objects are checked for an update. | |
| * | |
| * 1. In `RenderObjects.get()` which is executed when the render object is request. This | |
| * method checks the `needsUpdate` flag and recreates the render object if necessary. | |
| * 2. In `Renderer._renderObjectDirect()` right after getting the render object via | |
| * `RenderObjects.get()`. The render object's NodeMaterialObserver is then used to detect | |
| * a need for a refresh due to material, geometry or object related value changes. | |
| * | |
| * TODO: Investigate if it's possible to merge both steps so there is only a single place | |
| * that performs the 'needsUpdate' check. | |
| * | |
| * @type {boolean} | |
| * @readonly | |
| */ | |
| get needsUpdate() { | |
| return /*this.object.static !== true &&*/ ( this.initialNodesCacheKey !== this.getDynamicCacheKey() || this.clippingNeedsUpdate ); | |
| } | |
| /** | |
| * Returns the dynamic cache key which represents a key that is computed per draw command. | |
| * | |
| * @return {number} The cache key. | |
| */ | |
| getDynamicCacheKey() { | |
| let cacheKey = 0; | |
| // `Nodes.getCacheKey()` returns an environment cache key which is not relevant when | |
| // the renderer is inside a shadow pass. | |
| if ( this.material.isShadowPassMaterial !== true ) { | |
| cacheKey = this._nodes.getCacheKey( this.scene, this.lightsNode ); | |
| } | |
| if ( this.camera.isArrayCamera ) { | |
| cacheKey = hash( cacheKey, this.camera.cameras.length ); | |
| } | |
| if ( this.object.receiveShadow ) { | |
| cacheKey = hash( cacheKey, 1 ); | |
| } | |
| return cacheKey; | |
| } | |
| /** | |
| * Returns the render object's cache key. | |
| * | |
| * @return {number} The cache key. | |
| */ | |
| getCacheKey() { | |
| return this.getMaterialCacheKey() + this.getDynamicCacheKey(); | |
| } | |
| /** | |
| * Frees internal resources. | |
| */ | |
| dispose() { | |
| this.material.removeEventListener( 'dispose', this.onMaterialDispose ); | |
| this.onDispose(); | |
| } | |
| } | |
| export default RenderObject; | |
Xet Storage Details
- Size:
- 17.6 kB
- Xet hash:
- 416b699496fdc7988df82c9b8e4868e7816c5e2fff82d0bc00679e8a0a8c1757
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.