processPbrMaterials.js 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210
  1. import defaultValue from "../Core/defaultValue.js";
  2. import defined from "../Core/defined.js";
  3. import WebGLConstants from "../Core/WebGLConstants.js";
  4. import webGLConstantToGlslType from "../Core/webGLConstantToGlslType.js";
  5. import addToArray from "../ThirdParty/GltfPipeline/addToArray.js";
  6. import ForEach from "../ThirdParty/GltfPipeline/ForEach.js";
  7. import hasExtension from "../ThirdParty/GltfPipeline/hasExtension.js";
  8. import ModelUtility from "./ModelUtility.js";
  9. /**
  10. * @private
  11. */
  12. function processPbrMaterials(gltf, options) {
  13. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  14. // No need to create new techniques if they already exist,
  15. // the shader should handle these values
  16. if (hasExtension(gltf, "KHR_techniques_webgl")) {
  17. return gltf;
  18. }
  19. // All materials in glTF are PBR by default,
  20. // so we should apply PBR unless no materials are found.
  21. if (!defined(gltf.materials) || gltf.materials.length === 0) {
  22. return gltf;
  23. }
  24. if (!defined(gltf.extensions)) {
  25. gltf.extensions = {};
  26. }
  27. if (!defined(gltf.extensionsUsed)) {
  28. gltf.extensionsUsed = [];
  29. }
  30. if (!defined(gltf.extensionsRequired)) {
  31. gltf.extensionsRequired = [];
  32. }
  33. gltf.extensions.KHR_techniques_webgl = {
  34. programs: [],
  35. shaders: [],
  36. techniques: [],
  37. };
  38. gltf.extensionsUsed.push("KHR_techniques_webgl");
  39. gltf.extensionsRequired.push("KHR_techniques_webgl");
  40. var primitiveByMaterial = ModelUtility.splitIncompatibleMaterials(gltf);
  41. ForEach.material(gltf, function (material, materialIndex) {
  42. var generatedMaterialValues = {};
  43. var technique = generateTechnique(
  44. gltf,
  45. material,
  46. materialIndex,
  47. generatedMaterialValues,
  48. primitiveByMaterial,
  49. options
  50. );
  51. if (!defined(material.extensions)) {
  52. material.extensions = {};
  53. }
  54. material.extensions.KHR_techniques_webgl = {
  55. values: generatedMaterialValues,
  56. technique: technique,
  57. };
  58. });
  59. // If any primitives have semantics that aren't declared in the generated
  60. // shaders, we want to preserve them.
  61. ModelUtility.ensureSemanticExistence(gltf);
  62. return gltf;
  63. }
  64. function isSpecularGlossinessMaterial(material) {
  65. return (
  66. defined(material.extensions) &&
  67. defined(material.extensions.KHR_materials_pbrSpecularGlossiness)
  68. );
  69. }
  70. function addTextureCoordinates(
  71. gltf,
  72. textureName,
  73. generatedMaterialValues,
  74. defaultTexCoord,
  75. result
  76. ) {
  77. var texCoord;
  78. var texInfo = generatedMaterialValues[textureName];
  79. if (defined(texInfo) && defined(texInfo.texCoord) && texInfo.texCoord === 1) {
  80. defaultTexCoord = defaultTexCoord.replace("0", "1");
  81. }
  82. if (defined(generatedMaterialValues[textureName + "Offset"])) {
  83. texCoord = textureName + "Coord";
  84. result.fragmentShaderMain +=
  85. " vec2 " +
  86. texCoord +
  87. " = computeTexCoord(" +
  88. defaultTexCoord +
  89. ", " +
  90. textureName +
  91. "Offset, " +
  92. textureName +
  93. "Rotation, " +
  94. textureName +
  95. "Scale);\n";
  96. } else {
  97. texCoord = defaultTexCoord;
  98. }
  99. return texCoord;
  100. }
  101. var DEFAULT_TEXTURE_OFFSET = [0.0, 0.0];
  102. var DEFAULT_TEXTURE_ROTATION = [0.0];
  103. var DEFAULT_TEXTURE_SCALE = [1.0, 1.0];
  104. function handleKHRTextureTransform(
  105. parameterName,
  106. value,
  107. generatedMaterialValues
  108. ) {
  109. if (
  110. parameterName.indexOf("Texture") === -1 ||
  111. !defined(value.extensions) ||
  112. !defined(value.extensions.KHR_texture_transform)
  113. ) {
  114. return;
  115. }
  116. var uniformName = "u_" + parameterName;
  117. var extension = value.extensions.KHR_texture_transform;
  118. generatedMaterialValues[uniformName + "Offset"] = defaultValue(
  119. extension.offset,
  120. DEFAULT_TEXTURE_OFFSET
  121. );
  122. generatedMaterialValues[uniformName + "Rotation"] = defaultValue(
  123. extension.rotation,
  124. DEFAULT_TEXTURE_ROTATION
  125. );
  126. generatedMaterialValues[uniformName + "Scale"] = defaultValue(
  127. extension.scale,
  128. DEFAULT_TEXTURE_SCALE
  129. );
  130. if (defined(value.texCoord) && defined(extension.texCoord)) {
  131. generatedMaterialValues[uniformName].texCoord = extension.texCoord;
  132. }
  133. }
  134. function generateTechnique(
  135. gltf,
  136. material,
  137. materialIndex,
  138. generatedMaterialValues,
  139. primitiveByMaterial,
  140. options
  141. ) {
  142. var addBatchIdToGeneratedShaders = defaultValue(
  143. options.addBatchIdToGeneratedShaders,
  144. false
  145. );
  146. var techniquesWebgl = gltf.extensions.KHR_techniques_webgl;
  147. var techniques = techniquesWebgl.techniques;
  148. var shaders = techniquesWebgl.shaders;
  149. var programs = techniquesWebgl.programs;
  150. var useSpecGloss = isSpecularGlossinessMaterial(material);
  151. var uniformName;
  152. var parameterName;
  153. var value;
  154. var pbrMetallicRoughness = material.pbrMetallicRoughness;
  155. if (defined(pbrMetallicRoughness) && !useSpecGloss) {
  156. for (parameterName in pbrMetallicRoughness) {
  157. if (pbrMetallicRoughness.hasOwnProperty(parameterName)) {
  158. value = pbrMetallicRoughness[parameterName];
  159. uniformName = "u_" + parameterName;
  160. generatedMaterialValues[uniformName] = value;
  161. handleKHRTextureTransform(
  162. parameterName,
  163. value,
  164. generatedMaterialValues
  165. );
  166. }
  167. }
  168. }
  169. if (useSpecGloss) {
  170. var pbrSpecularGlossiness =
  171. material.extensions.KHR_materials_pbrSpecularGlossiness;
  172. for (parameterName in pbrSpecularGlossiness) {
  173. if (pbrSpecularGlossiness.hasOwnProperty(parameterName)) {
  174. value = pbrSpecularGlossiness[parameterName];
  175. uniformName = "u_" + parameterName;
  176. generatedMaterialValues[uniformName] = value;
  177. handleKHRTextureTransform(
  178. parameterName,
  179. value,
  180. generatedMaterialValues
  181. );
  182. }
  183. }
  184. }
  185. for (var additional in material) {
  186. if (
  187. material.hasOwnProperty(additional) &&
  188. (additional.indexOf("Texture") >= 0 || additional.indexOf("Factor") >= 0)
  189. ) {
  190. value = material[additional];
  191. uniformName = "u_" + additional;
  192. generatedMaterialValues[uniformName] = value;
  193. handleKHRTextureTransform(additional, value, generatedMaterialValues);
  194. }
  195. }
  196. var vertexShader = "precision highp float;\n";
  197. var fragmentShader = "precision highp float;\n";
  198. var skin;
  199. if (defined(gltf.skins)) {
  200. skin = gltf.skins[0];
  201. }
  202. var joints = defined(skin) ? skin.joints : [];
  203. var jointCount = joints.length;
  204. var primitiveInfo = primitiveByMaterial[materialIndex];
  205. var skinningInfo;
  206. var hasSkinning = false;
  207. var hasVertexColors = false;
  208. var hasMorphTargets = false;
  209. var hasNormals = false;
  210. var hasTangents = false;
  211. var hasTexCoords = false;
  212. var hasTexCoord1 = false;
  213. var hasOutline = false;
  214. var isUnlit = false;
  215. if (defined(primitiveInfo)) {
  216. skinningInfo = primitiveInfo.skinning;
  217. hasSkinning = skinningInfo.skinned && joints.length > 0;
  218. hasVertexColors = primitiveInfo.hasVertexColors;
  219. hasMorphTargets = primitiveInfo.hasMorphTargets;
  220. hasNormals = primitiveInfo.hasNormals;
  221. hasTangents = primitiveInfo.hasTangents;
  222. hasTexCoords = primitiveInfo.hasTexCoords;
  223. hasTexCoord1 = primitiveInfo.hasTexCoord1;
  224. hasOutline = primitiveInfo.hasOutline;
  225. }
  226. var morphTargets;
  227. if (hasMorphTargets) {
  228. ForEach.mesh(gltf, function (mesh) {
  229. ForEach.meshPrimitive(mesh, function (primitive) {
  230. if (primitive.material === materialIndex) {
  231. var targets = primitive.targets;
  232. if (defined(targets)) {
  233. morphTargets = targets;
  234. }
  235. }
  236. });
  237. });
  238. }
  239. // Add techniques
  240. var techniqueUniforms = {
  241. // Add matrices
  242. u_modelViewMatrix: {
  243. semantic: hasExtension(gltf, "CESIUM_RTC")
  244. ? "CESIUM_RTC_MODELVIEW"
  245. : "MODELVIEW",
  246. type: WebGLConstants.FLOAT_MAT4,
  247. },
  248. u_projectionMatrix: {
  249. semantic: "PROJECTION",
  250. type: WebGLConstants.FLOAT_MAT4,
  251. },
  252. };
  253. if (
  254. defined(material.extensions) &&
  255. defined(material.extensions.KHR_materials_unlit)
  256. ) {
  257. isUnlit = true;
  258. hasNormals = false;
  259. hasTangents = false;
  260. }
  261. if (hasNormals) {
  262. techniqueUniforms.u_normalMatrix = {
  263. semantic: "MODELVIEWINVERSETRANSPOSE",
  264. type: WebGLConstants.FLOAT_MAT3,
  265. };
  266. }
  267. if (hasSkinning) {
  268. techniqueUniforms.u_jointMatrix = {
  269. count: jointCount,
  270. semantic: "JOINTMATRIX",
  271. type: WebGLConstants.FLOAT_MAT4,
  272. };
  273. }
  274. if (hasMorphTargets) {
  275. techniqueUniforms.u_morphWeights = {
  276. count: morphTargets.length,
  277. semantic: "MORPHWEIGHTS",
  278. type: WebGLConstants.FLOAT,
  279. };
  280. }
  281. var alphaMode = material.alphaMode;
  282. if (defined(alphaMode) && alphaMode === "MASK") {
  283. techniqueUniforms.u_alphaCutoff = {
  284. semantic: "ALPHACUTOFF",
  285. type: WebGLConstants.FLOAT,
  286. };
  287. }
  288. // Add material values
  289. for (uniformName in generatedMaterialValues) {
  290. if (generatedMaterialValues.hasOwnProperty(uniformName)) {
  291. techniqueUniforms[uniformName] = {
  292. type: getPBRValueType(uniformName),
  293. };
  294. }
  295. }
  296. var baseColorUniform = defaultValue(
  297. techniqueUniforms.u_baseColorTexture,
  298. techniqueUniforms.u_baseColorFactor
  299. );
  300. if (defined(baseColorUniform)) {
  301. baseColorUniform.semantic = "_3DTILESDIFFUSE";
  302. }
  303. // Add uniforms to shaders
  304. for (uniformName in techniqueUniforms) {
  305. if (techniqueUniforms.hasOwnProperty(uniformName)) {
  306. var uniform = techniqueUniforms[uniformName];
  307. var arraySize = defined(uniform.count) ? "[" + uniform.count + "]" : "";
  308. if (
  309. (uniform.type !== WebGLConstants.FLOAT_MAT3 &&
  310. uniform.type !== WebGLConstants.FLOAT_MAT4 &&
  311. uniformName !== "u_morphWeights") ||
  312. uniform.useInFragment
  313. ) {
  314. fragmentShader +=
  315. "uniform " +
  316. webGLConstantToGlslType(uniform.type) +
  317. " " +
  318. uniformName +
  319. arraySize +
  320. ";\n";
  321. delete uniform.useInFragment;
  322. } else {
  323. vertexShader +=
  324. "uniform " +
  325. webGLConstantToGlslType(uniform.type) +
  326. " " +
  327. uniformName +
  328. arraySize +
  329. ";\n";
  330. }
  331. }
  332. }
  333. if (hasOutline) {
  334. fragmentShader += "uniform sampler2D u_outlineTexture;\n";
  335. }
  336. // Add attributes with semantics
  337. var vertexShaderMain = "";
  338. if (hasSkinning) {
  339. vertexShaderMain +=
  340. " mat4 skinMatrix =\n" +
  341. " a_weight.x * u_jointMatrix[int(a_joint.x)] +\n" +
  342. " a_weight.y * u_jointMatrix[int(a_joint.y)] +\n" +
  343. " a_weight.z * u_jointMatrix[int(a_joint.z)] +\n" +
  344. " a_weight.w * u_jointMatrix[int(a_joint.w)];\n";
  345. }
  346. // Add position always
  347. var techniqueAttributes = {
  348. a_position: {
  349. semantic: "POSITION",
  350. },
  351. };
  352. if (hasOutline) {
  353. techniqueAttributes.a_outlineCoordinates = {
  354. semantic: "_OUTLINE_COORDINATES",
  355. };
  356. }
  357. vertexShader += "attribute vec3 a_position;\n";
  358. if (hasNormals) {
  359. vertexShader += "varying vec3 v_positionEC;\n";
  360. }
  361. if (hasOutline) {
  362. vertexShader += "attribute vec3 a_outlineCoordinates;\n";
  363. vertexShader += "varying vec3 v_outlineCoordinates;\n";
  364. }
  365. // Morph Target Weighting
  366. vertexShaderMain += " vec3 weightedPosition = a_position;\n";
  367. if (hasNormals) {
  368. vertexShaderMain += " vec3 weightedNormal = a_normal;\n";
  369. }
  370. if (hasTangents) {
  371. vertexShaderMain += " vec4 weightedTangent = a_tangent;\n";
  372. }
  373. if (hasMorphTargets) {
  374. for (var k = 0; k < morphTargets.length; k++) {
  375. var targetAttributes = morphTargets[k];
  376. for (var targetAttribute in targetAttributes) {
  377. if (
  378. targetAttributes.hasOwnProperty(targetAttribute) &&
  379. targetAttribute !== "extras"
  380. ) {
  381. var attributeName = "a_" + targetAttribute + "_" + k;
  382. techniqueAttributes[attributeName] = {
  383. semantic: targetAttribute + "_" + k,
  384. };
  385. vertexShader += "attribute vec3 " + attributeName + ";\n";
  386. if (targetAttribute === "POSITION") {
  387. vertexShaderMain +=
  388. " weightedPosition += u_morphWeights[" +
  389. k +
  390. "] * " +
  391. attributeName +
  392. ";\n";
  393. } else if (targetAttribute === "NORMAL") {
  394. vertexShaderMain +=
  395. " weightedNormal += u_morphWeights[" +
  396. k +
  397. "] * " +
  398. attributeName +
  399. ";\n";
  400. } else if (hasTangents && targetAttribute === "TANGENT") {
  401. vertexShaderMain +=
  402. " weightedTangent.xyz += u_morphWeights[" +
  403. k +
  404. "] * " +
  405. attributeName +
  406. ";\n";
  407. }
  408. }
  409. }
  410. }
  411. }
  412. // Final position computation
  413. if (hasSkinning) {
  414. vertexShaderMain +=
  415. " vec4 position = skinMatrix * vec4(weightedPosition, 1.0);\n";
  416. } else {
  417. vertexShaderMain += " vec4 position = vec4(weightedPosition, 1.0);\n";
  418. }
  419. vertexShaderMain += " position = u_modelViewMatrix * position;\n";
  420. if (hasNormals) {
  421. vertexShaderMain += " v_positionEC = position.xyz;\n";
  422. }
  423. vertexShaderMain += " gl_Position = u_projectionMatrix * position;\n";
  424. if (hasOutline) {
  425. vertexShaderMain += " v_outlineCoordinates = a_outlineCoordinates;\n";
  426. }
  427. // Final normal computation
  428. if (hasNormals) {
  429. techniqueAttributes.a_normal = {
  430. semantic: "NORMAL",
  431. };
  432. vertexShader += "attribute vec3 a_normal;\n";
  433. vertexShader += "varying vec3 v_normal;\n";
  434. if (hasSkinning) {
  435. vertexShaderMain +=
  436. " v_normal = u_normalMatrix * mat3(skinMatrix) * weightedNormal;\n";
  437. } else {
  438. vertexShaderMain += " v_normal = u_normalMatrix * weightedNormal;\n";
  439. }
  440. fragmentShader += "varying vec3 v_normal;\n";
  441. fragmentShader += "varying vec3 v_positionEC;\n";
  442. }
  443. // Read tangents if available
  444. if (hasTangents) {
  445. techniqueAttributes.a_tangent = {
  446. semantic: "TANGENT",
  447. };
  448. vertexShader += "attribute vec4 a_tangent;\n";
  449. vertexShader += "varying vec4 v_tangent;\n";
  450. vertexShaderMain +=
  451. " v_tangent.xyz = u_normalMatrix * weightedTangent.xyz;\n";
  452. vertexShaderMain += " v_tangent.w = weightedTangent.w;\n";
  453. fragmentShader += "varying vec4 v_tangent;\n";
  454. }
  455. if (hasOutline) {
  456. fragmentShader += "varying vec3 v_outlineCoordinates;\n";
  457. }
  458. var fragmentShaderMain = "";
  459. // Add texture coordinates if the material uses them
  460. var v_texCoord;
  461. var normalTexCoord;
  462. var baseColorTexCoord;
  463. var specularGlossinessTexCoord;
  464. var diffuseTexCoord;
  465. var metallicRoughnessTexCoord;
  466. var occlusionTexCoord;
  467. var emissiveTexCoord;
  468. if (hasTexCoords) {
  469. techniqueAttributes.a_texcoord_0 = {
  470. semantic: "TEXCOORD_0",
  471. };
  472. v_texCoord = "v_texcoord_0";
  473. vertexShader += "attribute vec2 a_texcoord_0;\n";
  474. vertexShader += "varying vec2 " + v_texCoord + ";\n";
  475. vertexShaderMain += " " + v_texCoord + " = a_texcoord_0;\n";
  476. fragmentShader += "varying vec2 " + v_texCoord + ";\n";
  477. if (hasTexCoord1) {
  478. techniqueAttributes.a_texcoord_1 = {
  479. semantic: "TEXCOORD_1",
  480. };
  481. var v_texCoord1 = v_texCoord.replace("0", "1");
  482. vertexShader += "attribute vec2 a_texcoord_1;\n";
  483. vertexShader += "varying vec2 " + v_texCoord1 + ";\n";
  484. vertexShaderMain += " " + v_texCoord1 + " = a_texcoord_1;\n";
  485. fragmentShader += "varying vec2 " + v_texCoord1 + ";\n";
  486. }
  487. var result = {
  488. fragmentShaderMain: fragmentShaderMain,
  489. };
  490. normalTexCoord = addTextureCoordinates(
  491. gltf,
  492. "u_normalTexture",
  493. generatedMaterialValues,
  494. v_texCoord,
  495. result
  496. );
  497. baseColorTexCoord = addTextureCoordinates(
  498. gltf,
  499. "u_baseColorTexture",
  500. generatedMaterialValues,
  501. v_texCoord,
  502. result
  503. );
  504. specularGlossinessTexCoord = addTextureCoordinates(
  505. gltf,
  506. "u_specularGlossinessTexture",
  507. generatedMaterialValues,
  508. v_texCoord,
  509. result
  510. );
  511. diffuseTexCoord = addTextureCoordinates(
  512. gltf,
  513. "u_diffuseTexture",
  514. generatedMaterialValues,
  515. v_texCoord,
  516. result
  517. );
  518. metallicRoughnessTexCoord = addTextureCoordinates(
  519. gltf,
  520. "u_metallicRoughnessTexture",
  521. generatedMaterialValues,
  522. v_texCoord,
  523. result
  524. );
  525. occlusionTexCoord = addTextureCoordinates(
  526. gltf,
  527. "u_occlusionTexture",
  528. generatedMaterialValues,
  529. v_texCoord,
  530. result
  531. );
  532. emissiveTexCoord = addTextureCoordinates(
  533. gltf,
  534. "u_emissiveTexture",
  535. generatedMaterialValues,
  536. v_texCoord,
  537. result
  538. );
  539. fragmentShaderMain = result.fragmentShaderMain;
  540. }
  541. // Add skinning information if available
  542. if (hasSkinning) {
  543. techniqueAttributes.a_joint = {
  544. semantic: "JOINTS_0",
  545. };
  546. techniqueAttributes.a_weight = {
  547. semantic: "WEIGHTS_0",
  548. };
  549. vertexShader += "attribute vec4 a_joint;\n";
  550. vertexShader += "attribute vec4 a_weight;\n";
  551. }
  552. if (hasVertexColors) {
  553. techniqueAttributes.a_vertexColor = {
  554. semantic: "COLOR_0",
  555. };
  556. vertexShader += "attribute vec4 a_vertexColor;\n";
  557. vertexShader += "varying vec4 v_vertexColor;\n";
  558. vertexShaderMain += " v_vertexColor = a_vertexColor;\n";
  559. fragmentShader += "varying vec4 v_vertexColor;\n";
  560. }
  561. if (addBatchIdToGeneratedShaders) {
  562. techniqueAttributes.a_batchId = {
  563. semantic: "_BATCHID",
  564. };
  565. vertexShader += "attribute float a_batchId;\n";
  566. }
  567. vertexShader += "void main(void) \n{\n";
  568. vertexShader += vertexShaderMain;
  569. vertexShader += "}\n";
  570. // Fragment shader lighting
  571. if (hasNormals) {
  572. fragmentShader += "const float M_PI = 3.141592653589793;\n";
  573. fragmentShader +=
  574. "vec3 lambertianDiffuse(vec3 diffuseColor) \n" +
  575. "{\n" +
  576. " return diffuseColor / M_PI;\n" +
  577. "}\n\n";
  578. fragmentShader +=
  579. "vec3 fresnelSchlick2(vec3 f0, vec3 f90, float VdotH) \n" +
  580. "{\n" +
  581. " return f0 + (f90 - f0) * pow(clamp(1.0 - VdotH, 0.0, 1.0), 5.0);\n" +
  582. "}\n\n";
  583. fragmentShader +=
  584. "vec3 fresnelSchlick(float metalness, float VdotH) \n" +
  585. "{\n" +
  586. " return metalness + (vec3(1.0) - metalness) * pow(1.0 - VdotH, 5.0);\n" +
  587. "}\n\n";
  588. fragmentShader +=
  589. "float smithVisibilityG1(float NdotV, float roughness) \n" +
  590. "{\n" +
  591. " float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;\n" +
  592. " return NdotV / (NdotV * (1.0 - k) + k);\n" +
  593. "}\n\n";
  594. fragmentShader +=
  595. "float smithVisibilityGGX(float roughness, float NdotL, float NdotV) \n" +
  596. "{\n" +
  597. " return smithVisibilityG1(NdotL, roughness) * smithVisibilityG1(NdotV, roughness);\n" +
  598. "}\n\n";
  599. fragmentShader +=
  600. "float GGX(float roughness, float NdotH) \n" +
  601. "{\n" +
  602. " float roughnessSquared = roughness * roughness;\n" +
  603. " float f = (NdotH * roughnessSquared - NdotH) * NdotH + 1.0;\n" +
  604. " return roughnessSquared / (M_PI * f * f);\n" +
  605. "}\n\n";
  606. }
  607. fragmentShader +=
  608. "vec3 SRGBtoLINEAR3(vec3 srgbIn) \n" +
  609. "{\n" +
  610. " return pow(srgbIn, vec3(2.2));\n" +
  611. "}\n\n";
  612. fragmentShader +=
  613. "vec4 SRGBtoLINEAR4(vec4 srgbIn) \n" +
  614. "{\n" +
  615. " vec3 linearOut = pow(srgbIn.rgb, vec3(2.2));\n" +
  616. " return vec4(linearOut, srgbIn.a);\n" +
  617. "}\n\n";
  618. fragmentShader +=
  619. "vec3 applyTonemapping(vec3 linearIn) \n" +
  620. "{\n" +
  621. "#ifndef HDR \n" +
  622. " return czm_acesTonemapping(linearIn);\n" +
  623. "#else \n" +
  624. " return linearIn;\n" +
  625. "#endif \n" +
  626. "}\n\n";
  627. fragmentShader +=
  628. "vec3 LINEARtoSRGB(vec3 linearIn) \n" +
  629. "{\n" +
  630. "#ifndef HDR \n" +
  631. " return pow(linearIn, vec3(1.0/2.2));\n" +
  632. "#else \n" +
  633. " return linearIn;\n" +
  634. "#endif \n" +
  635. "}\n\n";
  636. fragmentShader +=
  637. "vec2 computeTexCoord(vec2 texCoords, vec2 offset, float rotation, vec2 scale) \n" +
  638. "{\n" +
  639. " rotation = -rotation; \n" +
  640. " mat3 transform = mat3(\n" +
  641. " cos(rotation) * scale.x, sin(rotation) * scale.x, 0.0, \n" +
  642. " -sin(rotation) * scale.y, cos(rotation) * scale.y, 0.0, \n" +
  643. " offset.x, offset.y, 1.0); \n" +
  644. " vec2 transformedTexCoords = (transform * vec3(fract(texCoords), 1.0)).xy; \n" +
  645. " return transformedTexCoords; \n" +
  646. "}\n\n";
  647. fragmentShader += "#ifdef USE_IBL_LIGHTING \n";
  648. fragmentShader += "uniform vec2 gltf_iblFactor; \n";
  649. fragmentShader += "#endif \n";
  650. fragmentShader += "#ifdef USE_CUSTOM_LIGHT_COLOR \n";
  651. fragmentShader += "uniform vec3 gltf_lightColor; \n";
  652. fragmentShader += "#endif \n";
  653. fragmentShader += "void main(void) \n{\n";
  654. fragmentShader += fragmentShaderMain;
  655. // Add normal mapping to fragment shader
  656. if (hasNormals) {
  657. fragmentShader += " vec3 ng = normalize(v_normal);\n";
  658. fragmentShader +=
  659. " vec3 positionWC = vec3(czm_inverseView * vec4(v_positionEC, 1.0));\n";
  660. if (defined(generatedMaterialValues.u_normalTexture)) {
  661. if (hasTangents) {
  662. // Read tangents from varying
  663. fragmentShader += " vec3 t = normalize(v_tangent.xyz);\n";
  664. fragmentShader +=
  665. " vec3 b = normalize(cross(ng, t) * v_tangent.w);\n";
  666. fragmentShader += " mat3 tbn = mat3(t, b, ng);\n";
  667. fragmentShader +=
  668. " vec3 n = texture2D(u_normalTexture, " +
  669. normalTexCoord +
  670. ").rgb;\n";
  671. fragmentShader += " n = normalize(tbn * (2.0 * n - 1.0));\n";
  672. } else {
  673. // Add standard derivatives extension
  674. fragmentShader =
  675. "#ifdef GL_OES_standard_derivatives\n" +
  676. "#extension GL_OES_standard_derivatives : enable\n" +
  677. "#endif\n" +
  678. fragmentShader;
  679. // Compute tangents
  680. fragmentShader += "#ifdef GL_OES_standard_derivatives\n";
  681. fragmentShader += " vec3 pos_dx = dFdx(v_positionEC);\n";
  682. fragmentShader += " vec3 pos_dy = dFdy(v_positionEC);\n";
  683. fragmentShader +=
  684. " vec3 tex_dx = dFdx(vec3(" + normalTexCoord + ",0.0));\n";
  685. fragmentShader +=
  686. " vec3 tex_dy = dFdy(vec3(" + normalTexCoord + ",0.0));\n";
  687. fragmentShader +=
  688. " vec3 t = (tex_dy.t * pos_dx - tex_dx.t * pos_dy) / (tex_dx.s * tex_dy.t - tex_dy.s * tex_dx.t);\n";
  689. fragmentShader += " t = normalize(t - ng * dot(ng, t));\n";
  690. fragmentShader += " vec3 b = normalize(cross(ng, t));\n";
  691. fragmentShader += " mat3 tbn = mat3(t, b, ng);\n";
  692. fragmentShader +=
  693. " vec3 n = texture2D(u_normalTexture, " +
  694. normalTexCoord +
  695. ").rgb;\n";
  696. fragmentShader += " n = normalize(tbn * (2.0 * n - 1.0));\n";
  697. fragmentShader += "#else\n";
  698. fragmentShader += " vec3 n = ng;\n";
  699. fragmentShader += "#endif\n";
  700. }
  701. } else {
  702. fragmentShader += " vec3 n = ng;\n";
  703. }
  704. if (material.doubleSided) {
  705. fragmentShader += " if (czm_backFacing())\n";
  706. fragmentShader += " {\n";
  707. fragmentShader += " n = -n;\n";
  708. fragmentShader += " }\n";
  709. }
  710. }
  711. // Add base color to fragment shader
  712. if (defined(generatedMaterialValues.u_baseColorTexture)) {
  713. fragmentShader +=
  714. " vec4 baseColorWithAlpha = SRGBtoLINEAR4(texture2D(u_baseColorTexture, " +
  715. baseColorTexCoord +
  716. "));\n";
  717. if (defined(generatedMaterialValues.u_baseColorFactor)) {
  718. fragmentShader += " baseColorWithAlpha *= u_baseColorFactor;\n";
  719. }
  720. } else if (defined(generatedMaterialValues.u_baseColorFactor)) {
  721. fragmentShader += " vec4 baseColorWithAlpha = u_baseColorFactor;\n";
  722. } else {
  723. fragmentShader += " vec4 baseColorWithAlpha = vec4(1.0);\n";
  724. }
  725. if (hasVertexColors) {
  726. fragmentShader += " baseColorWithAlpha *= v_vertexColor;\n";
  727. }
  728. fragmentShader += " vec3 baseColor = baseColorWithAlpha.rgb;\n";
  729. if (hasNormals) {
  730. if (useSpecGloss) {
  731. if (defined(generatedMaterialValues.u_specularGlossinessTexture)) {
  732. fragmentShader +=
  733. " vec4 specularGlossiness = SRGBtoLINEAR4(texture2D(u_specularGlossinessTexture, " +
  734. specularGlossinessTexCoord +
  735. "));\n";
  736. fragmentShader += " vec3 specular = specularGlossiness.rgb;\n";
  737. fragmentShader += " float glossiness = specularGlossiness.a;\n";
  738. if (defined(generatedMaterialValues.u_specularFactor)) {
  739. fragmentShader += " specular *= u_specularFactor;\n";
  740. }
  741. if (defined(generatedMaterialValues.u_glossinessFactor)) {
  742. fragmentShader += " glossiness *= u_glossinessFactor;\n";
  743. }
  744. } else {
  745. if (defined(generatedMaterialValues.u_specularFactor)) {
  746. fragmentShader +=
  747. " vec3 specular = clamp(u_specularFactor, vec3(0.0), vec3(1.0));\n";
  748. } else {
  749. fragmentShader += " vec3 specular = vec3(1.0);\n";
  750. }
  751. if (defined(generatedMaterialValues.u_glossinessFactor)) {
  752. fragmentShader +=
  753. " float glossiness = clamp(u_glossinessFactor, 0.0, 1.0);\n";
  754. } else {
  755. fragmentShader += " float glossiness = 1.0;\n";
  756. }
  757. }
  758. if (defined(generatedMaterialValues.u_diffuseTexture)) {
  759. fragmentShader +=
  760. " vec4 diffuse = SRGBtoLINEAR4(texture2D(u_diffuseTexture, " +
  761. diffuseTexCoord +
  762. "));\n";
  763. if (defined(generatedMaterialValues.u_diffuseFactor)) {
  764. fragmentShader += " diffuse *= u_diffuseFactor;\n";
  765. }
  766. } else if (defined(generatedMaterialValues.u_diffuseFactor)) {
  767. fragmentShader +=
  768. " vec4 diffuse = clamp(u_diffuseFactor, vec4(0.0), vec4(1.0));\n";
  769. } else {
  770. fragmentShader += " vec4 diffuse = vec4(1.0);\n";
  771. }
  772. } else if (defined(generatedMaterialValues.u_metallicRoughnessTexture)) {
  773. fragmentShader +=
  774. " vec3 metallicRoughness = texture2D(u_metallicRoughnessTexture, " +
  775. metallicRoughnessTexCoord +
  776. ").rgb;\n";
  777. fragmentShader +=
  778. " float metalness = clamp(metallicRoughness.b, 0.0, 1.0);\n";
  779. fragmentShader +=
  780. " float roughness = clamp(metallicRoughness.g, 0.04, 1.0);\n";
  781. if (defined(generatedMaterialValues.u_metallicFactor)) {
  782. fragmentShader += " metalness *= u_metallicFactor;\n";
  783. }
  784. if (defined(generatedMaterialValues.u_roughnessFactor)) {
  785. fragmentShader += " roughness *= u_roughnessFactor;\n";
  786. }
  787. } else {
  788. if (defined(generatedMaterialValues.u_metallicFactor)) {
  789. fragmentShader +=
  790. " float metalness = clamp(u_metallicFactor, 0.0, 1.0);\n";
  791. } else {
  792. fragmentShader += " float metalness = 1.0;\n";
  793. }
  794. if (defined(generatedMaterialValues.u_roughnessFactor)) {
  795. fragmentShader +=
  796. " float roughness = clamp(u_roughnessFactor, 0.04, 1.0);\n";
  797. } else {
  798. fragmentShader += " float roughness = 1.0;\n";
  799. }
  800. }
  801. fragmentShader += " vec3 v = -normalize(v_positionEC);\n";
  802. // Generate fragment shader's lighting block
  803. fragmentShader += "#ifndef USE_CUSTOM_LIGHT_COLOR \n";
  804. fragmentShader += " vec3 lightColorHdr = czm_lightColorHdr;\n";
  805. fragmentShader += "#else \n";
  806. fragmentShader += " vec3 lightColorHdr = gltf_lightColor;\n";
  807. fragmentShader += "#endif \n";
  808. fragmentShader += " vec3 l = normalize(czm_lightDirectionEC);\n";
  809. fragmentShader += " vec3 h = normalize(v + l);\n";
  810. fragmentShader += " float NdotL = clamp(dot(n, l), 0.001, 1.0);\n";
  811. fragmentShader += " float NdotV = abs(dot(n, v)) + 0.001;\n";
  812. fragmentShader += " float NdotH = clamp(dot(n, h), 0.0, 1.0);\n";
  813. fragmentShader += " float LdotH = clamp(dot(l, h), 0.0, 1.0);\n";
  814. fragmentShader += " float VdotH = clamp(dot(v, h), 0.0, 1.0);\n";
  815. fragmentShader += " vec3 f0 = vec3(0.04);\n";
  816. // Whether the material uses metallic-roughness or specular-glossiness changes how the BRDF inputs are computed.
  817. // It does not change the implementation of the BRDF itself.
  818. if (useSpecGloss) {
  819. fragmentShader += " float roughness = 1.0 - glossiness;\n";
  820. fragmentShader +=
  821. " vec3 diffuseColor = diffuse.rgb * (1.0 - max(max(specular.r, specular.g), specular.b));\n";
  822. fragmentShader += " vec3 specularColor = specular;\n";
  823. } else {
  824. fragmentShader +=
  825. " vec3 diffuseColor = baseColor * (1.0 - metalness) * (1.0 - f0);\n";
  826. fragmentShader +=
  827. " vec3 specularColor = mix(f0, baseColor, metalness);\n";
  828. }
  829. fragmentShader += " float alpha = roughness * roughness;\n";
  830. fragmentShader +=
  831. " float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);\n";
  832. fragmentShader +=
  833. " vec3 r90 = vec3(clamp(reflectance * 25.0, 0.0, 1.0));\n";
  834. fragmentShader += " vec3 r0 = specularColor.rgb;\n";
  835. fragmentShader += " vec3 F = fresnelSchlick2(r0, r90, VdotH);\n";
  836. fragmentShader +=
  837. " float G = smithVisibilityGGX(alpha, NdotL, NdotV);\n";
  838. fragmentShader += " float D = GGX(alpha, NdotH);\n";
  839. fragmentShader +=
  840. " vec3 diffuseContribution = (1.0 - F) * lambertianDiffuse(diffuseColor);\n";
  841. fragmentShader +=
  842. " vec3 specularContribution = F * G * D / (4.0 * NdotL * NdotV);\n";
  843. fragmentShader +=
  844. " vec3 color = NdotL * lightColorHdr * (diffuseContribution + specularContribution);\n";
  845. // Use the procedural IBL if there are no environment maps
  846. fragmentShader +=
  847. "#if defined(USE_IBL_LIGHTING) && !defined(DIFFUSE_IBL) && !defined(SPECULAR_IBL) \n";
  848. fragmentShader +=
  849. " vec3 r = normalize(czm_inverseViewRotation * normalize(reflect(v, n)));\n";
  850. // Figure out if the reflection vector hits the ellipsoid
  851. fragmentShader += " float vertexRadius = length(positionWC);\n";
  852. fragmentShader +=
  853. " float horizonDotNadir = 1.0 - min(1.0, czm_ellipsoidRadii.x / vertexRadius);\n";
  854. fragmentShader +=
  855. " float reflectionDotNadir = dot(r, normalize(positionWC));\n";
  856. // Flipping the X vector is a cheap way to get the inverse of czm_temeToPseudoFixed, since that's a rotation about Z.
  857. fragmentShader += " r.x = -r.x;\n";
  858. fragmentShader += " r = -normalize(czm_temeToPseudoFixed * r);\n";
  859. fragmentShader += " r.x = -r.x;\n";
  860. fragmentShader += " float inverseRoughness = 1.04 - roughness;\n";
  861. fragmentShader += " inverseRoughness *= inverseRoughness;\n";
  862. fragmentShader +=
  863. " vec3 sceneSkyBox = textureCube(czm_environmentMap, r).rgb * inverseRoughness;\n";
  864. fragmentShader += " float atmosphereHeight = 0.05;\n";
  865. fragmentShader +=
  866. " float blendRegionSize = 0.1 * ((1.0 - inverseRoughness) * 8.0 + 1.1 - horizonDotNadir);\n";
  867. fragmentShader += " float blendRegionOffset = roughness * -1.0;\n";
  868. fragmentShader +=
  869. " float farAboveHorizon = clamp(horizonDotNadir - blendRegionSize * 0.5 + blendRegionOffset, 1.0e-10 - blendRegionSize, 0.99999);\n";
  870. fragmentShader +=
  871. " float aroundHorizon = clamp(horizonDotNadir + blendRegionSize * 0.5, 1.0e-10 - blendRegionSize, 0.99999);\n";
  872. fragmentShader +=
  873. " float farBelowHorizon = clamp(horizonDotNadir + blendRegionSize * 1.5, 1.0e-10 - blendRegionSize, 0.99999);\n";
  874. fragmentShader +=
  875. " float smoothstepHeight = smoothstep(0.0, atmosphereHeight, horizonDotNadir);\n";
  876. fragmentShader +=
  877. " vec3 belowHorizonColor = mix(vec3(0.1, 0.15, 0.25), vec3(0.4, 0.7, 0.9), smoothstepHeight);\n";
  878. fragmentShader += " vec3 nadirColor = belowHorizonColor * 0.5;\n";
  879. fragmentShader +=
  880. " vec3 aboveHorizonColor = mix(vec3(0.9, 1.0, 1.2), belowHorizonColor, roughness * 0.5);\n";
  881. fragmentShader +=
  882. " vec3 blueSkyColor = mix(vec3(0.18, 0.26, 0.48), aboveHorizonColor, reflectionDotNadir * inverseRoughness * 0.5 + 0.75);\n";
  883. fragmentShader +=
  884. " vec3 zenithColor = mix(blueSkyColor, sceneSkyBox, smoothstepHeight);\n";
  885. fragmentShader += " vec3 blueSkyDiffuseColor = vec3(0.7, 0.85, 0.9);\n";
  886. fragmentShader +=
  887. " float diffuseIrradianceFromEarth = (1.0 - horizonDotNadir) * (reflectionDotNadir * 0.25 + 0.75) * smoothstepHeight;\n";
  888. fragmentShader +=
  889. " float diffuseIrradianceFromSky = (1.0 - smoothstepHeight) * (1.0 - (reflectionDotNadir * 0.25 + 0.25));\n";
  890. fragmentShader +=
  891. " vec3 diffuseIrradiance = blueSkyDiffuseColor * clamp(diffuseIrradianceFromEarth + diffuseIrradianceFromSky, 0.0, 1.0);\n";
  892. fragmentShader +=
  893. " float notDistantRough = (1.0 - horizonDotNadir * roughness * 0.8);\n";
  894. fragmentShader +=
  895. " vec3 specularIrradiance = mix(zenithColor, aboveHorizonColor, smoothstep(farAboveHorizon, aroundHorizon, reflectionDotNadir) * notDistantRough);\n";
  896. fragmentShader +=
  897. " specularIrradiance = mix(specularIrradiance, belowHorizonColor, smoothstep(aroundHorizon, farBelowHorizon, reflectionDotNadir) * inverseRoughness);\n";
  898. fragmentShader +=
  899. " specularIrradiance = mix(specularIrradiance, nadirColor, smoothstep(farBelowHorizon, 1.0, reflectionDotNadir) * inverseRoughness);\n";
  900. // Luminance model from page 40 of http://silviojemma.com/public/papers/lighting/spherical-harmonic-lighting.pdf
  901. fragmentShader += "#ifdef USE_SUN_LUMINANCE \n";
  902. // Angle between sun and zenith
  903. fragmentShader +=
  904. " float LdotZenith = clamp(dot(normalize(czm_inverseViewRotation * l), normalize(positionWC * -1.0)), 0.001, 1.0);\n";
  905. fragmentShader += " float S = acos(LdotZenith);\n";
  906. // Angle between zenith and current pixel
  907. fragmentShader +=
  908. " float NdotZenith = clamp(dot(normalize(czm_inverseViewRotation * n), normalize(positionWC * -1.0)), 0.001, 1.0);\n";
  909. // Angle between sun and current pixel
  910. fragmentShader += " float gamma = acos(NdotL);\n";
  911. fragmentShader +=
  912. " float numerator = ((0.91 + 10.0 * exp(-3.0 * gamma) + 0.45 * pow(NdotL, 2.0)) * (1.0 - exp(-0.32 / NdotZenith)));\n";
  913. fragmentShader +=
  914. " float denominator = (0.91 + 10.0 * exp(-3.0 * S) + 0.45 * pow(LdotZenith,2.0)) * (1.0 - exp(-0.32));\n";
  915. fragmentShader +=
  916. " float luminance = gltf_luminanceAtZenith * (numerator / denominator);\n";
  917. fragmentShader += "#endif \n";
  918. fragmentShader +=
  919. " vec2 brdfLut = texture2D(czm_brdfLut, vec2(NdotV, roughness)).rg;\n";
  920. fragmentShader +=
  921. " vec3 IBLColor = (diffuseIrradiance * diffuseColor * gltf_iblFactor.x) + (specularIrradiance * SRGBtoLINEAR3(specularColor * brdfLut.x + brdfLut.y) * gltf_iblFactor.y);\n";
  922. fragmentShader +=
  923. " float maximumComponent = max(max(lightColorHdr.x, lightColorHdr.y), lightColorHdr.z);\n";
  924. fragmentShader +=
  925. " vec3 lightColor = lightColorHdr / max(maximumComponent, 1.0);\n";
  926. fragmentShader += " IBLColor *= lightColor;\n";
  927. fragmentShader += "#ifdef USE_SUN_LUMINANCE \n";
  928. fragmentShader += " color += IBLColor * luminance;\n";
  929. fragmentShader += "#else \n";
  930. fragmentShader += " color += IBLColor; \n";
  931. fragmentShader += "#endif \n";
  932. // Environment maps were provided, use them for IBL
  933. fragmentShader += "#elif defined(DIFFUSE_IBL) || defined(SPECULAR_IBL) \n";
  934. fragmentShader +=
  935. " mat3 fixedToENU = mat3(gltf_clippingPlanesMatrix[0][0], gltf_clippingPlanesMatrix[1][0], gltf_clippingPlanesMatrix[2][0], \n";
  936. fragmentShader +=
  937. " gltf_clippingPlanesMatrix[0][1], gltf_clippingPlanesMatrix[1][1], gltf_clippingPlanesMatrix[2][1], \n";
  938. fragmentShader +=
  939. " gltf_clippingPlanesMatrix[0][2], gltf_clippingPlanesMatrix[1][2], gltf_clippingPlanesMatrix[2][2]); \n";
  940. fragmentShader +=
  941. " const mat3 yUpToZUp = mat3(-1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0); \n";
  942. fragmentShader +=
  943. " vec3 cubeDir = normalize(yUpToZUp * fixedToENU * normalize(reflect(-v, n))); \n";
  944. fragmentShader += "#ifdef DIFFUSE_IBL \n";
  945. fragmentShader += "#ifdef CUSTOM_SPHERICAL_HARMONICS \n";
  946. fragmentShader +=
  947. " vec3 diffuseIrradiance = czm_sphericalHarmonics(cubeDir, gltf_sphericalHarmonicCoefficients); \n";
  948. fragmentShader += "#else \n";
  949. fragmentShader +=
  950. " vec3 diffuseIrradiance = czm_sphericalHarmonics(cubeDir, czm_sphericalHarmonicCoefficients); \n";
  951. fragmentShader += "#endif \n";
  952. fragmentShader += "#else \n";
  953. fragmentShader += " vec3 diffuseIrradiance = vec3(0.0); \n";
  954. fragmentShader += "#endif \n";
  955. fragmentShader += "#ifdef SPECULAR_IBL \n";
  956. fragmentShader +=
  957. " vec2 brdfLut = texture2D(czm_brdfLut, vec2(NdotV, roughness)).rg;\n";
  958. fragmentShader += "#ifdef CUSTOM_SPECULAR_IBL \n";
  959. fragmentShader +=
  960. " vec3 specularIBL = czm_sampleOctahedralProjection(gltf_specularMap, gltf_specularMapSize, cubeDir, roughness * gltf_maxSpecularLOD, gltf_maxSpecularLOD);\n";
  961. fragmentShader += "#else \n";
  962. fragmentShader +=
  963. " vec3 specularIBL = czm_sampleOctahedralProjection(czm_specularEnvironmentMaps, czm_specularEnvironmentMapSize, cubeDir, roughness * czm_specularEnvironmentMapsMaximumLOD, czm_specularEnvironmentMapsMaximumLOD);\n";
  964. fragmentShader += "#endif \n";
  965. fragmentShader += " specularIBL *= F * brdfLut.x + brdfLut.y;\n";
  966. fragmentShader += "#else \n";
  967. fragmentShader += " vec3 specularIBL = vec3(0.0); \n";
  968. fragmentShader += "#endif \n";
  969. fragmentShader +=
  970. " color += diffuseIrradiance * diffuseColor + specularColor * specularIBL;\n";
  971. fragmentShader += "#endif \n";
  972. } else {
  973. fragmentShader += " vec3 color = baseColor;\n";
  974. }
  975. // Ignore occlusion and emissive when unlit
  976. if (!isUnlit) {
  977. if (defined(generatedMaterialValues.u_occlusionTexture)) {
  978. fragmentShader +=
  979. " color *= texture2D(u_occlusionTexture, " +
  980. occlusionTexCoord +
  981. ").r;\n";
  982. }
  983. if (defined(generatedMaterialValues.u_emissiveTexture)) {
  984. fragmentShader +=
  985. " vec3 emissive = SRGBtoLINEAR3(texture2D(u_emissiveTexture, " +
  986. emissiveTexCoord +
  987. ").rgb);\n";
  988. if (defined(generatedMaterialValues.u_emissiveFactor)) {
  989. fragmentShader += " emissive *= u_emissiveFactor;\n";
  990. }
  991. fragmentShader += " color += emissive;\n";
  992. } else if (defined(generatedMaterialValues.u_emissiveFactor)) {
  993. fragmentShader += " color += u_emissiveFactor;\n";
  994. }
  995. }
  996. if (!isUnlit) {
  997. fragmentShader += " color = applyTonemapping(color);\n";
  998. }
  999. fragmentShader += " color = LINEARtoSRGB(color);\n";
  1000. if (hasOutline) {
  1001. fragmentShader += " float outlineness = max(\n";
  1002. fragmentShader +=
  1003. " texture2D(u_outlineTexture, vec2(v_outlineCoordinates.x, 0.5)).r,\n";
  1004. fragmentShader += " max(\n";
  1005. fragmentShader +=
  1006. " texture2D(u_outlineTexture, vec2(v_outlineCoordinates.y, 0.5)).r,\n";
  1007. fragmentShader +=
  1008. " texture2D(u_outlineTexture, vec2(v_outlineCoordinates.z, 0.5)).r));\n";
  1009. fragmentShader +=
  1010. " color = mix(color, vec3(0.0, 0.0, 0.0), outlineness);\n";
  1011. }
  1012. if (defined(alphaMode)) {
  1013. if (alphaMode === "MASK") {
  1014. fragmentShader += " if (baseColorWithAlpha.a < u_alphaCutoff) {\n";
  1015. fragmentShader += " discard;\n";
  1016. fragmentShader += " }\n";
  1017. fragmentShader += " gl_FragColor = vec4(color, 1.0);\n";
  1018. } else if (alphaMode === "BLEND") {
  1019. fragmentShader +=
  1020. " gl_FragColor = vec4(color, baseColorWithAlpha.a);\n";
  1021. } else {
  1022. fragmentShader += " gl_FragColor = vec4(color, 1.0);\n";
  1023. }
  1024. } else {
  1025. fragmentShader += " gl_FragColor = vec4(color, 1.0);\n";
  1026. }
  1027. fragmentShader += "}\n";
  1028. // Add shaders
  1029. var vertexShaderId = addToArray(shaders, {
  1030. type: WebGLConstants.VERTEX_SHADER,
  1031. extras: {
  1032. _pipeline: {
  1033. source: vertexShader,
  1034. extension: ".glsl",
  1035. },
  1036. },
  1037. });
  1038. var fragmentShaderId = addToArray(shaders, {
  1039. type: WebGLConstants.FRAGMENT_SHADER,
  1040. extras: {
  1041. _pipeline: {
  1042. source: fragmentShader,
  1043. extension: ".glsl",
  1044. },
  1045. },
  1046. });
  1047. // Add program
  1048. var programId = addToArray(programs, {
  1049. fragmentShader: fragmentShaderId,
  1050. vertexShader: vertexShaderId,
  1051. });
  1052. var techniqueId = addToArray(techniques, {
  1053. attributes: techniqueAttributes,
  1054. program: programId,
  1055. uniforms: techniqueUniforms,
  1056. });
  1057. return techniqueId;
  1058. }
  1059. function getPBRValueType(paramName) {
  1060. if (paramName.indexOf("Offset") !== -1) {
  1061. return WebGLConstants.FLOAT_VEC2;
  1062. } else if (paramName.indexOf("Rotation") !== -1) {
  1063. return WebGLConstants.FLOAT;
  1064. } else if (paramName.indexOf("Scale") !== -1) {
  1065. return WebGLConstants.FLOAT_VEC2;
  1066. } else if (paramName.indexOf("Texture") !== -1) {
  1067. return WebGLConstants.SAMPLER_2D;
  1068. }
  1069. switch (paramName) {
  1070. case "u_baseColorFactor":
  1071. return WebGLConstants.FLOAT_VEC4;
  1072. case "u_metallicFactor":
  1073. return WebGLConstants.FLOAT;
  1074. case "u_roughnessFactor":
  1075. return WebGLConstants.FLOAT;
  1076. case "u_emissiveFactor":
  1077. return WebGLConstants.FLOAT_VEC3;
  1078. // Specular Glossiness Types
  1079. case "u_diffuseFactor":
  1080. return WebGLConstants.FLOAT_VEC4;
  1081. case "u_specularFactor":
  1082. return WebGLConstants.FLOAT_VEC3;
  1083. case "u_glossinessFactor":
  1084. return WebGLConstants.FLOAT;
  1085. }
  1086. }
  1087. export default processPbrMaterials;