processModelMaterialsCommon.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  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 processModelMaterialsCommon(gltf, options) {
  13. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  14. if (!defined(gltf)) {
  15. return;
  16. }
  17. if (!hasExtension(gltf, "KHR_materials_common")) {
  18. return;
  19. }
  20. if (!hasExtension(gltf, "KHR_techniques_webgl")) {
  21. if (!defined(gltf.extensions)) {
  22. gltf.extensions = {};
  23. }
  24. gltf.extensions.KHR_techniques_webgl = {
  25. programs: [],
  26. shaders: [],
  27. techniques: [],
  28. };
  29. gltf.extensionsUsed.push("KHR_techniques_webgl");
  30. gltf.extensionsRequired.push("KHR_techniques_webgl");
  31. }
  32. var techniquesWebgl = gltf.extensions.KHR_techniques_webgl;
  33. lightDefaults(gltf);
  34. var lightParameters = generateLightParameters(gltf);
  35. var primitiveByMaterial = ModelUtility.splitIncompatibleMaterials(gltf);
  36. var techniques = {};
  37. var generatedTechniques = false;
  38. ForEach.material(gltf, function (material, materialIndex) {
  39. if (
  40. defined(material.extensions) &&
  41. defined(material.extensions.KHR_materials_common)
  42. ) {
  43. var khrMaterialsCommon = material.extensions.KHR_materials_common;
  44. var primitiveInfo = primitiveByMaterial[materialIndex];
  45. var techniqueKey = getTechniqueKey(khrMaterialsCommon, primitiveInfo);
  46. var technique = techniques[techniqueKey];
  47. if (!defined(technique)) {
  48. technique = generateTechnique(
  49. gltf,
  50. techniquesWebgl,
  51. primitiveInfo,
  52. khrMaterialsCommon,
  53. lightParameters,
  54. options.addBatchIdToGeneratedShaders
  55. );
  56. techniques[techniqueKey] = technique;
  57. generatedTechniques = true;
  58. }
  59. var materialValues = {};
  60. var values = khrMaterialsCommon.values;
  61. var uniformName;
  62. for (var valueName in values) {
  63. if (
  64. values.hasOwnProperty(valueName) &&
  65. valueName !== "transparent" &&
  66. valueName !== "doubleSided"
  67. ) {
  68. uniformName = "u_" + valueName.toLowerCase();
  69. materialValues[uniformName] = values[valueName];
  70. }
  71. }
  72. material.extensions.KHR_techniques_webgl = {
  73. technique: technique,
  74. values: materialValues,
  75. };
  76. material.alphaMode = "OPAQUE";
  77. if (khrMaterialsCommon.transparent) {
  78. material.alphaMode = "BLEND";
  79. }
  80. if (khrMaterialsCommon.doubleSided) {
  81. material.doubleSided = true;
  82. }
  83. }
  84. });
  85. if (!generatedTechniques) {
  86. return gltf;
  87. }
  88. // If any primitives have semantics that aren't declared in the generated
  89. // shaders, we want to preserve them.
  90. ModelUtility.ensureSemanticExistence(gltf);
  91. return gltf;
  92. }
  93. function generateLightParameters(gltf) {
  94. var result = {};
  95. var lights;
  96. if (
  97. defined(gltf.extensions) &&
  98. defined(gltf.extensions.KHR_materials_common)
  99. ) {
  100. lights = gltf.extensions.KHR_materials_common.lights;
  101. }
  102. if (defined(lights)) {
  103. // Figure out which node references the light
  104. var nodes = gltf.nodes;
  105. for (var nodeName in nodes) {
  106. if (nodes.hasOwnProperty(nodeName)) {
  107. var node = nodes[nodeName];
  108. if (
  109. defined(node.extensions) &&
  110. defined(node.extensions.KHR_materials_common)
  111. ) {
  112. var nodeLightId = node.extensions.KHR_materials_common.light;
  113. if (defined(nodeLightId) && defined(lights[nodeLightId])) {
  114. lights[nodeLightId].node = nodeName;
  115. }
  116. delete node.extensions.KHR_materials_common;
  117. }
  118. }
  119. }
  120. // Add light parameters to result
  121. var lightCount = 0;
  122. for (var lightName in lights) {
  123. if (lights.hasOwnProperty(lightName)) {
  124. var light = lights[lightName];
  125. var lightType = light.type;
  126. if (lightType !== "ambient" && !defined(light.node)) {
  127. delete lights[lightName];
  128. continue;
  129. }
  130. var lightBaseName = "light" + lightCount.toString();
  131. light.baseName = lightBaseName;
  132. switch (lightType) {
  133. case "ambient":
  134. var ambient = light.ambient;
  135. result[lightBaseName + "Color"] = {
  136. type: WebGLConstants.FLOAT_VEC3,
  137. value: ambient.color,
  138. };
  139. break;
  140. case "directional":
  141. var directional = light.directional;
  142. result[lightBaseName + "Color"] = {
  143. type: WebGLConstants.FLOAT_VEC3,
  144. value: directional.color,
  145. };
  146. if (defined(light.node)) {
  147. result[lightBaseName + "Transform"] = {
  148. node: light.node,
  149. semantic: "MODELVIEW",
  150. type: WebGLConstants.FLOAT_MAT4,
  151. };
  152. }
  153. break;
  154. case "point":
  155. var point = light.point;
  156. result[lightBaseName + "Color"] = {
  157. type: WebGLConstants.FLOAT_VEC3,
  158. value: point.color,
  159. };
  160. if (defined(light.node)) {
  161. result[lightBaseName + "Transform"] = {
  162. node: light.node,
  163. semantic: "MODELVIEW",
  164. type: WebGLConstants.FLOAT_MAT4,
  165. };
  166. }
  167. result[lightBaseName + "Attenuation"] = {
  168. type: WebGLConstants.FLOAT_VEC3,
  169. value: [
  170. point.constantAttenuation,
  171. point.linearAttenuation,
  172. point.quadraticAttenuation,
  173. ],
  174. };
  175. break;
  176. case "spot":
  177. var spot = light.spot;
  178. result[lightBaseName + "Color"] = {
  179. type: WebGLConstants.FLOAT_VEC3,
  180. value: spot.color,
  181. };
  182. if (defined(light.node)) {
  183. result[lightBaseName + "Transform"] = {
  184. node: light.node,
  185. semantic: "MODELVIEW",
  186. type: WebGLConstants.FLOAT_MAT4,
  187. };
  188. result[lightBaseName + "InverseTransform"] = {
  189. node: light.node,
  190. semantic: "MODELVIEWINVERSE",
  191. type: WebGLConstants.FLOAT_MAT4,
  192. useInFragment: true,
  193. };
  194. }
  195. result[lightBaseName + "Attenuation"] = {
  196. type: WebGLConstants.FLOAT_VEC3,
  197. value: [
  198. spot.constantAttenuation,
  199. spot.linearAttenuation,
  200. spot.quadraticAttenuation,
  201. ],
  202. };
  203. result[lightBaseName + "FallOff"] = {
  204. type: WebGLConstants.FLOAT_VEC2,
  205. value: [spot.fallOffAngle, spot.fallOffExponent],
  206. };
  207. break;
  208. }
  209. ++lightCount;
  210. }
  211. }
  212. }
  213. return result;
  214. }
  215. function generateTechnique(
  216. gltf,
  217. techniquesWebgl,
  218. primitiveInfo,
  219. khrMaterialsCommon,
  220. lightParameters,
  221. addBatchIdToGeneratedShaders
  222. ) {
  223. if (!defined(khrMaterialsCommon)) {
  224. khrMaterialsCommon = {};
  225. }
  226. addBatchIdToGeneratedShaders = defaultValue(
  227. addBatchIdToGeneratedShaders,
  228. false
  229. );
  230. var techniques = techniquesWebgl.techniques;
  231. var shaders = techniquesWebgl.shaders;
  232. var programs = techniquesWebgl.programs;
  233. var lightingModel = khrMaterialsCommon.technique.toUpperCase();
  234. var lights;
  235. if (
  236. defined(gltf.extensions) &&
  237. defined(gltf.extensions.KHR_materials_common)
  238. ) {
  239. lights = gltf.extensions.KHR_materials_common.lights;
  240. }
  241. var parameterValues = khrMaterialsCommon.values;
  242. var jointCount = defaultValue(khrMaterialsCommon.jointCount, 0);
  243. var skinningInfo;
  244. var hasSkinning = false;
  245. var hasVertexColors = false;
  246. if (defined(primitiveInfo)) {
  247. skinningInfo = primitiveInfo.skinning;
  248. hasSkinning = skinningInfo.skinned;
  249. hasVertexColors = primitiveInfo.hasVertexColors;
  250. }
  251. var vertexShader = "precision highp float;\n";
  252. var fragmentShader = "precision highp float;\n";
  253. var hasNormals = lightingModel !== "CONSTANT";
  254. // Add techniques
  255. var techniqueUniforms = {
  256. u_modelViewMatrix: {
  257. semantic: hasExtension(gltf, "CESIUM_RTC")
  258. ? "CESIUM_RTC_MODELVIEW"
  259. : "MODELVIEW",
  260. type: WebGLConstants.FLOAT_MAT4,
  261. },
  262. u_projectionMatrix: {
  263. semantic: "PROJECTION",
  264. type: WebGLConstants.FLOAT_MAT4,
  265. },
  266. };
  267. if (hasNormals) {
  268. techniqueUniforms.u_normalMatrix = {
  269. semantic: "MODELVIEWINVERSETRANSPOSE",
  270. type: WebGLConstants.FLOAT_MAT3,
  271. };
  272. }
  273. if (hasSkinning) {
  274. techniqueUniforms.u_jointMatrix = {
  275. count: jointCount,
  276. semantic: "JOINTMATRIX",
  277. type: WebGLConstants.FLOAT_MAT4,
  278. };
  279. }
  280. // Add material values
  281. var uniformName;
  282. var hasTexCoords = false;
  283. for (var name in parameterValues) {
  284. //generate shader parameters for KHR_materials_common attributes
  285. //(including a check, because some boolean flags should not be used as shader parameters)
  286. if (
  287. parameterValues.hasOwnProperty(name) &&
  288. name !== "transparent" &&
  289. name !== "doubleSided"
  290. ) {
  291. var uniformType = getKHRMaterialsCommonValueType(
  292. name,
  293. parameterValues[name]
  294. );
  295. uniformName = "u_" + name.toLowerCase();
  296. if (!hasTexCoords && uniformType === WebGLConstants.SAMPLER_2D) {
  297. hasTexCoords = true;
  298. }
  299. techniqueUniforms[uniformName] = {
  300. type: uniformType,
  301. };
  302. }
  303. }
  304. // Give the diffuse uniform a semantic to support color replacement in 3D Tiles
  305. if (defined(techniqueUniforms.u_diffuse)) {
  306. techniqueUniforms.u_diffuse.semantic = "_3DTILESDIFFUSE";
  307. }
  308. // Copy light parameters into technique parameters
  309. if (defined(lightParameters)) {
  310. for (var lightParamName in lightParameters) {
  311. if (lightParameters.hasOwnProperty(lightParamName)) {
  312. uniformName = "u_" + lightParamName;
  313. techniqueUniforms[uniformName] = lightParameters[lightParamName];
  314. }
  315. }
  316. }
  317. // Add uniforms to shaders
  318. for (uniformName in techniqueUniforms) {
  319. if (techniqueUniforms.hasOwnProperty(uniformName)) {
  320. var uniform = techniqueUniforms[uniformName];
  321. var arraySize = defined(uniform.count) ? "[" + uniform.count + "]" : "";
  322. if (
  323. (uniform.type !== WebGLConstants.FLOAT_MAT3 &&
  324. uniform.type !== WebGLConstants.FLOAT_MAT4) ||
  325. uniform.useInFragment
  326. ) {
  327. fragmentShader +=
  328. "uniform " +
  329. webGLConstantToGlslType(uniform.type) +
  330. " " +
  331. uniformName +
  332. arraySize +
  333. ";\n";
  334. delete uniform.useInFragment;
  335. } else {
  336. vertexShader +=
  337. "uniform " +
  338. webGLConstantToGlslType(uniform.type) +
  339. " " +
  340. uniformName +
  341. arraySize +
  342. ";\n";
  343. }
  344. }
  345. }
  346. // Add attributes with semantics
  347. var vertexShaderMain = "";
  348. if (hasSkinning) {
  349. vertexShaderMain +=
  350. " mat4 skinMatrix =\n" +
  351. " a_weight.x * u_jointMatrix[int(a_joint.x)] +\n" +
  352. " a_weight.y * u_jointMatrix[int(a_joint.y)] +\n" +
  353. " a_weight.z * u_jointMatrix[int(a_joint.z)] +\n" +
  354. " a_weight.w * u_jointMatrix[int(a_joint.w)];\n";
  355. }
  356. // Add position always
  357. var techniqueAttributes = {
  358. a_position: {
  359. semantic: "POSITION",
  360. },
  361. };
  362. vertexShader += "attribute vec3 a_position;\n";
  363. vertexShader += "varying vec3 v_positionEC;\n";
  364. if (hasSkinning) {
  365. vertexShaderMain +=
  366. " vec4 pos = u_modelViewMatrix * skinMatrix * vec4(a_position,1.0);\n";
  367. } else {
  368. vertexShaderMain +=
  369. " vec4 pos = u_modelViewMatrix * vec4(a_position,1.0);\n";
  370. }
  371. vertexShaderMain += " v_positionEC = pos.xyz;\n";
  372. vertexShaderMain += " gl_Position = u_projectionMatrix * pos;\n";
  373. fragmentShader += "varying vec3 v_positionEC;\n";
  374. // Add normal if we don't have constant lighting
  375. if (hasNormals) {
  376. techniqueAttributes.a_normal = {
  377. semantic: "NORMAL",
  378. };
  379. vertexShader += "attribute vec3 a_normal;\n";
  380. vertexShader += "varying vec3 v_normal;\n";
  381. if (hasSkinning) {
  382. vertexShaderMain +=
  383. " v_normal = u_normalMatrix * mat3(skinMatrix) * a_normal;\n";
  384. } else {
  385. vertexShaderMain += " v_normal = u_normalMatrix * a_normal;\n";
  386. }
  387. fragmentShader += "varying vec3 v_normal;\n";
  388. }
  389. // Add texture coordinates if the material uses them
  390. var v_texcoord;
  391. if (hasTexCoords) {
  392. techniqueAttributes.a_texcoord_0 = {
  393. semantic: "TEXCOORD_0",
  394. };
  395. v_texcoord = "v_texcoord_0";
  396. vertexShader += "attribute vec2 a_texcoord_0;\n";
  397. vertexShader += "varying vec2 " + v_texcoord + ";\n";
  398. vertexShaderMain += " " + v_texcoord + " = a_texcoord_0;\n";
  399. fragmentShader += "varying vec2 " + v_texcoord + ";\n";
  400. }
  401. if (hasSkinning) {
  402. techniqueAttributes.a_joint = {
  403. semantic: "JOINTS_0",
  404. };
  405. techniqueAttributes.a_weight = {
  406. semantic: "WEIGHTS_0",
  407. };
  408. vertexShader += "attribute vec4 a_joint;\n";
  409. vertexShader += "attribute vec4 a_weight;\n";
  410. }
  411. if (hasVertexColors) {
  412. techniqueAttributes.a_vertexColor = {
  413. semantic: "COLOR_0",
  414. };
  415. vertexShader += "attribute vec4 a_vertexColor;\n";
  416. vertexShader += "varying vec4 v_vertexColor;\n";
  417. vertexShaderMain += " v_vertexColor = a_vertexColor;\n";
  418. fragmentShader += "varying vec4 v_vertexColor;\n";
  419. }
  420. if (addBatchIdToGeneratedShaders) {
  421. techniqueAttributes.a_batchId = {
  422. semantic: "_BATCHID",
  423. };
  424. vertexShader += "attribute float a_batchId;\n";
  425. }
  426. var hasSpecular =
  427. hasNormals &&
  428. (lightingModel === "BLINN" || lightingModel === "PHONG") &&
  429. defined(techniqueUniforms.u_specular) &&
  430. defined(techniqueUniforms.u_shininess) &&
  431. techniqueUniforms.u_shininess > 0.0;
  432. // Generate lighting code blocks
  433. var hasNonAmbientLights = false;
  434. var hasAmbientLights = false;
  435. var fragmentLightingBlock = "";
  436. for (var lightName in lights) {
  437. if (lights.hasOwnProperty(lightName)) {
  438. var light = lights[lightName];
  439. var lightType = light.type.toLowerCase();
  440. var lightBaseName = light.baseName;
  441. fragmentLightingBlock += " {\n";
  442. var lightColorName = "u_" + lightBaseName + "Color";
  443. var varyingDirectionName;
  444. var varyingPositionName;
  445. if (lightType === "ambient") {
  446. hasAmbientLights = true;
  447. fragmentLightingBlock +=
  448. " ambientLight += " + lightColorName + ";\n";
  449. } else if (hasNormals) {
  450. hasNonAmbientLights = true;
  451. varyingDirectionName = "v_" + lightBaseName + "Direction";
  452. varyingPositionName = "v_" + lightBaseName + "Position";
  453. if (lightType !== "point") {
  454. vertexShader += "varying vec3 " + varyingDirectionName + ";\n";
  455. fragmentShader += "varying vec3 " + varyingDirectionName + ";\n";
  456. vertexShaderMain +=
  457. " " +
  458. varyingDirectionName +
  459. " = mat3(u_" +
  460. lightBaseName +
  461. "Transform) * vec3(0.,0.,1.);\n";
  462. if (lightType === "directional") {
  463. fragmentLightingBlock +=
  464. " vec3 l = normalize(" + varyingDirectionName + ");\n";
  465. }
  466. }
  467. if (lightType !== "directional") {
  468. vertexShader += "varying vec3 " + varyingPositionName + ";\n";
  469. fragmentShader += "varying vec3 " + varyingPositionName + ";\n";
  470. vertexShaderMain +=
  471. " " +
  472. varyingPositionName +
  473. " = u_" +
  474. lightBaseName +
  475. "Transform[3].xyz;\n";
  476. fragmentLightingBlock +=
  477. " vec3 VP = " + varyingPositionName + " - v_positionEC;\n";
  478. fragmentLightingBlock += " vec3 l = normalize(VP);\n";
  479. fragmentLightingBlock += " float range = length(VP);\n";
  480. fragmentLightingBlock +=
  481. " float attenuation = 1.0 / (u_" +
  482. lightBaseName +
  483. "Attenuation.x + ";
  484. fragmentLightingBlock +=
  485. "(u_" + lightBaseName + "Attenuation.y * range) + ";
  486. fragmentLightingBlock +=
  487. "(u_" + lightBaseName + "Attenuation.z * range * range));\n";
  488. } else {
  489. fragmentLightingBlock += " float attenuation = 1.0;\n";
  490. }
  491. if (lightType === "spot") {
  492. fragmentLightingBlock +=
  493. " float spotDot = dot(l, normalize(" +
  494. varyingDirectionName +
  495. "));\n";
  496. fragmentLightingBlock +=
  497. " if (spotDot < cos(u_" + lightBaseName + "FallOff.x * 0.5))\n";
  498. fragmentLightingBlock += " {\n";
  499. fragmentLightingBlock += " attenuation = 0.0;\n";
  500. fragmentLightingBlock += " }\n";
  501. fragmentLightingBlock += " else\n";
  502. fragmentLightingBlock += " {\n";
  503. fragmentLightingBlock +=
  504. " attenuation *= max(0.0, pow(spotDot, u_" +
  505. lightBaseName +
  506. "FallOff.y));\n";
  507. fragmentLightingBlock += " }\n";
  508. }
  509. fragmentLightingBlock +=
  510. " diffuseLight += " +
  511. lightColorName +
  512. "* max(dot(normal,l), 0.) * attenuation;\n";
  513. if (hasSpecular) {
  514. if (lightingModel === "BLINN") {
  515. fragmentLightingBlock += " vec3 h = normalize(l + viewDir);\n";
  516. fragmentLightingBlock +=
  517. " float specularIntensity = max(0., pow(max(dot(normal, h), 0.), u_shininess)) * attenuation;\n";
  518. } else {
  519. // PHONG
  520. fragmentLightingBlock +=
  521. " vec3 reflectDir = reflect(-l, normal);\n";
  522. fragmentLightingBlock +=
  523. " float specularIntensity = max(0., pow(max(dot(reflectDir, viewDir), 0.), u_shininess)) * attenuation;\n";
  524. }
  525. fragmentLightingBlock +=
  526. " specularLight += " +
  527. lightColorName +
  528. " * specularIntensity;\n";
  529. }
  530. }
  531. fragmentLightingBlock += " }\n";
  532. }
  533. }
  534. if (!hasAmbientLights) {
  535. // Add an ambient light if we don't have one
  536. fragmentLightingBlock += " ambientLight += vec3(0.2, 0.2, 0.2);\n";
  537. }
  538. if (!hasNonAmbientLights && lightingModel !== "CONSTANT") {
  539. fragmentShader += "#ifdef USE_CUSTOM_LIGHT_COLOR \n";
  540. fragmentShader += "uniform vec3 gltf_lightColor; \n";
  541. fragmentShader += "#endif \n";
  542. fragmentLightingBlock += "#ifndef USE_CUSTOM_LIGHT_COLOR \n";
  543. fragmentLightingBlock += " vec3 lightColor = czm_lightColor;\n";
  544. fragmentLightingBlock += "#else \n";
  545. fragmentLightingBlock += " vec3 lightColor = gltf_lightColor;\n";
  546. fragmentLightingBlock += "#endif \n";
  547. fragmentLightingBlock += " vec3 l = normalize(czm_lightDirectionEC);\n";
  548. var minimumLighting = "0.2"; // Use strings instead of values as 0.0 -> 0 when stringified
  549. fragmentLightingBlock +=
  550. " diffuseLight += lightColor * max(dot(normal,l), " +
  551. minimumLighting +
  552. ");\n";
  553. if (hasSpecular) {
  554. if (lightingModel === "BLINN") {
  555. fragmentLightingBlock += " vec3 h = normalize(l + viewDir);\n";
  556. fragmentLightingBlock +=
  557. " float specularIntensity = max(0., pow(max(dot(normal, h), 0.), u_shininess));\n";
  558. } else {
  559. // PHONG
  560. fragmentLightingBlock += " vec3 reflectDir = reflect(-l, normal);\n";
  561. fragmentLightingBlock +=
  562. " float specularIntensity = max(0., pow(max(dot(reflectDir, viewDir), 0.), u_shininess));\n";
  563. }
  564. fragmentLightingBlock +=
  565. " specularLight += lightColor * specularIntensity;\n";
  566. }
  567. }
  568. vertexShader += "void main(void) {\n";
  569. vertexShader += vertexShaderMain;
  570. vertexShader += "}\n";
  571. fragmentShader += "void main(void) {\n";
  572. var colorCreationBlock = " vec3 color = vec3(0.0, 0.0, 0.0);\n";
  573. if (hasNormals) {
  574. fragmentShader += " vec3 normal = normalize(v_normal);\n";
  575. if (khrMaterialsCommon.doubleSided) {
  576. fragmentShader += " if (czm_backFacing())\n";
  577. fragmentShader += " {\n";
  578. fragmentShader += " normal = -normal;\n";
  579. fragmentShader += " }\n";
  580. }
  581. }
  582. var finalColorComputation;
  583. if (lightingModel !== "CONSTANT") {
  584. if (defined(techniqueUniforms.u_diffuse)) {
  585. if (techniqueUniforms.u_diffuse.type === WebGLConstants.SAMPLER_2D) {
  586. fragmentShader +=
  587. " vec4 diffuse = texture2D(u_diffuse, " + v_texcoord + ");\n";
  588. } else {
  589. fragmentShader += " vec4 diffuse = u_diffuse;\n";
  590. }
  591. fragmentShader += " vec3 diffuseLight = vec3(0.0, 0.0, 0.0);\n";
  592. colorCreationBlock += " color += diffuse.rgb * diffuseLight;\n";
  593. }
  594. if (hasSpecular) {
  595. if (techniqueUniforms.u_specular.type === WebGLConstants.SAMPLER_2D) {
  596. fragmentShader +=
  597. " vec3 specular = texture2D(u_specular, " + v_texcoord + ").rgb;\n";
  598. } else {
  599. fragmentShader += " vec3 specular = u_specular.rgb;\n";
  600. }
  601. fragmentShader += " vec3 specularLight = vec3(0.0, 0.0, 0.0);\n";
  602. colorCreationBlock += " color += specular * specularLight;\n";
  603. }
  604. if (defined(techniqueUniforms.u_transparency)) {
  605. finalColorComputation =
  606. " gl_FragColor = vec4(color * diffuse.a * u_transparency, diffuse.a * u_transparency);\n";
  607. } else {
  608. finalColorComputation =
  609. " gl_FragColor = vec4(color * diffuse.a, diffuse.a);\n";
  610. }
  611. } else if (defined(techniqueUniforms.u_transparency)) {
  612. finalColorComputation =
  613. " gl_FragColor = vec4(color * u_transparency, u_transparency);\n";
  614. } else {
  615. finalColorComputation = " gl_FragColor = vec4(color, 1.0);\n";
  616. }
  617. if (hasVertexColors) {
  618. colorCreationBlock += " color *= v_vertexColor.rgb;\n";
  619. }
  620. if (defined(techniqueUniforms.u_emission)) {
  621. if (techniqueUniforms.u_emission.type === WebGLConstants.SAMPLER_2D) {
  622. fragmentShader +=
  623. " vec3 emission = texture2D(u_emission, " + v_texcoord + ").rgb;\n";
  624. } else {
  625. fragmentShader += " vec3 emission = u_emission.rgb;\n";
  626. }
  627. colorCreationBlock += " color += emission;\n";
  628. }
  629. if (defined(techniqueUniforms.u_ambient) || lightingModel !== "CONSTANT") {
  630. if (defined(techniqueUniforms.u_ambient)) {
  631. if (techniqueUniforms.u_ambient.type === WebGLConstants.SAMPLER_2D) {
  632. fragmentShader +=
  633. " vec3 ambient = texture2D(u_ambient, " + v_texcoord + ").rgb;\n";
  634. } else {
  635. fragmentShader += " vec3 ambient = u_ambient.rgb;\n";
  636. }
  637. } else {
  638. fragmentShader += " vec3 ambient = diffuse.rgb;\n";
  639. }
  640. colorCreationBlock += " color += ambient * ambientLight;\n";
  641. }
  642. fragmentShader += " vec3 viewDir = -normalize(v_positionEC);\n";
  643. fragmentShader += " vec3 ambientLight = vec3(0.0, 0.0, 0.0);\n";
  644. // Add in light computations
  645. fragmentShader += fragmentLightingBlock;
  646. fragmentShader += colorCreationBlock;
  647. fragmentShader += finalColorComputation;
  648. fragmentShader += "}\n";
  649. // Add shaders
  650. var vertexShaderId = addToArray(shaders, {
  651. type: WebGLConstants.VERTEX_SHADER,
  652. extras: {
  653. _pipeline: {
  654. source: vertexShader,
  655. extension: ".glsl",
  656. },
  657. },
  658. });
  659. var fragmentShaderId = addToArray(shaders, {
  660. type: WebGLConstants.FRAGMENT_SHADER,
  661. extras: {
  662. _pipeline: {
  663. source: fragmentShader,
  664. extension: ".glsl",
  665. },
  666. },
  667. });
  668. // Add program
  669. var programId = addToArray(programs, {
  670. fragmentShader: fragmentShaderId,
  671. vertexShader: vertexShaderId,
  672. });
  673. var techniqueId = addToArray(techniques, {
  674. attributes: techniqueAttributes,
  675. program: programId,
  676. uniforms: techniqueUniforms,
  677. });
  678. return techniqueId;
  679. }
  680. function getKHRMaterialsCommonValueType(paramName, paramValue) {
  681. var value;
  682. // Backwards compatibility for COLLADA2GLTF v1.0-draft when it encoding
  683. // materials using KHR_materials_common with explicit type/value members
  684. if (defined(paramValue.value)) {
  685. value = paramValue.value;
  686. } else if (defined(paramValue.index)) {
  687. value = [paramValue.index];
  688. } else {
  689. value = paramValue;
  690. }
  691. switch (paramName) {
  692. case "ambient":
  693. return value.length === 1
  694. ? WebGLConstants.SAMPLER_2D
  695. : WebGLConstants.FLOAT_VEC4;
  696. case "diffuse":
  697. return value.length === 1
  698. ? WebGLConstants.SAMPLER_2D
  699. : WebGLConstants.FLOAT_VEC4;
  700. case "emission":
  701. return value.length === 1
  702. ? WebGLConstants.SAMPLER_2D
  703. : WebGLConstants.FLOAT_VEC4;
  704. case "specular":
  705. return value.length === 1
  706. ? WebGLConstants.SAMPLER_2D
  707. : WebGLConstants.FLOAT_VEC4;
  708. case "shininess":
  709. return WebGLConstants.FLOAT;
  710. case "transparency":
  711. return WebGLConstants.FLOAT;
  712. // these two are usually not used directly within shaders,
  713. // they are just added here for completeness
  714. case "transparent":
  715. return WebGLConstants.BOOL;
  716. case "doubleSided":
  717. return WebGLConstants.BOOL;
  718. }
  719. }
  720. function getTechniqueKey(khrMaterialsCommon, primitiveInfo) {
  721. var techniqueKey = "";
  722. techniqueKey += "technique:" + khrMaterialsCommon.technique + ";";
  723. var values = khrMaterialsCommon.values;
  724. var keys = Object.keys(values).sort();
  725. var keysCount = keys.length;
  726. for (var i = 0; i < keysCount; ++i) {
  727. var name = keys[i];
  728. if (values.hasOwnProperty(name)) {
  729. techniqueKey +=
  730. name + ":" + getKHRMaterialsCommonValueType(name, values[name]);
  731. techniqueKey += ";";
  732. }
  733. }
  734. var jointCount = defaultValue(khrMaterialsCommon.jointCount, 0);
  735. techniqueKey += jointCount.toString() + ";";
  736. if (defined(primitiveInfo)) {
  737. var skinningInfo = primitiveInfo.skinning;
  738. if (jointCount > 0) {
  739. techniqueKey += skinningInfo.type + ";";
  740. }
  741. techniqueKey += primitiveInfo.hasVertexColors;
  742. }
  743. return techniqueKey;
  744. }
  745. function lightDefaults(gltf) {
  746. var khrMaterialsCommon = gltf.extensions.KHR_materials_common;
  747. if (!defined(khrMaterialsCommon) || !defined(khrMaterialsCommon.lights)) {
  748. return;
  749. }
  750. var lights = khrMaterialsCommon.lights;
  751. var lightsLength = lights.length;
  752. for (var lightId = 0; lightId < lightsLength; lightId++) {
  753. var light = lights[lightId];
  754. if (light.type === "ambient") {
  755. if (!defined(light.ambient)) {
  756. light.ambient = {};
  757. }
  758. var ambientLight = light.ambient;
  759. if (!defined(ambientLight.color)) {
  760. ambientLight.color = [1.0, 1.0, 1.0];
  761. }
  762. } else if (light.type === "directional") {
  763. if (!defined(light.directional)) {
  764. light.directional = {};
  765. }
  766. var directionalLight = light.directional;
  767. if (!defined(directionalLight.color)) {
  768. directionalLight.color = [1.0, 1.0, 1.0];
  769. }
  770. } else if (light.type === "point") {
  771. if (!defined(light.point)) {
  772. light.point = {};
  773. }
  774. var pointLight = light.point;
  775. if (!defined(pointLight.color)) {
  776. pointLight.color = [1.0, 1.0, 1.0];
  777. }
  778. pointLight.constantAttenuation = defaultValue(
  779. pointLight.constantAttenuation,
  780. 1.0
  781. );
  782. pointLight.linearAttenuation = defaultValue(
  783. pointLight.linearAttenuation,
  784. 0.0
  785. );
  786. pointLight.quadraticAttenuation = defaultValue(
  787. pointLight.quadraticAttenuation,
  788. 0.0
  789. );
  790. } else if (light.type === "spot") {
  791. if (!defined(light.spot)) {
  792. light.spot = {};
  793. }
  794. var spotLight = light.spot;
  795. if (!defined(spotLight.color)) {
  796. spotLight.color = [1.0, 1.0, 1.0];
  797. }
  798. spotLight.constantAttenuation = defaultValue(
  799. spotLight.constantAttenuation,
  800. 1.0
  801. );
  802. spotLight.fallOffAngle = defaultValue(spotLight.fallOffAngle, 3.14159265);
  803. spotLight.fallOffExponent = defaultValue(spotLight.fallOffExponent, 0.0);
  804. spotLight.linearAttenuation = defaultValue(
  805. spotLight.linearAttenuation,
  806. 0.0
  807. );
  808. spotLight.quadraticAttenuation = defaultValue(
  809. spotLight.quadraticAttenuation,
  810. 0.0
  811. );
  812. }
  813. }
  814. }
  815. export default processModelMaterialsCommon;