processPbrMaterials.js 45 KB

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