Material.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017
  1. import { Color } from '../math/Color.js';
  2. import { EventDispatcher } from '../core/EventDispatcher.js';
  3. import { FrontSide, NormalBlending, LessEqualDepth, AddEquation, OneMinusSrcAlphaFactor, SrcAlphaFactor, AlwaysStencilFunc, KeepStencilOp } from '../constants.js';
  4. import { generateUUID } from '../math/MathUtils.js';
  5. import { warn } from '../utils.js';
  6. let _materialId = 0;
  7. /**
  8. * Abstract base class for materials.
  9. *
  10. * Materials define the appearance of renderable 3D objects.
  11. *
  12. * @abstract
  13. * @augments EventDispatcher
  14. */
  15. class Material extends EventDispatcher {
  16. /**
  17. * Constructs a new material.
  18. */
  19. constructor() {
  20. super();
  21. /**
  22. * This flag can be used for type testing.
  23. *
  24. * @type {boolean}
  25. * @readonly
  26. * @default true
  27. */
  28. this.isMaterial = true;
  29. /**
  30. * The ID of the material.
  31. *
  32. * @name Material#id
  33. * @type {number}
  34. * @readonly
  35. */
  36. Object.defineProperty( this, 'id', { value: _materialId ++ } );
  37. /**
  38. * The UUID of the material.
  39. *
  40. * @type {string}
  41. * @readonly
  42. */
  43. this.uuid = generateUUID();
  44. /**
  45. * The name of the material.
  46. *
  47. * @type {string}
  48. */
  49. this.name = '';
  50. /**
  51. * The type property is used for detecting the object type
  52. * in context of serialization/deserialization.
  53. *
  54. * @type {string}
  55. * @readonly
  56. */
  57. this.type = 'Material';
  58. /**
  59. * Defines the blending type of the material.
  60. *
  61. * It must be set to `CustomBlending` if custom blending properties like
  62. * {@link Material#blendSrc}, {@link Material#blendDst} or {@link Material#blendEquation}
  63. * should have any effect.
  64. *
  65. * @type {(NoBlending|NormalBlending|AdditiveBlending|SubtractiveBlending|MultiplyBlending|CustomBlending)}
  66. * @default NormalBlending
  67. */
  68. this.blending = NormalBlending;
  69. /**
  70. * Defines which side of faces will be rendered - front, back or both.
  71. *
  72. * @type {(FrontSide|BackSide|DoubleSide)}
  73. * @default FrontSide
  74. */
  75. this.side = FrontSide;
  76. /**
  77. * If set to `true`, vertex colors should be used.
  78. *
  79. * The engine supports RGB and RGBA vertex colors depending on whether a three (RGB) or
  80. * four (RGBA) component color buffer attribute is used.
  81. *
  82. * @type {boolean}
  83. * @default false
  84. */
  85. this.vertexColors = false;
  86. /**
  87. * Defines how transparent the material is.
  88. * A value of `0.0` indicates fully transparent, `1.0` is fully opaque.
  89. *
  90. * If the {@link Material#transparent} is not set to `true`,
  91. * the material will remain fully opaque and this value will only affect its color.
  92. *
  93. * @type {number}
  94. * @default 1
  95. */
  96. this.opacity = 1;
  97. /**
  98. * Defines whether this material is transparent. This has an effect on
  99. * rendering as transparent objects need special treatment and are rendered
  100. * after non-transparent objects.
  101. *
  102. * When set to true, the extent to which the material is transparent is
  103. * controlled by {@link Material#opacity}.
  104. *
  105. * @type {boolean}
  106. * @default false
  107. */
  108. this.transparent = false;
  109. /**
  110. * Enables alpha hashed transparency, an alternative to {@link Material#transparent} or
  111. * {@link Material#alphaTest}. The material will not be rendered if opacity is lower than
  112. * a random threshold. Randomization introduces some grain or noise, but approximates alpha
  113. * blending without the associated problems of sorting. Using TAA can reduce the resulting noise.
  114. *
  115. * @type {boolean}
  116. * @default false
  117. */
  118. this.alphaHash = false;
  119. /**
  120. * Defines the blending source factor.
  121. *
  122. * @type {(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)}
  123. * @default SrcAlphaFactor
  124. */
  125. this.blendSrc = SrcAlphaFactor;
  126. /**
  127. * Defines the blending destination factor.
  128. *
  129. * @type {(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)}
  130. * @default OneMinusSrcAlphaFactor
  131. */
  132. this.blendDst = OneMinusSrcAlphaFactor;
  133. /**
  134. * Defines the blending equation.
  135. *
  136. * @type {(AddEquation|SubtractEquation|ReverseSubtractEquation|MinEquation|MaxEquation)}
  137. * @default AddEquation
  138. */
  139. this.blendEquation = AddEquation;
  140. /**
  141. * Defines the blending source alpha factor.
  142. *
  143. * @type {?(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)}
  144. * @default null
  145. */
  146. this.blendSrcAlpha = null;
  147. /**
  148. * Defines the blending destination alpha factor.
  149. *
  150. * @type {?(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)}
  151. * @default null
  152. */
  153. this.blendDstAlpha = null;
  154. /**
  155. * Defines the blending equation of the alpha channel.
  156. *
  157. * @type {?(AddEquation|SubtractEquation|ReverseSubtractEquation|MinEquation|MaxEquation)}
  158. * @default null
  159. */
  160. this.blendEquationAlpha = null;
  161. /**
  162. * Represents the RGB values of the constant blend color.
  163. *
  164. * This property has only an effect when using custom blending with `ConstantColor` or `OneMinusConstantColor`.
  165. *
  166. * @type {Color}
  167. * @default (0,0,0)
  168. */
  169. this.blendColor = new Color( 0, 0, 0 );
  170. /**
  171. * Represents the alpha value of the constant blend color.
  172. *
  173. * This property has only an effect when using custom blending with `ConstantAlpha` or `OneMinusConstantAlpha`.
  174. *
  175. * @type {number}
  176. * @default 0
  177. */
  178. this.blendAlpha = 0;
  179. /**
  180. * Defines the depth function.
  181. *
  182. * @type {(NeverDepth|AlwaysDepth|LessDepth|LessEqualDepth|EqualDepth|GreaterEqualDepth|GreaterDepth|NotEqualDepth)}
  183. * @default LessEqualDepth
  184. */
  185. this.depthFunc = LessEqualDepth;
  186. /**
  187. * Whether to have depth test enabled when rendering this material.
  188. * When the depth test is disabled, the depth write will also be implicitly disabled.
  189. *
  190. * @type {boolean}
  191. * @default true
  192. */
  193. this.depthTest = true;
  194. /**
  195. * Whether rendering this material has any effect on the depth buffer.
  196. *
  197. * When drawing 2D overlays it can be useful to disable the depth writing in
  198. * order to layer several things together without creating z-index artifacts.
  199. *
  200. * @type {boolean}
  201. * @default true
  202. */
  203. this.depthWrite = true;
  204. /**
  205. * The bit mask to use when writing to the stencil buffer.
  206. *
  207. * @type {number}
  208. * @default 0xff
  209. */
  210. this.stencilWriteMask = 0xff;
  211. /**
  212. * The stencil comparison function to use.
  213. *
  214. * @type {NeverStencilFunc|LessStencilFunc|EqualStencilFunc|LessEqualStencilFunc|GreaterStencilFunc|NotEqualStencilFunc|GreaterEqualStencilFunc|AlwaysStencilFunc}
  215. * @default AlwaysStencilFunc
  216. */
  217. this.stencilFunc = AlwaysStencilFunc;
  218. /**
  219. * The value to use when performing stencil comparisons or stencil operations.
  220. *
  221. * @type {number}
  222. * @default 0
  223. */
  224. this.stencilRef = 0;
  225. /**
  226. * The bit mask to use when comparing against the stencil buffer.
  227. *
  228. * @type {number}
  229. * @default 0xff
  230. */
  231. this.stencilFuncMask = 0xff;
  232. /**
  233. * Which stencil operation to perform when the comparison function returns `false`.
  234. *
  235. * @type {ZeroStencilOp|KeepStencilOp|ReplaceStencilOp|IncrementStencilOp|DecrementStencilOp|IncrementWrapStencilOp|DecrementWrapStencilOp|InvertStencilOp}
  236. * @default KeepStencilOp
  237. */
  238. this.stencilFail = KeepStencilOp;
  239. /**
  240. * Which stencil operation to perform when the comparison function returns
  241. * `true` but the depth test fails.
  242. *
  243. * @type {ZeroStencilOp|KeepStencilOp|ReplaceStencilOp|IncrementStencilOp|DecrementStencilOp|IncrementWrapStencilOp|DecrementWrapStencilOp|InvertStencilOp}
  244. * @default KeepStencilOp
  245. */
  246. this.stencilZFail = KeepStencilOp;
  247. /**
  248. * Which stencil operation to perform when the comparison function returns
  249. * `true` and the depth test passes.
  250. *
  251. * @type {ZeroStencilOp|KeepStencilOp|ReplaceStencilOp|IncrementStencilOp|DecrementStencilOp|IncrementWrapStencilOp|DecrementWrapStencilOp|InvertStencilOp}
  252. * @default KeepStencilOp
  253. */
  254. this.stencilZPass = KeepStencilOp;
  255. /**
  256. * Whether stencil operations are performed against the stencil buffer. In
  257. * order to perform writes or comparisons against the stencil buffer this
  258. * value must be `true`.
  259. *
  260. * @type {boolean}
  261. * @default false
  262. */
  263. this.stencilWrite = false;
  264. /**
  265. * User-defined clipping planes specified as THREE.Plane objects in world
  266. * space. These planes apply to the objects this material is attached to.
  267. * Points in space whose signed distance to the plane is negative are clipped
  268. * (not rendered). This requires {@link WebGLRenderer#localClippingEnabled} to
  269. * be `true`.
  270. *
  271. * @type {?Array<Plane>}
  272. * @default null
  273. */
  274. this.clippingPlanes = null;
  275. /**
  276. * Changes the behavior of clipping planes so that only their intersection is
  277. * clipped, rather than their union.
  278. *
  279. * @type {boolean}
  280. * @default false
  281. */
  282. this.clipIntersection = false;
  283. /**
  284. * Defines whether to clip shadows according to the clipping planes specified
  285. * on this material.
  286. *
  287. * @type {boolean}
  288. * @default false
  289. */
  290. this.clipShadows = false;
  291. /**
  292. * Defines which side of faces cast shadows. If `null`, the side casting shadows
  293. * is determined as follows:
  294. *
  295. * - When {@link Material#side} is set to `FrontSide`, the back side cast shadows.
  296. * - When {@link Material#side} is set to `BackSide`, the front side cast shadows.
  297. * - When {@link Material#side} is set to `DoubleSide`, both sides cast shadows.
  298. *
  299. * @type {?(FrontSide|BackSide|DoubleSide)}
  300. * @default null
  301. */
  302. this.shadowSide = null;
  303. /**
  304. * Whether to render the material's color.
  305. *
  306. * This can be used in conjunction with {@link Object3D#renderOder} to create invisible
  307. * objects that occlude other objects.
  308. *
  309. * @type {boolean}
  310. * @default true
  311. */
  312. this.colorWrite = true;
  313. /**
  314. * Override the renderer's default precision for this material.
  315. *
  316. * @type {?('highp'|'mediump'|'lowp')}
  317. * @default null
  318. */
  319. this.precision = null;
  320. /**
  321. * Whether to use polygon offset or not. When enabled, each fragment's depth value will
  322. * be offset after it is interpolated from the depth values of the appropriate vertices.
  323. * The offset is added before the depth test is performed and before the value is written
  324. * into the depth buffer.
  325. *
  326. * Can be useful for rendering hidden-line images, for applying decals to surfaces, and for
  327. * rendering solids with highlighted edges.
  328. *
  329. * @type {boolean}
  330. * @default false
  331. */
  332. this.polygonOffset = false;
  333. /**
  334. * Specifies a scale factor that is used to create a variable depth offset for each polygon.
  335. *
  336. * @type {number}
  337. * @default 0
  338. */
  339. this.polygonOffsetFactor = 0;
  340. /**
  341. * Is multiplied by an implementation-specific value to create a constant depth offset.
  342. *
  343. * @type {number}
  344. * @default 0
  345. */
  346. this.polygonOffsetUnits = 0;
  347. /**
  348. * Whether to apply dithering to the color to remove the appearance of banding.
  349. *
  350. * @type {boolean}
  351. * @default false
  352. */
  353. this.dithering = false;
  354. /**
  355. * Whether alpha to coverage should be enabled or not. Can only be used with MSAA-enabled contexts
  356. * (meaning when the renderer was created with *antialias* parameter set to `true`). Enabling this
  357. * will smooth aliasing on clip plane edges and alphaTest-clipped edges.
  358. *
  359. * @type {boolean}
  360. * @default false
  361. */
  362. this.alphaToCoverage = false;
  363. /**
  364. * Whether to premultiply the alpha (transparency) value.
  365. *
  366. * @type {boolean}
  367. * @default false
  368. */
  369. this.premultipliedAlpha = false;
  370. /**
  371. * Whether double-sided, transparent objects should be rendered with a single pass or not.
  372. *
  373. * The engine renders double-sided, transparent objects with two draw calls (back faces first,
  374. * then front faces) to mitigate transparency artifacts. There are scenarios however where this
  375. * approach produces no quality gains but still doubles draw calls e.g. when rendering flat
  376. * vegetation like grass sprites. In these cases, set the `forceSinglePass` flag to `true` to
  377. * disable the two pass rendering to avoid performance issues.
  378. *
  379. * @type {boolean}
  380. * @default false
  381. */
  382. this.forceSinglePass = false;
  383. /**
  384. * Whether it's possible to override the material with {@link Scene#overrideMaterial} or not.
  385. *
  386. * @type {boolean}
  387. * @default true
  388. */
  389. this.allowOverride = true;
  390. /**
  391. * Defines whether 3D objects using this material are visible.
  392. *
  393. * @type {boolean}
  394. * @default true
  395. */
  396. this.visible = true;
  397. /**
  398. * Defines whether this material is tone mapped according to the renderer's tone mapping setting.
  399. *
  400. * It is ignored when rendering to a render target or using post processing or when using
  401. * `WebGPURenderer`. In all these cases, all materials are honored by tone mapping.
  402. *
  403. * @type {boolean}
  404. * @default true
  405. */
  406. this.toneMapped = true;
  407. /**
  408. * An object that can be used to store custom data about the Material. It
  409. * should not hold references to functions as these will not be cloned.
  410. *
  411. * @type {Object}
  412. */
  413. this.userData = {};
  414. /**
  415. * This starts at `0` and counts how many times {@link Material#needsUpdate} is set to `true`.
  416. *
  417. * @type {number}
  418. * @readonly
  419. * @default 0
  420. */
  421. this.version = 0;
  422. this._alphaTest = 0;
  423. }
  424. /**
  425. * Sets the alpha value to be used when running an alpha test. The material
  426. * will not be rendered if the opacity is lower than this value.
  427. *
  428. * @type {number}
  429. * @readonly
  430. * @default 0
  431. */
  432. get alphaTest() {
  433. return this._alphaTest;
  434. }
  435. set alphaTest( value ) {
  436. if ( this._alphaTest > 0 !== value > 0 ) {
  437. this.version ++;
  438. }
  439. this._alphaTest = value;
  440. }
  441. /**
  442. * An optional callback that is executed immediately before the material is used to render a 3D object.
  443. *
  444. * This method can only be used when rendering with {@link WebGLRenderer}.
  445. *
  446. * @param {WebGLRenderer} renderer - The renderer.
  447. * @param {Scene} scene - The scene.
  448. * @param {Camera} camera - The camera that is used to render the scene.
  449. * @param {BufferGeometry} geometry - The 3D object's geometry.
  450. * @param {Object3D} object - The 3D object.
  451. * @param {Object} group - The geometry group data.
  452. */
  453. onBeforeRender( /* renderer, scene, camera, geometry, object, group */ ) {}
  454. /**
  455. * An optional callback that is executed immediately before the shader
  456. * program is compiled. This function is called with the shader source code
  457. * as a parameter. Useful for the modification of built-in materials.
  458. *
  459. * This method can only be used when rendering with {@link WebGLRenderer}. The
  460. * recommended approach when customizing materials is to use `WebGPURenderer` with the new
  461. * Node Material system and [TSL](https://github.com/mrdoob/three.js/wiki/Three.js-Shading-Language).
  462. *
  463. * @param {{vertexShader:string,fragmentShader:string,uniforms:Object}} shaderobject - The object holds the uniforms and the vertex and fragment shader source.
  464. * @param {WebGLRenderer} renderer - A reference to the renderer.
  465. */
  466. onBeforeCompile( /* shaderobject, renderer */ ) {}
  467. /**
  468. * In case {@link Material#onBeforeCompile} is used, this callback can be used to identify
  469. * values of settings used in `onBeforeCompile()`, so three.js can reuse a cached
  470. * shader or recompile the shader for this material as needed.
  471. *
  472. * This method can only be used when rendering with {@link WebGLRenderer}.
  473. *
  474. * @return {string} The custom program cache key.
  475. */
  476. customProgramCacheKey() {
  477. return this.onBeforeCompile.toString();
  478. }
  479. /**
  480. * This method can be used to set default values from parameter objects.
  481. * It is a generic implementation so it can be used with different types
  482. * of materials.
  483. *
  484. * @param {Object} [values] - The material values to set.
  485. */
  486. setValues( values ) {
  487. if ( values === undefined ) return;
  488. for ( const key in values ) {
  489. const newValue = values[ key ];
  490. if ( newValue === undefined ) {
  491. warn( `Material: parameter '${ key }' has value of undefined.` );
  492. continue;
  493. }
  494. const currentValue = this[ key ];
  495. if ( currentValue === undefined ) {
  496. warn( `Material: '${ key }' is not a property of THREE.${ this.type }.` );
  497. continue;
  498. }
  499. if ( currentValue && currentValue.isColor ) {
  500. currentValue.set( newValue );
  501. } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {
  502. currentValue.copy( newValue );
  503. } else {
  504. this[ key ] = newValue;
  505. }
  506. }
  507. }
  508. /**
  509. * Serializes the material into JSON.
  510. *
  511. * @param {?(Object|string)} meta - An optional value holding meta information about the serialization.
  512. * @return {Object} A JSON object representing the serialized material.
  513. * @see {@link ObjectLoader#parse}
  514. */
  515. toJSON( meta ) {
  516. const isRootObject = ( meta === undefined || typeof meta === 'string' );
  517. if ( isRootObject ) {
  518. meta = {
  519. textures: {},
  520. images: {}
  521. };
  522. }
  523. const data = {
  524. metadata: {
  525. version: 4.7,
  526. type: 'Material',
  527. generator: 'Material.toJSON'
  528. }
  529. };
  530. // standard Material serialization
  531. data.uuid = this.uuid;
  532. data.type = this.type;
  533. if ( this.name !== '' ) data.name = this.name;
  534. if ( this.color && this.color.isColor ) data.color = this.color.getHex();
  535. if ( this.roughness !== undefined ) data.roughness = this.roughness;
  536. if ( this.metalness !== undefined ) data.metalness = this.metalness;
  537. if ( this.sheen !== undefined ) data.sheen = this.sheen;
  538. if ( this.sheenColor && this.sheenColor.isColor ) data.sheenColor = this.sheenColor.getHex();
  539. if ( this.sheenRoughness !== undefined ) data.sheenRoughness = this.sheenRoughness;
  540. if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();
  541. if ( this.emissiveIntensity !== undefined && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity;
  542. if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();
  543. if ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity;
  544. if ( this.specularColor && this.specularColor.isColor ) data.specularColor = this.specularColor.getHex();
  545. if ( this.shininess !== undefined ) data.shininess = this.shininess;
  546. if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat;
  547. if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness;
  548. if ( this.clearcoatMap && this.clearcoatMap.isTexture ) {
  549. data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid;
  550. }
  551. if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) {
  552. data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid;
  553. }
  554. if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) {
  555. data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid;
  556. data.clearcoatNormalScale = this.clearcoatNormalScale.toArray();
  557. }
  558. if ( this.sheenColorMap && this.sheenColorMap.isTexture ) {
  559. data.sheenColorMap = this.sheenColorMap.toJSON( meta ).uuid;
  560. }
  561. if ( this.sheenRoughnessMap && this.sheenRoughnessMap.isTexture ) {
  562. data.sheenRoughnessMap = this.sheenRoughnessMap.toJSON( meta ).uuid;
  563. }
  564. if ( this.dispersion !== undefined ) data.dispersion = this.dispersion;
  565. if ( this.iridescence !== undefined ) data.iridescence = this.iridescence;
  566. if ( this.iridescenceIOR !== undefined ) data.iridescenceIOR = this.iridescenceIOR;
  567. if ( this.iridescenceThicknessRange !== undefined ) data.iridescenceThicknessRange = this.iridescenceThicknessRange;
  568. if ( this.iridescenceMap && this.iridescenceMap.isTexture ) {
  569. data.iridescenceMap = this.iridescenceMap.toJSON( meta ).uuid;
  570. }
  571. if ( this.iridescenceThicknessMap && this.iridescenceThicknessMap.isTexture ) {
  572. data.iridescenceThicknessMap = this.iridescenceThicknessMap.toJSON( meta ).uuid;
  573. }
  574. if ( this.anisotropy !== undefined ) data.anisotropy = this.anisotropy;
  575. if ( this.anisotropyRotation !== undefined ) data.anisotropyRotation = this.anisotropyRotation;
  576. if ( this.anisotropyMap && this.anisotropyMap.isTexture ) {
  577. data.anisotropyMap = this.anisotropyMap.toJSON( meta ).uuid;
  578. }
  579. if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;
  580. if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid;
  581. if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;
  582. if ( this.lightMap && this.lightMap.isTexture ) {
  583. data.lightMap = this.lightMap.toJSON( meta ).uuid;
  584. data.lightMapIntensity = this.lightMapIntensity;
  585. }
  586. if ( this.aoMap && this.aoMap.isTexture ) {
  587. data.aoMap = this.aoMap.toJSON( meta ).uuid;
  588. data.aoMapIntensity = this.aoMapIntensity;
  589. }
  590. if ( this.bumpMap && this.bumpMap.isTexture ) {
  591. data.bumpMap = this.bumpMap.toJSON( meta ).uuid;
  592. data.bumpScale = this.bumpScale;
  593. }
  594. if ( this.normalMap && this.normalMap.isTexture ) {
  595. data.normalMap = this.normalMap.toJSON( meta ).uuid;
  596. data.normalMapType = this.normalMapType;
  597. data.normalScale = this.normalScale.toArray();
  598. }
  599. if ( this.displacementMap && this.displacementMap.isTexture ) {
  600. data.displacementMap = this.displacementMap.toJSON( meta ).uuid;
  601. data.displacementScale = this.displacementScale;
  602. data.displacementBias = this.displacementBias;
  603. }
  604. if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;
  605. if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;
  606. if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;
  607. if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;
  608. if ( this.specularIntensityMap && this.specularIntensityMap.isTexture ) data.specularIntensityMap = this.specularIntensityMap.toJSON( meta ).uuid;
  609. if ( this.specularColorMap && this.specularColorMap.isTexture ) data.specularColorMap = this.specularColorMap.toJSON( meta ).uuid;
  610. if ( this.envMap && this.envMap.isTexture ) {
  611. data.envMap = this.envMap.toJSON( meta ).uuid;
  612. if ( this.combine !== undefined ) data.combine = this.combine;
  613. }
  614. if ( this.envMapRotation !== undefined ) data.envMapRotation = this.envMapRotation.toArray();
  615. if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity;
  616. if ( this.reflectivity !== undefined ) data.reflectivity = this.reflectivity;
  617. if ( this.refractionRatio !== undefined ) data.refractionRatio = this.refractionRatio;
  618. if ( this.gradientMap && this.gradientMap.isTexture ) {
  619. data.gradientMap = this.gradientMap.toJSON( meta ).uuid;
  620. }
  621. if ( this.transmission !== undefined ) data.transmission = this.transmission;
  622. if ( this.transmissionMap && this.transmissionMap.isTexture ) data.transmissionMap = this.transmissionMap.toJSON( meta ).uuid;
  623. if ( this.thickness !== undefined ) data.thickness = this.thickness;
  624. if ( this.thicknessMap && this.thicknessMap.isTexture ) data.thicknessMap = this.thicknessMap.toJSON( meta ).uuid;
  625. if ( this.attenuationDistance !== undefined && this.attenuationDistance !== Infinity ) data.attenuationDistance = this.attenuationDistance;
  626. if ( this.attenuationColor !== undefined ) data.attenuationColor = this.attenuationColor.getHex();
  627. if ( this.size !== undefined ) data.size = this.size;
  628. if ( this.shadowSide !== null ) data.shadowSide = this.shadowSide;
  629. if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;
  630. if ( this.blending !== NormalBlending ) data.blending = this.blending;
  631. if ( this.side !== FrontSide ) data.side = this.side;
  632. if ( this.vertexColors === true ) data.vertexColors = true;
  633. if ( this.opacity < 1 ) data.opacity = this.opacity;
  634. if ( this.transparent === true ) data.transparent = true;
  635. if ( this.blendSrc !== SrcAlphaFactor ) data.blendSrc = this.blendSrc;
  636. if ( this.blendDst !== OneMinusSrcAlphaFactor ) data.blendDst = this.blendDst;
  637. if ( this.blendEquation !== AddEquation ) data.blendEquation = this.blendEquation;
  638. if ( this.blendSrcAlpha !== null ) data.blendSrcAlpha = this.blendSrcAlpha;
  639. if ( this.blendDstAlpha !== null ) data.blendDstAlpha = this.blendDstAlpha;
  640. if ( this.blendEquationAlpha !== null ) data.blendEquationAlpha = this.blendEquationAlpha;
  641. if ( this.blendColor && this.blendColor.isColor ) data.blendColor = this.blendColor.getHex();
  642. if ( this.blendAlpha !== 0 ) data.blendAlpha = this.blendAlpha;
  643. if ( this.depthFunc !== LessEqualDepth ) data.depthFunc = this.depthFunc;
  644. if ( this.depthTest === false ) data.depthTest = this.depthTest;
  645. if ( this.depthWrite === false ) data.depthWrite = this.depthWrite;
  646. if ( this.colorWrite === false ) data.colorWrite = this.colorWrite;
  647. if ( this.stencilWriteMask !== 0xff ) data.stencilWriteMask = this.stencilWriteMask;
  648. if ( this.stencilFunc !== AlwaysStencilFunc ) data.stencilFunc = this.stencilFunc;
  649. if ( this.stencilRef !== 0 ) data.stencilRef = this.stencilRef;
  650. if ( this.stencilFuncMask !== 0xff ) data.stencilFuncMask = this.stencilFuncMask;
  651. if ( this.stencilFail !== KeepStencilOp ) data.stencilFail = this.stencilFail;
  652. if ( this.stencilZFail !== KeepStencilOp ) data.stencilZFail = this.stencilZFail;
  653. if ( this.stencilZPass !== KeepStencilOp ) data.stencilZPass = this.stencilZPass;
  654. if ( this.stencilWrite === true ) data.stencilWrite = this.stencilWrite;
  655. // rotation (SpriteMaterial)
  656. if ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation;
  657. if ( this.polygonOffset === true ) data.polygonOffset = true;
  658. if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor;
  659. if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits;
  660. if ( this.linewidth !== undefined && this.linewidth !== 1 ) data.linewidth = this.linewidth;
  661. if ( this.dashSize !== undefined ) data.dashSize = this.dashSize;
  662. if ( this.gapSize !== undefined ) data.gapSize = this.gapSize;
  663. if ( this.scale !== undefined ) data.scale = this.scale;
  664. if ( this.dithering === true ) data.dithering = true;
  665. if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;
  666. if ( this.alphaHash === true ) data.alphaHash = true;
  667. if ( this.alphaToCoverage === true ) data.alphaToCoverage = true;
  668. if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = true;
  669. if ( this.forceSinglePass === true ) data.forceSinglePass = true;
  670. if ( this.allowOverride === false ) data.allowOverride = false;
  671. if ( this.wireframe === true ) data.wireframe = true;
  672. if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
  673. if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
  674. if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
  675. if ( this.flatShading === true ) data.flatShading = true;
  676. if ( this.visible === false ) data.visible = false;
  677. if ( this.toneMapped === false ) data.toneMapped = false;
  678. if ( this.fog === false ) data.fog = false;
  679. if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;
  680. // TODO: Copied from Object3D.toJSON
  681. function extractFromCache( cache ) {
  682. const values = [];
  683. for ( const key in cache ) {
  684. const data = cache[ key ];
  685. delete data.metadata;
  686. values.push( data );
  687. }
  688. return values;
  689. }
  690. if ( isRootObject ) {
  691. const textures = extractFromCache( meta.textures );
  692. const images = extractFromCache( meta.images );
  693. if ( textures.length > 0 ) data.textures = textures;
  694. if ( images.length > 0 ) data.images = images;
  695. }
  696. return data;
  697. }
  698. /**
  699. * Returns a new material with copied values from this instance.
  700. *
  701. * @return {Material} A clone of this instance.
  702. */
  703. clone() {
  704. return new this.constructor().copy( this );
  705. }
  706. /**
  707. * Copies the values of the given material to this instance.
  708. *
  709. * @param {Material} source - The material to copy.
  710. * @return {Material} A reference to this instance.
  711. */
  712. copy( source ) {
  713. this.name = source.name;
  714. this.blending = source.blending;
  715. this.side = source.side;
  716. this.vertexColors = source.vertexColors;
  717. this.opacity = source.opacity;
  718. this.transparent = source.transparent;
  719. this.blendSrc = source.blendSrc;
  720. this.blendDst = source.blendDst;
  721. this.blendEquation = source.blendEquation;
  722. this.blendSrcAlpha = source.blendSrcAlpha;
  723. this.blendDstAlpha = source.blendDstAlpha;
  724. this.blendEquationAlpha = source.blendEquationAlpha;
  725. this.blendColor.copy( source.blendColor );
  726. this.blendAlpha = source.blendAlpha;
  727. this.depthFunc = source.depthFunc;
  728. this.depthTest = source.depthTest;
  729. this.depthWrite = source.depthWrite;
  730. this.stencilWriteMask = source.stencilWriteMask;
  731. this.stencilFunc = source.stencilFunc;
  732. this.stencilRef = source.stencilRef;
  733. this.stencilFuncMask = source.stencilFuncMask;
  734. this.stencilFail = source.stencilFail;
  735. this.stencilZFail = source.stencilZFail;
  736. this.stencilZPass = source.stencilZPass;
  737. this.stencilWrite = source.stencilWrite;
  738. const srcPlanes = source.clippingPlanes;
  739. let dstPlanes = null;
  740. if ( srcPlanes !== null ) {
  741. const n = srcPlanes.length;
  742. dstPlanes = new Array( n );
  743. for ( let i = 0; i !== n; ++ i ) {
  744. dstPlanes[ i ] = srcPlanes[ i ].clone();
  745. }
  746. }
  747. this.clippingPlanes = dstPlanes;
  748. this.clipIntersection = source.clipIntersection;
  749. this.clipShadows = source.clipShadows;
  750. this.shadowSide = source.shadowSide;
  751. this.colorWrite = source.colorWrite;
  752. this.precision = source.precision;
  753. this.polygonOffset = source.polygonOffset;
  754. this.polygonOffsetFactor = source.polygonOffsetFactor;
  755. this.polygonOffsetUnits = source.polygonOffsetUnits;
  756. this.dithering = source.dithering;
  757. this.alphaTest = source.alphaTest;
  758. this.alphaHash = source.alphaHash;
  759. this.alphaToCoverage = source.alphaToCoverage;
  760. this.premultipliedAlpha = source.premultipliedAlpha;
  761. this.forceSinglePass = source.forceSinglePass;
  762. this.allowOverride = source.allowOverride;
  763. this.visible = source.visible;
  764. this.toneMapped = source.toneMapped;
  765. this.userData = JSON.parse( JSON.stringify( source.userData ) );
  766. return this;
  767. }
  768. /**
  769. * Frees the GPU-related resources allocated by this instance. Call this
  770. * method whenever this instance is no longer used in your app.
  771. *
  772. * @fires Material#dispose
  773. */
  774. dispose() {
  775. /**
  776. * Fires when the material has been disposed of.
  777. *
  778. * @event Material#dispose
  779. * @type {Object}
  780. */
  781. this.dispatchEvent( { type: 'dispose' } );
  782. }
  783. /**
  784. * Setting this property to `true` indicates the engine the material
  785. * needs to be recompiled.
  786. *
  787. * @type {boolean}
  788. * @default false
  789. * @param {boolean} value
  790. */
  791. set needsUpdate( value ) {
  792. if ( value === true ) this.version ++;
  793. }
  794. }
  795. export { Material };
粤ICP备19079148号