/home/lindsay/xeolabs/xeogl-next/xeogl/src/materials/specularMaterial.js
API Docs for:

File: /home/lindsay/xeolabs/xeogl-next/xeogl/src/materials/specularMaterial.js

  1. /**
  2. A **SpecularMaterial** is a physically-based {{#crossLink "Material"}}{{/crossLink}} that defines the surface appearance of
  3. {{#crossLink "Mesh"}}Meshes{{/crossLink}} using the *specular-glossiness* workflow.
  4.  
  5. ## Examples
  6.  
  7. | <a href="../../examples/#importing_gltf_pbr_specular_telephone"><img src="../../assets/images/screenshots/SpecularMaterial/telephone.png"></img></a> | <a href="../../examples/#materials_specular_samples"><img src="../../assets/images/screenshots/SpecularMaterial/materials.png"></img></a> | <a href="../../examples/#materials_specular_textures"><img src="../../assets/images/screenshots/SpecularMaterial/textures.png"></img></a> | <a href="../../examples/#materials_specular_specularVsGlossiness"><img src="../../assets/images/screenshots/SpecularMaterial/specVsGloss.png"></img></a> |
  8. |:------:|:----:|:-----:|:-----:|
  9. |[glTF models with PBR materials](../../examples/#importing_gltf_pbr_specular_telephone)|[Sample materials ](../../examples/#materials_specular_samples) | [Texturing spec/gloss channels](../../examples/#materials_specular_textures) | [Specular Vs. glossiness](../../examples/#materials_specular_specularVsGlossiness) |
  10.  
  11. ## Overview
  12.  
  13. * SpecularMaterial is usually used for insulators, such as ceramic, wood and plastic.
  14. * {{#crossLink "MetallicMaterial"}}{{/crossLink}} is usually used for conductive materials, such as metal.
  15. * {{#crossLink "PhongMaterial"}}{{/crossLink}} is usually used for non-realistic objects.
  16.  
  17. For an introduction to PBR concepts, try these articles:
  18.  
  19. * Joe Wilson's [Basic Theory of Physically-Based Rendering](https://www.marmoset.co/posts/basic-theory-of-physically-based-rendering/)
  20. * Jeff Russel's [Physically-based Rendering, and you can too!](https://www.marmoset.co/posts/physically-based-rendering-and-you-can-too/)
  21. * Sebastien Legarde's [Adapting a physically-based shading model](http://seblagarde.wordpress.com/tag/physically-based-rendering/)
  22.  
  23. The following table summarizes SpecularMaterial properties:
  24.  
  25. | Property | Type | Range | Default Value | Space | Description |
  26. |:--------:|:----:|:-----:|:-------------:|:-----:|:-----------:|
  27. | {{#crossLink "SpecularMaterial/diffuse:property"}}{{/crossLink}} | Array | [0, 1] for all components | [1,1,1,1] | linear | The RGB components of the diffuse color of the material. |
  28. | {{#crossLink "SpecularMaterial/specular:property"}}{{/crossLink}} | Array | [0, 1] for all components | [1,1,1,1] | linear | The RGB components of the specular color of the material. |
  29. | {{#crossLink "SpecularMaterial/glossiness:property"}}{{/crossLink}} | Number | [0, 1] | 1 | linear | The glossiness the material. |
  30. | {{#crossLink "SpecularMaterial/specularF0:property"}}{{/crossLink}} | Number | [0, 1] | 1 | linear | The specularF0 of the material surface. |
  31. | {{#crossLink "SpecularMaterial/emissive:property"}}{{/crossLink}} | Array | [0, 1] for all components | [0,0,0] | linear | The RGB components of the emissive color of the material. |
  32. | {{#crossLink "SpecularMaterial/alpha:property"}}{{/crossLink}} | Number | [0, 1] | 1 | linear | The transparency of the material surface (0 fully transparent, 1 fully opaque). |
  33. | {{#crossLink "SpecularMaterial/diffuseMap:property"}}{{/crossLink}} | {{#crossLink "Texture"}}{{/crossLink}} | | null | sRGB | Texture RGB components multiplying by {{#crossLink "SpecularMaterial/diffuse:property"}}{{/crossLink}}. If the fourth component (A) is present, it multiplies by {{#crossLink "SpecularMaterial/alpha:property"}}{{/crossLink}}. |
  34. | {{#crossLink "SpecularMaterial/specularMap:property"}}{{/crossLink}} | {{#crossLink "Texture"}}{{/crossLink}} | | null | sRGB | Texture RGB components multiplying by {{#crossLink "SpecularMaterial/specular:property"}}{{/crossLink}}. If the fourth component (A) is present, it multiplies by {{#crossLink "SpecularMaterial/alpha:property"}}{{/crossLink}}. |
  35. | {{#crossLink "SpecularMaterial/glossinessMap:property"}}{{/crossLink}} | {{#crossLink "Texture"}}{{/crossLink}} | | null | linear | Texture with first component multiplying by {{#crossLink "SpecularMaterial/glossiness:property"}}{{/crossLink}}. |
  36. | {{#crossLink "SpecularMaterial/specularGlossinessMap:property"}}{{/crossLink}} | {{#crossLink "Texture"}}{{/crossLink}} | | null | linear | Texture with first three components multiplying by {{#crossLink "SpecularMaterial/specular:property"}}{{/crossLink}} and fourth component multiplying by {{#crossLink "SpecularMaterial/glossiness:property"}}{{/crossLink}}. |
  37. | {{#crossLink "SpecularMaterial/emissiveMap:property"}}{{/crossLink}} | {{#crossLink "Texture"}}{{/crossLink}} | | null | linear | Texture with RGB components multiplying by {{#crossLink "SpecularMaterial/emissive:property"}}{{/crossLink}}. |
  38. | {{#crossLink "SpecularMaterial/alphaMap:property"}}{{/crossLink}} | {{#crossLink "Texture"}}{{/crossLink}} | | null | linear | Texture with first component multiplying by {{#crossLink "SpecularMaterial/alpha:property"}}{{/crossLink}}. |
  39. | {{#crossLink "SpecularMaterial/occlusionMap:property"}}{{/crossLink}} | {{#crossLink "Texture"}}{{/crossLink}} | | null | linear | Ambient occlusion texture multiplying by surface's reflected diffuse and specular light. |
  40. | {{#crossLink "SpecularMaterial/normalMap:property"}}{{/crossLink}} | {{#crossLink "Texture"}}{{/crossLink}} | | null | linear | Tangent-space normal map. |
  41. | {{#crossLink "SpecularMaterial/alphaMode:property"}}{{/crossLink}} | String | "opaque", "blend", "mask" | "blend" | | Alpha blend mode. |
  42. | {{#crossLink "SpecularMaterial/alphaCutoff:property"}}{{/crossLink}} | Number | [0..1] | 0.5 | | Alpha cutoff value. |
  43. | {{#crossLink "SpecularMaterial/backfaces:property"}}{{/crossLink}} | Boolean | | false | | Whether to render {{#crossLink "Geometry"}}Geometry{{/crossLink}} backfaces. |
  44. | {{#crossLink "SpecularMaterial/frontface:property"}}{{/crossLink}} | String | "ccw", "cw" | "ccw" | | The winding order for {{#crossLink "Geometry"}}Geometry{{/crossLink}} frontfaces - "cw" for clockwise, or "ccw" for counter-clockwise. |
  45.  
  46. ## Usage
  47.  
  48. In the example below we'll create the plastered sphere shown in the [Sample Materials](../../examples/#materials_specular_textures) example (see screenshots above).
  49.  
  50. Here's a closeup of the sphere we'll create:
  51.  
  52. <a href="../../examples/#materials_specular_samples"><img src="../../assets/images/screenshots/SpecularMaterial/plaster.png"></img></a>
  53.  
  54. Our plastered sphere {{#crossLink "Mesh"}}{{/crossLink}} has:
  55.  
  56. * a {{#crossLink "SphereGeometry"}}{{/crossLink}},
  57. * a SpecularMaterial with {{#crossLink "Texture"}}Textures{{/crossLink}} providing diffuse, glossiness, specular and normal maps.
  58.  
  59. We'll also provide its {{#crossLink "Scene"}}{{/crossLink}}'s {{#crossLink "Lights"}}{{/crossLink}} with
  60. {{#crossLink "DirLight"}}DirLights{{/crossLink}}, plus {{#crossLink "CubeTexture"}}CubeTextures{{/crossLink}} for light
  61. and reflection maps.
  62.  
  63. Note that in this example we're providing separate {{#crossLink "Texture"}}Textures{{/crossLink}} for the {{#crossLink "SpecularMaterial/specular:property"}}{{/crossLink}} and {{#crossLink "SpecularMaterial/glossiness:property"}}{{/crossLink}}
  64. channels, which allows us a little creative flexibility. Then, in the next example further down, we'll combine those channels
  65. within the same {{#crossLink "Texture"}}{{/crossLink}} for efficiency.
  66.  
  67. ````javascript
  68. var plasteredSphere = new xeogl.Mesh({
  69.  
  70. geometry: new xeogl.SphereGeometry({
  71. center: [0,0,0],
  72. radius: 1.5,
  73. heightSegments: 60,
  74. widthSegments: 60
  75. }),
  76.  
  77. material: new xeogl.SpecularMaterial({
  78.  
  79. // Channels with default values, just to show them
  80.  
  81. diffuse: [1.0, 1.0, 1.0],
  82. specular: [1.0, 1.0, 1.0],
  83. glossiness: 1.0,
  84. emissive: [0.0, 0.0, 0.0]
  85. alpha: 1.0,
  86.  
  87. // Textures to multiply some of the channels
  88.  
  89. diffuseMap: { // RGB components multiply by diffuse
  90. src: "textures/materials/poligon/Plaster07_1k/Plaster07_COL_VAR1_1K.jpg"
  91. },
  92. specularMap: { // RGB component multiplies by specular
  93. src: "textures/materials/poligon/Plaster07_1k/Plaster07_REFL_1K.jpg"
  94. },
  95. glossinessMap: { // R component multiplies by glossiness
  96. src: "textures/materials/poligon/Plaster07_1k/Plaster07_GLOSS_1K.jpg"
  97. },
  98. normalMap: {
  99. src: "textures/materials/poligon/Plaster07_1k/Plaster07_NRM_1K.jpg"
  100. }
  101. })
  102. });
  103.  
  104. var scene = plasteredSphere.scene;
  105.  
  106. scene.lights.lights = [
  107. new xeogl.DirLight({
  108. dir: [0.8, -0.6, -0.8],
  109. color: [0.8, 0.8, 0.8],
  110. space: "view"
  111. }),
  112. new xeogl.DirLight({
  113. dir: [-0.8, -0.4, -0.4],
  114. color: [0.4, 0.4, 0.5],
  115. space: "view"
  116. }),
  117. new xeogl.DirLight({
  118. dir: [0.2, -0.8, 0.8],
  119. color: [0.8, 0.8, 0.8],
  120. space: "view"
  121. }
  122. ];
  123.  
  124. scene.lights.lightMap = new xeogl.CubeTexture({
  125. src: [
  126. "textures/light/Uffizi_Gallery/Uffizi_Gallery_Irradiance_PX.png",
  127. "textures/light/Uffizi_Gallery/Uffizi_Gallery_Irradiance_NX.png",
  128. "textures/light/Uffizi_Gallery/Uffizi_Gallery_Irradiance_PY.png",
  129. "textures/light/Uffizi_Gallery/Uffizi_Gallery_Irradiance_NY.png",
  130. "textures/light/Uffizi_Gallery/Uffizi_Gallery_Irradiance_PZ.png",
  131. "textures/light/Uffizi_Gallery/Uffizi_Gallery_Irradiance_NZ.png"
  132. ]
  133. });
  134.  
  135. scene.lights.reflectionMap = new xeogl.CubeTexture({
  136. src: [
  137. "textures/reflect/Uffizi_Gallery/Uffizi_Gallery_Radiance_PX.png",
  138. "textures/reflect/Uffizi_Gallery/Uffizi_Gallery_Radiance_NX.png",
  139. "textures/reflect/Uffizi_Gallery/Uffizi_Gallery_Radiance_PY.png",
  140. "textures/reflect/Uffizi_Gallery/Uffizi_Gallery_Radiance_NY.png",
  141. "textures/reflect/Uffizi_Gallery/Uffizi_Gallery_Radiance_PZ.png",
  142. "textures/reflect/Uffizi_Gallery/Uffizi_Gallery_Radiance_NZ.png"
  143. ]
  144. });
  145. ````
  146.  
  147. ### Combining channels within the same textures
  148.  
  149. In the previous example we provided separate {{#crossLink "Texture"}}Textures{{/crossLink}} for the {{#crossLink "SpecularMaterial/specular:property"}}{{/crossLink}} and
  150. {{#crossLink "SpecularMaterial/glossiness:property"}}{{/crossLink}} channels, but we can combine those channels into the same {{#crossLink "Texture"}}{{/crossLink}} to reduce download time, memory footprint and rendering time (and also for glTF compatibility).
  151.  
  152. Here's our SpecularMaterial again with those channels combined in the
  153. {{#crossLink "SpecularMaterial/specularGlossinessMap:property"}}{{/crossLink}} {{#crossLink "Texture"}}Texture{{/crossLink}}, where the
  154. *RGB* component multiplies by {{#crossLink "SpecularMaterial/specular:property"}}{{/crossLink}} and *A* multiplies by {{#crossLink "SpecularMaterial/glossiness:property"}}{{/crossLink}}.
  155.  
  156. ````javascript
  157. plasteredSphere.material = new xeogl.SpecularMaterial({
  158.  
  159. // Default values
  160. diffuse: [1.0, 1.0, 1.0],
  161. specular: [1.0, 1.0, 1.0],
  162. glossiness: 1.0,
  163. emissive: [0.0, 0.0, 0.0]
  164. alpha: 1.0,
  165.  
  166. diffuseMap: {
  167. src: "textures/materials/poligon/Plaster07_1k/Plaster07_COL_VAR1_1K.jpg"
  168. },
  169. specularGlossinessMap: { // RGB multiplies by specular, A by glossiness
  170. src: "textures/materials/poligon/Plaster07_1k/Plaster07_REFL_GLOSS_1K.jpg"
  171. },
  172. normalMap: {
  173. src: "textures/materials/poligon/Plaster07_1k/Plaster07_NRM_1K.jpg"
  174. }
  175. });
  176. ````
  177.  
  178. Although not shown in this example, we can also texture {{#crossLink "SpecularMaterial/alpha:property"}}{{/crossLink}} with
  179. the *A* component of {{#crossLink "SpecularMaterial/diffuseMap:property"}}{{/crossLink}}'s {{#crossLink "Texture"}}{{/crossLink}},
  180. if required.
  181.  
  182. ## Transparency
  183.  
  184. ### Alpha Blending
  185.  
  186. Let's make our plastered sphere transparent. We'll update its SpecularMaterial's {{#crossLink "SpecularMaterial/alpha:property"}}{{/crossLink}}
  187. and {{#crossLink "SpecularMaterial/alphaMode:property"}}{{/crossLink}}, causing it to blend 50% with the background:
  188.  
  189. ````javascript
  190. plasteredSphere.material.alpha = 0.5;
  191. plasteredSphere.material.alphaMode = "blend";
  192. ````
  193.  
  194. *TODO: Screenshot*
  195.  
  196. ### Alpha Masking
  197.  
  198. Now let's make holes in our plastered sphere. We'll give its SpecularMaterial an {{#crossLink "SpecularMaterial/alphaMap:property"}}{{/crossLink}}
  199. and configure {{#crossLink "SpecularMaterial/alpha:property"}}{{/crossLink}}, {{#crossLink "SpecularMaterial/alphaMode:property"}}{{/crossLink}},
  200. and {{#crossLink "SpecularMaterial/alphaCutoff:property"}}{{/crossLink}} to treat it as an alpha mask:
  201.  
  202. ````javascript
  203. plasteredSphere.material.alphaMap = new xeogl.Texture({
  204. src: "textures/diffuse/crossGridColorMap.jpg"
  205. });
  206.  
  207. plasteredSphere.material.alpha = 1.0;
  208. plasteredSphere.material.alphaMode = "mask";
  209. plasteredSphere.material.alphaCutoff = 0.2;
  210. ````
  211.  
  212. *TODO: Screenshot*
  213.  
  214. @class SpecularMaterial
  215. @module xeogl
  216. @submodule materials
  217. @constructor
  218. @extends Material
  219.  
  220. @param [owner] {Component} Owner component. When destroyed, the owner will destroy this component as well. Creates this component within the default {{#crossLink "Scene"}}{{/crossLink}} when omitted.
  221.  
  222. @param [cfg] {*} The SpecularMaterial configuration
  223.  
  224. @param [cfg.id] {String} Optional ID, unique among all components in the parent {{#crossLink "Scene"}}Scene{{/crossLink}}, generated automatically when omitted.
  225.  
  226. @param [cfg.meta=null] {String:Object} Metadata to attach to this SpecularMaterial.
  227.  
  228. @param [cfg.diffuse=[1,1,1]] {Float32Array} RGB diffuse color of this SpecularMaterial. Multiplies by the RGB
  229. components of {{#crossLink "SpecularMaterial/diffuseMap:property"}}{{/crossLink}}.
  230.  
  231. @param [cfg.diffuseMap=undefined] {Texture} RGBA {{#crossLink "Texture"}}{{/crossLink}} containing the diffuse color
  232. of this SpecularMaterial, with optional *A* component for alpha. The RGB components multiply by the
  233. {{#crossLink "SpecularMaterial/diffuse:property"}}{{/crossLink}} property,
  234. while the *A* component, if present, multiplies by the {{#crossLink "SpecularMaterial/alpha:property"}}{{/crossLink}} property.
  235.  
  236. @param [cfg.specular=[1,1,1]] {Number} RGB specular color of this SpecularMaterial. Multiplies by the
  237. {{#crossLink "SpecularMaterial/specularMap:property"}}{{/crossLink}} and the *RGB* components of
  238. {{#crossLink "SpecularMaterial/specularGlossinessMap:property"}}{{/crossLink}}.
  239.  
  240. @param [cfg.specularMap=undefined] {Texture} RGB texture containing the specular color of this SpecularMaterial. Multiplies
  241. by the {{#crossLink "SpecularMaterial/specular:property"}}{{/crossLink}} property. Must be within the same {{#crossLink "Scene"}}Scene{{/crossLink}} as this SpecularMaterial.
  242.  
  243. @param [cfg.glossiness=1.0] {Number} Factor in the range [0..1] indicating how glossy this SpecularMaterial is. 0 is
  244. no glossiness, 1 is full glossiness. Multiplies by the *R* component of {{#crossLink "SpecularMaterial/glossinessMap:property"}}{{/crossLink}}
  245. and the *A* component of {{#crossLink "SpecularMaterial/specularGlossinessMap:property"}}{{/crossLink}}.
  246.  
  247. @param [cfg.specularGlossinessMap=undefined] {Texture} RGBA {{#crossLink "Texture"}}{{/crossLink}} containing this
  248. SpecularMaterial's specular color in its *RGB* component and glossiness in its *A* component. Its *RGB* components multiply by the
  249. {{#crossLink "SpecularMaterial/specular:property"}}{{/crossLink}} property, while its *A* component multiplies by the
  250. {{#crossLink "SpecularMaterial/glossiness:property"}}{{/crossLink}} property. Must be within the same
  251. {{#crossLink "Scene"}}Scene{{/crossLink}} as this SpecularMaterial.
  252.  
  253. @param [cfg.specularF0=0.0] {Number} Factor in the range 0..1 indicating how reflective this SpecularMaterial is.
  254.  
  255. @param [cfg.emissive=[0,0,0]] {Float32Array} RGB emissive color of this SpecularMaterial. Multiplies by the RGB
  256. components of {{#crossLink "SpecularMaterial/emissiveMap:property"}}{{/crossLink}}.
  257.  
  258. @param [cfg.emissiveMap=undefined] {Texture} RGB {{#crossLink "Texture"}}{{/crossLink}} containing the emissive color of this
  259. SpecularMaterial. Multiplies by the {{#crossLink "SpecularMaterial/emissive:property"}}{{/crossLink}} property.
  260. Must be within the same {{#crossLink "Scene"}}Scene{{/crossLink}} as this SpecularMaterial.
  261.  
  262. @param [cfg.occlusionMap=undefined] {Texture} RGB ambient occlusion {{#crossLink "Texture"}}{{/crossLink}}. Within shaders,
  263. multiplies by the specular and diffuse light reflected by surfaces. Must be within the same {{#crossLink "Scene"}}{{/crossLink}}
  264. as this SpecularMaterial.
  265.  
  266. @param [cfg.normalMap=undefined] {Texture} RGB tangent-space normal {{#crossLink "Texture"}}{{/crossLink}}. Must be
  267. within the same {{#crossLink "Scene"}}Scene{{/crossLink}} as this SpecularMaterial.
  268.  
  269. @param [cfg.alpha=1.0] {Number} Factor in the range 0..1 indicating how transparent this SpecularMaterial is.
  270. A value of 0.0 indicates fully transparent, 1.0 is fully opaque. Multiplies by the *R* component of
  271. {{#crossLink "SpecularMaterial/alphaMap:property"}}{{/crossLink}} and the *A* component, if present, of
  272. {{#crossLink "SpecularMaterial/diffuseMap:property"}}{{/crossLink}}.
  273.  
  274. @param [cfg.alphaMap=undefined] {Texture} RGB {{#crossLink "Texture"}}{{/crossLink}} containing this SpecularMaterial's
  275. alpha in its *R* component. The *R* component multiplies by the {{#crossLink "SpecularMaterial/alpha:property"}}{{/crossLink}} property. Must
  276. be within the same {{#crossLink "Scene"}}Scene{{/crossLink}} as this SpecularMaterial.
  277.  
  278. @param [cfg.alphaMode="opaque"] {String} The alpha blend mode - accepted values are "opaque", "blend" and "mask".
  279. See the {{#crossLink "SpecularMaterial/alphaMode:property"}}{{/crossLink}} property for more info.
  280.  
  281. @param [cfg.alphaCutoff=0.5] {Number} The alpha cutoff value.
  282. See the {{#crossLink "SpecularMaterial/alphaCutoff:property"}}{{/crossLink}} property for more info.
  283.  
  284. @param [cfg.backfaces=false] {Boolean} Whether to render {{#crossLink "Geometry"}}Geometry{{/crossLink}} backfaces.
  285.  
  286. @param [cfg.frontface="ccw"] {Boolean} The winding order for {{#crossLink "Geometry"}}Geometry{{/crossLink}} front faces - "cw" for clockwise, or "ccw" for counter-clockwise.
  287.  
  288. @param [cfg.lineWidth=1] {Number} Scalar that controls the width of lines for {{#crossLink "Geometry"}}{{/crossLink}} with {{#crossLink "Geometry/primitive:property"}}{{/crossLink}} set to "lines".
  289. @param [cfg.pointSize=1] {Number} Scalar that controls the size of points for {{#crossLink "Geometry"}}{{/crossLink}} with {{#crossLink "Geometry/primitive:property"}}{{/crossLink}} set to "points".
  290.  
  291. */
  292. import {Material} from './material.js';
  293. import {State} from '../renderer/state.js';
  294. import {math} from '../math/math.js';
  295. import {componentClasses} from "./../componentClasses.js";
  296.  
  297. const type = "xeogl.SpecularMaterial";
  298. const alphaModes = {"opaque": 0, "mask": 1, "blend": 2};
  299. const alphaModeNames = ["opaque", "mask", "blend"];
  300.  
  301. class SpecularMaterial extends Material {
  302.  
  303. /**
  304. JavaScript class name for this Component.
  305.  
  306. For example: "xeogl.AmbientLight", "xeogl.MetallicMaterial" etc.
  307.  
  308. @property type
  309. @type String
  310. @final
  311. */
  312. get type() {
  313. return type;
  314. }
  315.  
  316. init(cfg) {
  317.  
  318. super.init(cfg);
  319.  
  320. this._state = new State({
  321. type: "SpecularMaterial",
  322. diffuse: math.vec3([1.0, 1.0, 1.0]),
  323. emissive: math.vec3([0.0, 0.0, 0.0]),
  324. specular: math.vec3([1.0, 1.0, 1.0]),
  325. glossiness: null,
  326. specularF0: null,
  327. alpha: null,
  328. alphaMode: null,
  329. alphaCutoff: null,
  330. lineWidth: null,
  331. pointSize: null,
  332. backfaces: null,
  333. frontface: null, // Boolean for speed; true == "ccw", false == "cw"
  334. hash: null
  335. });
  336.  
  337. this.diffuse = cfg.diffuse;
  338. this.specular = cfg.specular;
  339. this.glossiness = cfg.glossiness;
  340. this.specularF0 = cfg.specularF0;
  341. this.emissive = cfg.emissive;
  342. this.alpha = cfg.alpha;
  343.  
  344. if (cfg.diffuseMap) {
  345. this._diffuseMap = this._checkComponent("xeogl.Texture", cfg.diffuseMap);
  346. }
  347. if (cfg.emissiveMap) {
  348. this._emissiveMap = this._checkComponent("xeogl.Texture", cfg.emissiveMap);
  349. }
  350. if (cfg.specularMap) {
  351. this._specularMap = this._checkComponent("xeogl.Texture", cfg.specularMap);
  352. }
  353. if (cfg.glossinessMap) {
  354. this._glossinessMap = this._checkComponent("xeogl.Texture", cfg.glossinessMap);
  355. }
  356. if (cfg.specularGlossinessMap) {
  357. this._specularGlossinessMap = this._checkComponent("xeogl.Texture", cfg.specularGlossinessMap);
  358. }
  359. if (cfg.occlusionMap) {
  360. this._occlusionMap = this._checkComponent("xeogl.Texture", cfg.occlusionMap);
  361. }
  362. if (cfg.alphaMap) {
  363. this._alphaMap = this._checkComponent("xeogl.Texture", cfg.alphaMap);
  364. }
  365. if (cfg.normalMap) {
  366. this._normalMap = this._checkComponent("xeogl.Texture", cfg.normalMap);
  367. }
  368.  
  369. this.alphaMode = cfg.alphaMode;
  370. this.alphaCutoff = cfg.alphaCutoff;
  371. this.backfaces = cfg.backfaces;
  372. this.frontface = cfg.frontface;
  373.  
  374. this.lineWidth = cfg.lineWidth;
  375. this.pointSize = cfg.pointSize;
  376.  
  377. this._makeHash();
  378. }
  379.  
  380. _makeHash() {
  381. const state = this._state;
  382. const hash = ["/spe"];
  383. if (this._diffuseMap) {
  384. hash.push("/dm");
  385. if (this._diffuseMap.hasMatrix) {
  386. hash.push("/mat");
  387. }
  388. hash.push("/" + this._diffuseMap.encoding);
  389. }
  390. if (this._emissiveMap) {
  391. hash.push("/em");
  392. if (this._emissiveMap.hasMatrix) {
  393. hash.push("/mat");
  394. }
  395. }
  396. if (this._glossinessMap) {
  397. hash.push("/gm");
  398. if (this._glossinessMap.hasMatrix) {
  399. hash.push("/mat");
  400. }
  401. }
  402. if (this._specularMap) {
  403. hash.push("/sm");
  404. if (this._specularMap.hasMatrix) {
  405. hash.push("/mat");
  406. }
  407. }
  408. if (this._specularGlossinessMap) {
  409. hash.push("/sgm");
  410. if (this._specularGlossinessMap.hasMatrix) {
  411. hash.push("/mat");
  412. }
  413. }
  414. if (this._occlusionMap) {
  415. hash.push("/ocm");
  416. if (this._occlusionMap.hasMatrix) {
  417. hash.push("/mat");
  418. }
  419. }
  420. if (this._normalMap) {
  421. hash.push("/nm");
  422. if (this._normalMap.hasMatrix) {
  423. hash.push("/mat");
  424. }
  425. }
  426. if (this._alphaMap) {
  427. hash.push("/opm");
  428. if (this._alphaMap.hasMatrix) {
  429. hash.push("/mat");
  430. }
  431. }
  432. hash.push(";");
  433. state.hash = hash.join("");
  434. }
  435.  
  436. /**
  437. RGB diffuse color of this SpecularMaterial.
  438.  
  439. Multiplies by the *RGB* components of {{#crossLink "SpecularMaterial/diffuseMap:property"}}{{/crossLink}}.
  440.  
  441. @property diffuse
  442. @default [1.0, 1.0, 1.0]
  443. @type Float32Array
  444. */
  445. set diffuse(value) {
  446. let diffuse = this._state.diffuse;
  447. if (!diffuse) {
  448. diffuse = this._state.diffuse = new Float32Array(3);
  449. } else if (value && diffuse[0] === value[0] && diffuse[1] === value[1] && diffuse[2] === value[2]) {
  450. return;
  451. }
  452. if (value) {
  453. diffuse[0] = value[0];
  454. diffuse[1] = value[1];
  455. diffuse[2] = value[2];
  456. } else {
  457. diffuse[0] = 1;
  458. diffuse[1] = 1;
  459. diffuse[2] = 1;
  460. }
  461. this._renderer.imageDirty();
  462. }
  463.  
  464. get diffuse() {
  465. return this._state.diffuse;
  466. }
  467.  
  468. /**
  469. RGB {{#crossLink "Texture"}}{{/crossLink}} containing the diffuse color of this SpecularMaterial, with optional *A* component for alpha.
  470.  
  471. The *RGB* components multiply by the {{#crossLink "SpecularMaterial/diffuse:property"}}{{/crossLink}} property,
  472. while the *A* component, if present, multiplies by the {{#crossLink "SpecularMaterial/alpha:property"}}{{/crossLink}} property.
  473.  
  474. @property diffuseMap
  475. @default undefined
  476. @type {Texture}
  477. @final
  478. */
  479. get diffuseMap() {
  480. return this._diffuseMap;
  481. }
  482.  
  483. /**
  484. RGB specular color of this SpecularMaterial.
  485.  
  486. Multiplies by the {{#crossLink "SpecularMaterial/specularMap:property"}}{{/crossLink}}
  487. and the *A* component of {{#crossLink "SpecularMaterial/specularGlossinessMap:property"}}{{/crossLink}}.
  488.  
  489. @property specular
  490. @default [1.0, 1.0, 1.0]
  491. @type Float32Array
  492. */
  493. set specular(value) {
  494. let specular = this._state.specular;
  495. if (!specular) {
  496. specular = this._state.specular = new Float32Array(3);
  497. } else if (value && specular[0] === value[0] && specular[1] === value[1] && specular[2] === value[2]) {
  498. return;
  499. }
  500. if (value) {
  501. specular[0] = value[0];
  502. specular[1] = value[1];
  503. specular[2] = value[2];
  504. } else {
  505. specular[0] = 1;
  506. specular[1] = 1;
  507. specular[2] = 1;
  508. }
  509. this._renderer.imageDirty();
  510. }
  511.  
  512. get specular() {
  513. return this._state.specular;
  514. }
  515.  
  516. /**
  517. RGB texture containing the specular color of this SpecularMaterial.
  518.  
  519. Multiplies by the {{#crossLink "SpecularMaterial/specular:property"}}{{/crossLink}} property.
  520.  
  521. @property specularMap
  522. @default undefined
  523. @type {Texture}
  524. @final
  525. */
  526. get specularMap() {
  527. return this._specularMap;
  528. }
  529.  
  530. /**
  531. RGBA texture containing this SpecularMaterial's specular color in its *RGB* components and glossiness in its *A* component.
  532.  
  533. The *RGB* components multiply by the {{#crossLink "SpecularMaterial/specular:property"}}{{/crossLink}} property, while
  534. the *A* component multiplies by the {{#crossLink "SpecularMaterial/glossiness:property"}}{{/crossLink}} property.
  535.  
  536. @property specularGlossinessMap
  537. @default undefined
  538. @type {Texture}
  539. @final
  540. */
  541. get specularGlossinessMap() {
  542. return this._specularGlossinessMap;
  543. }
  544.  
  545. /**
  546. Factor in the range [0..1] indicating how glossy this SpecularMaterial is.
  547.  
  548. 0 is no glossiness, 1 is full glossiness.
  549.  
  550. Multiplies by the *R* component of {{#crossLink "SpecularMaterial/glossinessMap:property"}}{{/crossLink}}
  551. and the *A* component of {{#crossLink "SpecularMaterial/specularGlossinessMap:property"}}{{/crossLink}}.
  552.  
  553. @property glossiness
  554. @default 1.0
  555. @type Number
  556. */
  557. set glossiness(value) {
  558. value = (value !== undefined && value !== null) ? value : 1.0;
  559. if (this._state.glossiness === value) {
  560. return;
  561. }
  562. this._state.glossiness = value;
  563. this._renderer.imageDirty();
  564. }
  565.  
  566. get glossiness() {
  567. return this._state.glossiness;
  568. }
  569.  
  570. /**
  571. RGB texture containing this SpecularMaterial's glossiness in its *R* component.
  572.  
  573. The *R* component multiplies by the {{#crossLink "SpecularMaterial/glossiness:property"}}{{/crossLink}} property.
  574.  
  575. Must be within the same {{#crossLink "Scene"}}Scene{{/crossLink}} as this SpecularMaterial.
  576.  
  577. @property glossinessMap
  578. @default undefined
  579. @type {Texture}
  580. @final
  581. */
  582. get glossinessMap() {
  583. return this._glossinessMap;
  584. }
  585.  
  586. /**
  587. Factor in the range [0..1] indicating amount of specular Fresnel.
  588.  
  589. @property specularF0
  590. @default 0.0
  591. @type Number
  592. */
  593. set specularF0(value) {
  594. value = (value !== undefined && value !== null) ? value : 0.0;
  595. if (this._state.specularF0 === value) {
  596. return;
  597. }
  598. this._state.specularF0 = value;
  599. this._renderer.imageDirty();
  600. }
  601.  
  602. get specularF0() {
  603. return this._state.specularF0;
  604. }
  605.  
  606. /**
  607. RGB emissive color of this SpecularMaterial.
  608.  
  609. Multiplies by {{#crossLink "SpecularMaterial/emissiveMap:property"}}{{/crossLink}}.
  610.  
  611. @property emissive
  612. @default [0.0, 0.0, 0.0]
  613. @type Float32Array
  614. */
  615. set emissive(value) {
  616. let emissive = this._state.emissive;
  617. if (!emissive) {
  618. emissive = this._state.emissive = new Float32Array(3);
  619. } else if (value && emissive[0] === value[0] && emissive[1] === value[1] && emissive[2] === value[2]) {
  620. return;
  621. }
  622. if (value) {
  623. emissive[0] = value[0];
  624. emissive[1] = value[1];
  625. emissive[2] = value[2];
  626. } else {
  627. emissive[0] = 0;
  628. emissive[1] = 0;
  629. emissive[2] = 0;
  630. }
  631. this._renderer.imageDirty();
  632. }
  633.  
  634. get emissive() {
  635. return this._state.emissive;
  636. }
  637.  
  638. /**
  639. RGB texture containing the emissive color of this SpecularMaterial.
  640.  
  641. Multiplies by the {{#crossLink "SpecularMaterial/emissive:property"}}{{/crossLink}} property.
  642.  
  643. @property emissiveMap
  644. @default undefined
  645. @type {Texture}
  646. @final
  647. */
  648. get emissiveMap() {
  649. return this._emissiveMap;
  650. }
  651.  
  652. /**
  653. Factor in the range [0..1] indicating how transparent this SpecularMaterial is.
  654.  
  655. A value of 0.0 is fully transparent, while 1.0 is fully opaque.
  656.  
  657. Multiplies by the *R* component of {{#crossLink "SpecularMaterial/alphaMap:property"}}{{/crossLink}} and
  658. the *A* component, if present, of {{#crossLink "SpecularMaterial/diffuseMap:property"}}{{/crossLink}}.
  659.  
  660. @property alpha
  661. @default 1.0
  662. @type Number
  663. */
  664. set alpha(value) {
  665. value = (value !== undefined && value !== null) ? value : 1.0;
  666. if (this._state.alpha === value) {
  667. return;
  668. }
  669. this._state.alpha = value;
  670. this._renderer.imageDirty();
  671. }
  672.  
  673. get alpha() {
  674. return this._state.alpha;
  675. }
  676.  
  677. /**
  678. RGB {{#crossLink "Texture"}}{{/crossLink}} with alpha in its *R* component.
  679.  
  680. The *R* component multiplies by the {{#crossLink "SpecularMaterial/alpha:property"}}{{/crossLink}} property.
  681.  
  682. @property alphaMap
  683. @default undefined
  684. @type {Texture}
  685. @final
  686. */
  687. get alphaMap() {
  688. return this._alphaMap;
  689. }
  690.  
  691. /**
  692. RGB tangent-space normal {{#crossLink "Texture"}}{{/crossLink}} attached to this SpecularMaterial.
  693.  
  694. @property normalMap
  695. @default undefined
  696. @type {Texture}
  697. @final
  698. */
  699. get normalMap() {
  700. return this._normalMap;
  701. }
  702.  
  703. /**
  704. RGB ambient occlusion {{#crossLink "Texture"}}{{/crossLink}} attached to this SpecularMaterial.
  705.  
  706. Within objectRenderers, multiplies by the specular and diffuse light reflected by surfaces.
  707.  
  708. @property occlusionMap
  709. @default undefined
  710. @type {Texture}
  711. @final
  712. */
  713. get occlusionMap() {
  714. return this._occlusionMap;
  715. }
  716.  
  717. /**
  718. The alpha rendering mode.
  719.  
  720. This governs how alpha is treated. Alpha is the combined result of the
  721. {{#crossLink "SpecularMaterial/alpha:property"}}{{/crossLink}} and
  722. {{#crossLink "SpecularMaterial/alphaMap:property"}}{{/crossLink}} properties.
  723.  
  724. * "opaque" - The alpha value is ignored and the rendered output is fully opaque.
  725. * "mask" - The rendered output is either fully opaque or fully transparent depending on the alpha value and the specified alpha cutoff value.
  726. * "blend" - The alpha value is used to composite the source and destination areas. The rendered output is combined with the background using the normal painting operation (i.e. the Porter and Duff over operator)
  727.  
  728. @property alphaMode
  729. @default "opaque"
  730. @type {String}
  731. */
  732. set alphaMode(alphaMode) {
  733. alphaMode = alphaMode || "opaque";
  734. let value = alphaModes[alphaMode];
  735. if (value === undefined) {
  736. this.error("Unsupported value for 'alphaMode': " + alphaMode + " defaulting to 'opaque'");
  737. value = "opaque";
  738. }
  739. if (this._state.alphaMode === value) {
  740. return;
  741. }
  742. this._state.alphaMode = value;
  743. this._renderer.imageDirty();
  744. }
  745.  
  746. get alphaMode() {
  747. return alphaModeNames[this._state.alphaMode];
  748. }
  749.  
  750. /**
  751. The alpha cutoff value.
  752.  
  753. Specifies the cutoff threshold when {{#crossLink "SpecularMaterial/alphaMode:property"}}{{/crossLink}}
  754. equals "mask". If the alpha is greater than or equal to this value then it is rendered as fully
  755. opaque, otherwise, it is rendered as fully transparent. A value greater than 1.0 will render the entire
  756. material as fully transparent. This value is ignored for other modes.
  757.  
  758. Alpha is the combined result of the
  759. {{#crossLink "SpecularMaterial/alpha:property"}}{{/crossLink}} and
  760. {{#crossLink "SpecularMaterial/alphaMap:property"}}{{/crossLink}} properties.
  761.  
  762. @property alphaCutoff
  763. @default 0.5
  764. @type {Number}
  765. */
  766. set alphaCutoff(alphaCutoff) {
  767. if (alphaCutoff === null || alphaCutoff === undefined) {
  768. alphaCutoff = 0.5;
  769. }
  770. if (this._state.alphaCutoff === alphaCutoff) {
  771. return;
  772. }
  773. this._state.alphaCutoff = alphaCutoff;
  774. }
  775.  
  776. get alphaCutoff() {
  777. return this._state.alphaCutoff;
  778. }
  779.  
  780. /**
  781. Whether backfaces are visible on attached {{#crossLink "Mesh"}}Meshes{{/crossLink}}.
  782.  
  783. The backfaces will belong to {{#crossLink "Geometry"}}{{/crossLink}} compoents that are also attached to
  784. the {{#crossLink "Mesh"}}Meshes{{/crossLink}}.
  785.  
  786. @property backfaces
  787. @default false
  788. @type Boolean
  789. */
  790. set backfaces(value) {
  791. value = !!value;
  792. if (this._state.backfaces === value) {
  793. return;
  794. }
  795. this._state.backfaces = value;
  796. this._renderer.imageDirty();
  797. }
  798.  
  799. get backfaces() {
  800. return this._state.backfaces;
  801. }
  802.  
  803. /**
  804. Indicates the winding direction of front faces on attached {{#crossLink "Mesh"}}Meshes{{/crossLink}}.
  805.  
  806. The faces will belong to {{#crossLink "Geometry"}}{{/crossLink}} components that are also attached to
  807. the {{#crossLink "Mesh"}}Meshes{{/crossLink}}.
  808.  
  809. @property frontface
  810. @default "ccw"
  811. @type String
  812. */
  813. set frontface(value) {
  814. value = value !== "cw";
  815. if (this._state.frontface === value) {
  816. return;
  817. }
  818. this._state.frontface = value;
  819. this._renderer.imageDirty();
  820. }
  821.  
  822. get frontface() {
  823. return this._state.frontface ? "ccw" : "cw";
  824. }
  825.  
  826. /**
  827. The SpecularMaterial's line width.
  828.  
  829. @property lineWidth
  830. @default 1.0
  831. @type Number
  832. */
  833. set lineWidth(value) {
  834. this._state.lineWidth = value || 1.0;
  835. this._renderer.imageDirty();
  836. }
  837.  
  838. get lineWidth() {
  839. return this._state.lineWidth;
  840. }
  841.  
  842. /**
  843. The SpecularMaterial's point size.
  844.  
  845. @property pointSize
  846. @default 1
  847. @type Number
  848. */
  849. set pointSize(value) {
  850. this._state.pointSize = value || 1;
  851. this._renderer.imageDirty();
  852. }
  853.  
  854. get pointSize() {
  855. return this._state.pointSize;
  856. }
  857.  
  858. destroy() {
  859. super.destroy();
  860. this._state.destroy();
  861. }
  862. }
  863.  
  864. componentClasses[type] = SpecularMaterial;
  865.  
  866. export{SpecularMaterial};