processModelMaterialsCommon.js 33 KB

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