processPbrMaterials.js 40 KB

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