Buckets:
| const refreshUniforms = [ | |
| 'alphaMap', | |
| 'alphaTest', | |
| 'anisotropy', | |
| 'anisotropyMap', | |
| 'anisotropyRotation', | |
| 'aoMap', | |
| 'attenuationColor', | |
| 'attenuationDistance', | |
| 'bumpMap', | |
| 'clearcoat', | |
| 'clearcoatMap', | |
| 'clearcoatNormalMap', | |
| 'clearcoatNormalScale', | |
| 'clearcoatRoughness', | |
| 'color', | |
| 'dispersion', | |
| 'displacementMap', | |
| 'emissive', | |
| 'emissiveMap', | |
| 'envMap', | |
| 'gradientMap', | |
| 'ior', | |
| 'iridescence', | |
| 'iridescenceIOR', | |
| 'iridescenceMap', | |
| 'iridescenceThicknessMap', | |
| 'lightMap', | |
| 'map', | |
| 'matcap', | |
| 'metalness', | |
| 'metalnessMap', | |
| 'normalMap', | |
| 'normalScale', | |
| 'opacity', | |
| 'roughness', | |
| 'roughnessMap', | |
| 'sheen', | |
| 'sheenColor', | |
| 'sheenColorMap', | |
| 'sheenRoughnessMap', | |
| 'shininess', | |
| 'specular', | |
| 'specularColor', | |
| 'specularColorMap', | |
| 'specularIntensity', | |
| 'specularIntensityMap', | |
| 'specularMap', | |
| 'thickness', | |
| 'transmission', | |
| 'transmissionMap' | |
| ]; | |
| /** | |
| * This class is used by {@link WebGPURenderer} as management component. | |
| * It's primary purpose is to determine whether render objects require a | |
| * refresh right before they are going to be rendered or not. | |
| */ | |
| class NodeMaterialObserver { | |
| /** | |
| * Constructs a new node material observer. | |
| * | |
| * @param {NodeBuilder} builder - The node builder. | |
| */ | |
| constructor( builder ) { | |
| /** | |
| * A node material can be used by more than one render object so the | |
| * monitor must maintain a list of render objects. | |
| * | |
| * @type {WeakMap<RenderObject,Object>} | |
| */ | |
| this.renderObjects = new WeakMap(); | |
| /** | |
| * Whether the material uses node objects or not. | |
| * | |
| * @type {boolean} | |
| */ | |
| this.hasNode = this.containsNode( builder ); | |
| /** | |
| * Whether the node builder's 3D object is animated or not. | |
| * | |
| * @type {boolean} | |
| */ | |
| this.hasAnimation = builder.object.isSkinnedMesh === true; | |
| /** | |
| * A list of all possible material uniforms | |
| * | |
| * @type {Array<string>} | |
| */ | |
| this.refreshUniforms = refreshUniforms; | |
| /** | |
| * Holds the current render ID from the node frame. | |
| * | |
| * @type {number} | |
| * @default 0 | |
| */ | |
| this.renderId = 0; | |
| } | |
| /** | |
| * Returns `true` if the given render object is verified for the first time of this observer. | |
| * | |
| * @param {RenderObject} renderObject - The render object. | |
| * @return {boolean} Whether the given render object is verified for the first time of this observer. | |
| */ | |
| firstInitialization( renderObject ) { | |
| const hasInitialized = this.renderObjects.has( renderObject ); | |
| if ( hasInitialized === false ) { | |
| this.getRenderObjectData( renderObject ); | |
| return true; | |
| } | |
| return false; | |
| } | |
| /** | |
| * Returns `true` if the current rendering produces motion vectors. | |
| * | |
| * @param {Renderer} renderer - The renderer. | |
| * @return {boolean} Whether the current rendering produces motion vectors or not. | |
| */ | |
| needsVelocity( renderer ) { | |
| const mrt = renderer.getMRT(); | |
| return ( mrt !== null && mrt.has( 'velocity' ) ); | |
| } | |
| /** | |
| * Returns monitoring data for the given render object. | |
| * | |
| * @param {RenderObject} renderObject - The render object. | |
| * @return {Object} The monitoring data. | |
| */ | |
| getRenderObjectData( renderObject ) { | |
| let data = this.renderObjects.get( renderObject ); | |
| if ( data === undefined ) { | |
| const { geometry, material, object } = renderObject; | |
| data = { | |
| material: this.getMaterialData( material ), | |
| geometry: { | |
| id: geometry.id, | |
| attributes: this.getAttributesData( geometry.attributes ), | |
| indexVersion: geometry.index ? geometry.index.version : null, | |
| drawRange: { start: geometry.drawRange.start, count: geometry.drawRange.count } | |
| }, | |
| worldMatrix: object.matrixWorld.clone() | |
| }; | |
| if ( object.center ) { | |
| data.center = object.center.clone(); | |
| } | |
| if ( object.morphTargetInfluences ) { | |
| data.morphTargetInfluences = object.morphTargetInfluences.slice(); | |
| } | |
| if ( renderObject.bundle !== null ) { | |
| data.version = renderObject.bundle.version; | |
| } | |
| if ( data.material.transmission > 0 ) { | |
| const { width, height } = renderObject.context; | |
| data.bufferWidth = width; | |
| data.bufferHeight = height; | |
| } | |
| this.renderObjects.set( renderObject, data ); | |
| } | |
| return data; | |
| } | |
| /** | |
| * Returns an attribute data structure holding the attributes versions for | |
| * monitoring. | |
| * | |
| * @param {Object} attributes - The geometry attributes. | |
| * @return {Object} An object for monitoring the versions of attributes. | |
| */ | |
| getAttributesData( attributes ) { | |
| const attributesData = {}; | |
| for ( const name in attributes ) { | |
| const attribute = attributes[ name ]; | |
| attributesData[ name ] = { | |
| version: attribute.version | |
| }; | |
| } | |
| return attributesData; | |
| } | |
| /** | |
| * Returns `true` if the node builder's material uses | |
| * node properties. | |
| * | |
| * @param {NodeBuilder} builder - The current node builder. | |
| * @return {boolean} Whether the node builder's material uses node properties or not. | |
| */ | |
| containsNode( builder ) { | |
| const material = builder.material; | |
| for ( const property in material ) { | |
| if ( material[ property ] && material[ property ].isNode ) | |
| return true; | |
| } | |
| if ( builder.renderer.overrideNodes.modelViewMatrix !== null || builder.renderer.overrideNodes.modelNormalViewMatrix !== null ) | |
| return true; | |
| return false; | |
| } | |
| /** | |
| * Returns a material data structure holding the material property values for | |
| * monitoring. | |
| * | |
| * @param {Material} material - The material. | |
| * @return {Object} An object for monitoring material properties. | |
| */ | |
| getMaterialData( material ) { | |
| const data = {}; | |
| for ( const property of this.refreshUniforms ) { | |
| const value = material[ property ]; | |
| if ( value === null || value === undefined ) continue; | |
| if ( typeof value === 'object' && value.clone !== undefined ) { | |
| if ( value.isTexture === true ) { | |
| data[ property ] = { id: value.id, version: value.version }; | |
| } else { | |
| data[ property ] = value.clone(); | |
| } | |
| } else { | |
| data[ property ] = value; | |
| } | |
| } | |
| return data; | |
| } | |
| /** | |
| * Returns `true` if the given render object has not changed its state. | |
| * | |
| * @param {RenderObject} renderObject - The render object. | |
| * @return {boolean} Whether the given render object has changed its state or not. | |
| */ | |
| equals( renderObject ) { | |
| const { object, material, geometry } = renderObject; | |
| const renderObjectData = this.getRenderObjectData( renderObject ); | |
| // world matrix | |
| if ( renderObjectData.worldMatrix.equals( object.matrixWorld ) !== true ) { | |
| renderObjectData.worldMatrix.copy( object.matrixWorld ); | |
| return false; | |
| } | |
| // material | |
| const materialData = renderObjectData.material; | |
| for ( const property in materialData ) { | |
| const value = materialData[ property ]; | |
| const mtlValue = material[ property ]; | |
| if ( value.equals !== undefined ) { | |
| if ( value.equals( mtlValue ) === false ) { | |
| value.copy( mtlValue ); | |
| return false; | |
| } | |
| } else if ( mtlValue.isTexture === true ) { | |
| if ( value.id !== mtlValue.id || value.version !== mtlValue.version ) { | |
| value.id = mtlValue.id; | |
| value.version = mtlValue.version; | |
| return false; | |
| } | |
| } else if ( value !== mtlValue ) { | |
| materialData[ property ] = mtlValue; | |
| return false; | |
| } | |
| } | |
| if ( materialData.transmission > 0 ) { | |
| const { width, height } = renderObject.context; | |
| if ( renderObjectData.bufferWidth !== width || renderObjectData.bufferHeight !== height ) { | |
| renderObjectData.bufferWidth = width; | |
| renderObjectData.bufferHeight = height; | |
| return false; | |
| } | |
| } | |
| // geometry | |
| const storedGeometryData = renderObjectData.geometry; | |
| const attributes = geometry.attributes; | |
| const storedAttributes = storedGeometryData.attributes; | |
| const storedAttributeNames = Object.keys( storedAttributes ); | |
| const currentAttributeNames = Object.keys( attributes ); | |
| if ( storedGeometryData.id !== geometry.id ) { | |
| storedGeometryData.id = geometry.id; | |
| return false; | |
| } | |
| if ( storedAttributeNames.length !== currentAttributeNames.length ) { | |
| renderObjectData.geometry.attributes = this.getAttributesData( attributes ); | |
| return false; | |
| } | |
| // compare each attribute | |
| for ( const name of storedAttributeNames ) { | |
| const storedAttributeData = storedAttributes[ name ]; | |
| const attribute = attributes[ name ]; | |
| if ( attribute === undefined ) { | |
| // attribute was removed | |
| delete storedAttributes[ name ]; | |
| return false; | |
| } | |
| if ( storedAttributeData.version !== attribute.version ) { | |
| storedAttributeData.version = attribute.version; | |
| return false; | |
| } | |
| } | |
| // check index | |
| const index = geometry.index; | |
| const storedIndexVersion = storedGeometryData.indexVersion; | |
| const currentIndexVersion = index ? index.version : null; | |
| if ( storedIndexVersion !== currentIndexVersion ) { | |
| storedGeometryData.indexVersion = currentIndexVersion; | |
| return false; | |
| } | |
| // check drawRange | |
| if ( storedGeometryData.drawRange.start !== geometry.drawRange.start || storedGeometryData.drawRange.count !== geometry.drawRange.count ) { | |
| storedGeometryData.drawRange.start = geometry.drawRange.start; | |
| storedGeometryData.drawRange.count = geometry.drawRange.count; | |
| return false; | |
| } | |
| // morph targets | |
| if ( renderObjectData.morphTargetInfluences ) { | |
| let morphChanged = false; | |
| for ( let i = 0; i < renderObjectData.morphTargetInfluences.length; i ++ ) { | |
| if ( renderObjectData.morphTargetInfluences[ i ] !== object.morphTargetInfluences[ i ] ) { | |
| morphChanged = true; | |
| } | |
| } | |
| if ( morphChanged ) return true; | |
| } | |
| // center | |
| if ( renderObjectData.center ) { | |
| if ( renderObjectData.center.equals( object.center ) === false ) { | |
| renderObjectData.center.copy( object.center ); | |
| return true; | |
| } | |
| } | |
| // bundle | |
| if ( renderObject.bundle !== null ) { | |
| renderObjectData.version = renderObject.bundle.version; | |
| } | |
| return true; | |
| } | |
| /** | |
| * Checks if the given render object requires a refresh. | |
| * | |
| * @param {RenderObject} renderObject - The render object. | |
| * @param {NodeFrame} nodeFrame - The current node frame. | |
| * @return {boolean} Whether the given render object requires a refresh or not. | |
| */ | |
| needsRefresh( renderObject, nodeFrame ) { | |
| if ( this.hasNode || this.hasAnimation || this.firstInitialization( renderObject ) || this.needsVelocity( nodeFrame.renderer ) ) | |
| return true; | |
| const { renderId } = nodeFrame; | |
| if ( this.renderId !== renderId ) { | |
| this.renderId = renderId; | |
| return true; | |
| } | |
| const isStatic = renderObject.object.static === true; | |
| const isBundle = renderObject.bundle !== null && renderObject.bundle.static === true && this.getRenderObjectData( renderObject ).version === renderObject.bundle.version; | |
| if ( isStatic || isBundle ) | |
| return false; | |
| const notEqual = this.equals( renderObject ) !== true; | |
| return notEqual; | |
| } | |
| } | |
| export default NodeMaterialObserver; | |
Xet Storage Details
- Size:
- 10.8 kB
- Xet hash:
- 5238094ec754d44faf11a1d0dbd6516e40e5a3f6ce3a38ff9f3947ca7ac7a49f
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.