NodeMaterialObserver.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. const refreshUniforms = [
  2. 'alphaMap',
  3. 'alphaTest',
  4. 'anisotropy',
  5. 'anisotropyMap',
  6. 'anisotropyRotation',
  7. 'aoMap',
  8. 'attenuationColor',
  9. 'attenuationDistance',
  10. 'bumpMap',
  11. 'clearcoat',
  12. 'clearcoatMap',
  13. 'clearcoatNormalMap',
  14. 'clearcoatNormalScale',
  15. 'clearcoatRoughness',
  16. 'color',
  17. 'dispersion',
  18. 'displacementMap',
  19. 'emissive',
  20. 'emissiveMap',
  21. 'envMap',
  22. 'gradientMap',
  23. 'ior',
  24. 'iridescence',
  25. 'iridescenceIOR',
  26. 'iridescenceMap',
  27. 'iridescenceThicknessMap',
  28. 'lightMap',
  29. 'map',
  30. 'matcap',
  31. 'metalness',
  32. 'metalnessMap',
  33. 'normalMap',
  34. 'normalScale',
  35. 'opacity',
  36. 'roughness',
  37. 'roughnessMap',
  38. 'sheen',
  39. 'sheenColor',
  40. 'sheenColorMap',
  41. 'sheenRoughnessMap',
  42. 'shininess',
  43. 'specular',
  44. 'specularColor',
  45. 'specularColorMap',
  46. 'specularIntensity',
  47. 'specularIntensityMap',
  48. 'specularMap',
  49. 'thickness',
  50. 'transmission',
  51. 'transmissionMap'
  52. ];
  53. class NodeMaterialObserver {
  54. constructor( builder ) {
  55. this.renderObjects = new WeakMap();
  56. this.hasNode = this.containsNode( builder );
  57. this.hasAnimation = builder.object.isSkinnedMesh === true;
  58. this.refreshUniforms = refreshUniforms;
  59. this.renderId = 0;
  60. }
  61. firstInitialization( renderObject ) {
  62. const hasInitialized = this.renderObjects.has( renderObject );
  63. if ( hasInitialized === false ) {
  64. this.getRenderObjectData( renderObject );
  65. return true;
  66. }
  67. return false;
  68. }
  69. getRenderObjectData( renderObject ) {
  70. let data = this.renderObjects.get( renderObject );
  71. if ( data === undefined ) {
  72. const { geometry, material } = renderObject;
  73. data = {
  74. material: this.getMaterialData( material ),
  75. geometry: {
  76. attributes: this.getAttributesData( geometry.attributes ),
  77. indexVersion: geometry.index ? geometry.index.version : null,
  78. drawRange: { start: geometry.drawRange.start, count: geometry.drawRange.count }
  79. },
  80. worldMatrix: renderObject.object.matrixWorld.clone()
  81. };
  82. if ( renderObject.object.center ) {
  83. data.center = renderObject.object.center.clone();
  84. }
  85. if ( renderObject.object.morphTargetInfluences ) {
  86. data.morphTargetInfluences = renderObject.object.morphTargetInfluences.slice();
  87. }
  88. if ( renderObject.bundle !== null ) {
  89. data.version = renderObject.bundle.version;
  90. }
  91. if ( data.material.transmission > 0 ) {
  92. const { width, height } = renderObject.context;
  93. data.bufferWidth = width;
  94. data.bufferHeight = height;
  95. }
  96. this.renderObjects.set( renderObject, data );
  97. }
  98. return data;
  99. }
  100. getAttributesData( attributes ) {
  101. const attributesData = {};
  102. for ( const name in attributes ) {
  103. const attribute = attributes[ name ];
  104. attributesData[ name ] = {
  105. version: attribute.version
  106. };
  107. }
  108. return attributesData;
  109. }
  110. containsNode( builder ) {
  111. const material = builder.material;
  112. for ( const property in material ) {
  113. if ( material[ property ] && material[ property ].isNode )
  114. return true;
  115. }
  116. if ( builder.renderer.nodes.modelViewMatrix !== null || builder.renderer.nodes.modelNormalViewMatrix !== null )
  117. return true;
  118. return false;
  119. }
  120. getMaterialData( material ) {
  121. const data = {};
  122. for ( const property of this.refreshUniforms ) {
  123. const value = material[ property ];
  124. if ( value === null || value === undefined ) continue;
  125. if ( typeof value === 'object' && value.clone !== undefined ) {
  126. if ( value.isTexture === true ) {
  127. data[ property ] = { id: value.id, version: value.version };
  128. } else {
  129. data[ property ] = value.clone();
  130. }
  131. } else {
  132. data[ property ] = value;
  133. }
  134. }
  135. return data;
  136. }
  137. equals( renderObject ) {
  138. const { object, material, geometry } = renderObject;
  139. const renderObjectData = this.getRenderObjectData( renderObject );
  140. // world matrix
  141. if ( renderObjectData.worldMatrix.equals( object.matrixWorld ) !== true ) {
  142. renderObjectData.worldMatrix.copy( object.matrixWorld );
  143. return false;
  144. }
  145. // material
  146. const materialData = renderObjectData.material;
  147. for ( const property in materialData ) {
  148. const value = materialData[ property ];
  149. const mtlValue = material[ property ];
  150. if ( value.equals !== undefined ) {
  151. if ( value.equals( mtlValue ) === false ) {
  152. value.copy( mtlValue );
  153. return false;
  154. }
  155. } else if ( mtlValue.isTexture === true ) {
  156. if ( value.id !== mtlValue.id || value.version !== mtlValue.version ) {
  157. value.id = mtlValue.id;
  158. value.version = mtlValue.version;
  159. return false;
  160. }
  161. } else if ( value !== mtlValue ) {
  162. materialData[ property ] = mtlValue;
  163. return false;
  164. }
  165. }
  166. if ( materialData.transmission > 0 ) {
  167. const { width, height } = renderObject.context;
  168. if ( renderObjectData.bufferWidth !== width || renderObjectData.bufferHeight !== height ) {
  169. renderObjectData.bufferWidth = width;
  170. renderObjectData.bufferHeight = height;
  171. return false;
  172. }
  173. }
  174. // geometry
  175. const storedGeometryData = renderObjectData.geometry;
  176. const attributes = geometry.attributes;
  177. const storedAttributes = storedGeometryData.attributes;
  178. const storedAttributeNames = Object.keys( storedAttributes );
  179. const currentAttributeNames = Object.keys( attributes );
  180. if ( storedAttributeNames.length !== currentAttributeNames.length ) {
  181. renderObjectData.geometry.attributes = this.getAttributesData( attributes );
  182. return false;
  183. }
  184. // Compare each attribute
  185. for ( const name of storedAttributeNames ) {
  186. const storedAttributeData = storedAttributes[ name ];
  187. const attribute = attributes[ name ];
  188. if ( attribute === undefined ) {
  189. // Attribute was removed
  190. delete storedAttributes[ name ];
  191. return false;
  192. }
  193. if ( storedAttributeData.version !== attribute.version ) {
  194. storedAttributeData.version = attribute.version;
  195. return false;
  196. }
  197. }
  198. // Check index
  199. const index = geometry.index;
  200. const storedIndexVersion = storedGeometryData.indexVersion;
  201. const currentIndexVersion = index ? index.version : null;
  202. if ( storedIndexVersion !== currentIndexVersion ) {
  203. storedGeometryData.indexVersion = currentIndexVersion;
  204. return false;
  205. }
  206. // Check drawRange
  207. if ( storedGeometryData.drawRange.start !== geometry.drawRange.start || storedGeometryData.drawRange.count !== geometry.drawRange.count ) {
  208. storedGeometryData.drawRange.start = geometry.drawRange.start;
  209. storedGeometryData.drawRange.count = geometry.drawRange.count;
  210. return false;
  211. }
  212. // morph targets
  213. if ( renderObjectData.morphTargetInfluences ) {
  214. let morphChanged = false;
  215. for ( let i = 0; i < renderObjectData.morphTargetInfluences.length; i ++ ) {
  216. if ( renderObjectData.morphTargetInfluences[ i ] !== object.morphTargetInfluences[ i ] ) {
  217. morphChanged = true;
  218. }
  219. }
  220. if ( morphChanged ) return true;
  221. }
  222. // center
  223. if ( renderObjectData.center ) {
  224. if ( renderObjectData.center.equals( object.center ) === false ) {
  225. renderObjectData.center.copy( object.center );
  226. return true;
  227. }
  228. }
  229. // bundle
  230. if ( renderObject.bundle !== null ) {
  231. renderObjectData.version = renderObject.bundle.version;
  232. }
  233. return true;
  234. }
  235. needsRefresh( renderObject, nodeFrame ) {
  236. if ( this.hasNode || this.hasAnimation || this.firstInitialization( renderObject ) )
  237. return true;
  238. const { renderId } = nodeFrame;
  239. if ( this.renderId !== renderId ) {
  240. this.renderId = renderId;
  241. return true;
  242. }
  243. const isStatic = renderObject.object.static === true;
  244. const isBundle = renderObject.bundle !== null && renderObject.bundle.static === true && this.getRenderObjectData( renderObject ).version === renderObject.bundle.version;
  245. if ( isStatic || isBundle )
  246. return false;
  247. const notEqual = this.equals( renderObject ) !== true;
  248. return notEqual;
  249. }
  250. }
  251. export default NodeMaterialObserver;
粤ICP备19079148号