babylon.materialHelper.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. module BABYLON {
  2. export class MaterialHelper {
  3. public static PrepareDefinesForAttributes(mesh: AbstractMesh, defines: MaterialDefines, useInstances: boolean): void {
  4. if (!defines._areAttributesDirty) {
  5. return;
  6. }
  7. defines["NORMAL"] = (defines._needNormals && mesh.isVerticesDataPresent(VertexBuffer.NormalKind));
  8. if (defines._needUVs) {
  9. defines["UV1"] = mesh.isVerticesDataPresent(VertexBuffer.UVKind);
  10. defines["UV2"] = mesh.isVerticesDataPresent(VertexBuffer.UV2Kind);
  11. } else {
  12. defines["UV1"] = false;
  13. defines["UV2"] = false;
  14. }
  15. defines["VERTEXCOLOR"] = mesh.useVertexColors && mesh.isVerticesDataPresent(VertexBuffer.ColorKind);
  16. defines["VERTEXALPHA"] = mesh.hasVertexAlpha;
  17. if (mesh.useBones && mesh.computeBonesUsingShaders) {
  18. defines["NUM_BONE_INFLUENCERS"] = mesh.numBoneInfluencers;
  19. defines["BonesPerMesh"] = (mesh.skeleton.bones.length + 1);
  20. } else {
  21. defines["NUM_BONE_INFLUENCERS"] = 0;
  22. defines["BonesPerMesh"] = 0;
  23. }
  24. }
  25. public static PrepareDefinesForLights(scene: Scene, mesh: AbstractMesh, defines: MaterialDefines, specularSupported: boolean, maxSimultaneousLights = 4, disableLighting = false): boolean {
  26. if (!defines._areLightsDirty) {
  27. return defines._needNormals;
  28. }
  29. var lightIndex = 0;
  30. var needNormals = false;
  31. var needRebuild = false;
  32. var lightmapMode = false;
  33. var shadowEnabled = false;
  34. var specularEnabled = false;
  35. if (scene.lightsEnabled && !disableLighting) {
  36. for (var light of mesh._lightSources) {
  37. needNormals = true;
  38. if (defines["LIGHT" + lightIndex] === undefined) {
  39. needRebuild = true;
  40. }
  41. defines["LIGHT" + lightIndex] = true;
  42. defines["SPOTLIGHT" + lightIndex] = false;
  43. defines["HEMILIGHT" + lightIndex] = false;
  44. defines["POINTLIGHT" + lightIndex] = false;
  45. defines["DIRLIGHT" + lightIndex] = false;
  46. var type;
  47. if (light instanceof SpotLight) {
  48. type = "SPOTLIGHT" + lightIndex;
  49. } else if (light instanceof HemisphericLight) {
  50. type = "HEMILIGHT" + lightIndex;
  51. } else if (light instanceof PointLight) {
  52. type = "POINTLIGHT" + lightIndex;
  53. } else {
  54. type = "DIRLIGHT" + lightIndex;
  55. }
  56. defines[type] = true;
  57. // Specular
  58. if (specularSupported && !light.specular.equalsFloats(0, 0, 0)) {
  59. specularEnabled = true;
  60. }
  61. // Shadows
  62. defines["SHADOW" + lightIndex] = false;
  63. if (scene.shadowsEnabled) {
  64. var shadowGenerator = <ShadowGenerator>light.getShadowGenerator();
  65. if (mesh && mesh.receiveShadows && shadowGenerator) {
  66. defines["SHADOW" + lightIndex] = true;
  67. shadowEnabled = true;
  68. defines["SHADOWPCF" + lightIndex] = false;
  69. defines["SHADOWESM" + lightIndex] = false;
  70. if (shadowGenerator.usePoissonSampling) {
  71. defines["SHADOWPCF" + lightIndex] = true;
  72. }
  73. else if (shadowGenerator.useExponentialShadowMap || shadowGenerator.useBlurExponentialShadowMap) {
  74. defines["SHADOWESM" + lightIndex] = true;
  75. }
  76. }
  77. }
  78. if (light.lightmapMode != Light.LIGHTMAP_DEFAULT ) {
  79. lightmapMode = true;
  80. defines["LIGHTMAPEXCLUDED" + lightIndex] = true;
  81. defines["LIGHTMAPNOSPECULAR" + lightIndex] = (light.lightmapMode == Light.LIGHTMAP_SHADOWSONLY);
  82. } else {
  83. defines["LIGHTMAPEXCLUDED" + lightIndex] = false;
  84. defines["LIGHTMAPNOSPECULAR" + lightIndex] = false;
  85. }
  86. lightIndex++;
  87. if (lightIndex === maxSimultaneousLights)
  88. break;
  89. }
  90. }
  91. defines["SPECULARTERM"] = specularEnabled;
  92. defines["SHADOWS"] = shadowEnabled;
  93. // Resetting all other lights if any
  94. for (var index = lightIndex; index < maxSimultaneousLights; index++) {
  95. if (defines["LIGHT" + index] !== undefined) {
  96. defines["LIGHT" + index] = false;
  97. }
  98. }
  99. let caps = scene.getEngine().getCaps();
  100. if (defines["SHADOWFULLFLOAT"] === undefined) {
  101. needRebuild = true;
  102. }
  103. defines["SHADOWFULLFLOAT"] = (shadowEnabled && caps.textureFloat && caps.textureFloatLinearFiltering && caps.textureFloatRender);
  104. defines["LIGHTMAPEXCLUDED"] = lightmapMode;
  105. if (needRebuild) {
  106. defines.rebuild();
  107. }
  108. return needNormals;
  109. }
  110. public static PrepareUniformsAndSamplersList(uniformsList: string[], samplersList: string[], defines: MaterialDefines, maxSimultaneousLights = 4): void {
  111. for (var lightIndex = 0; lightIndex < maxSimultaneousLights; lightIndex++) {
  112. if (!defines["LIGHT" + lightIndex]) {
  113. break;
  114. }
  115. uniformsList.push(
  116. "vLightData" + lightIndex,
  117. "vLightDiffuse" + lightIndex,
  118. "vLightSpecular" + lightIndex,
  119. "vLightDirection" + lightIndex,
  120. "vLightGround" + lightIndex,
  121. "lightMatrix" + lightIndex,
  122. "shadowsInfo" + lightIndex
  123. );
  124. samplersList.push("shadowSampler" + lightIndex);
  125. }
  126. }
  127. public static HandleFallbacksForShadows(defines: MaterialDefines, fallbacks: EffectFallbacks, maxSimultaneousLights = 4): void {
  128. for (var lightIndex = 0; lightIndex < maxSimultaneousLights; lightIndex++) {
  129. if (!defines["LIGHT" + lightIndex]) {
  130. break;
  131. }
  132. if (lightIndex > 0) {
  133. fallbacks.addFallback(lightIndex, "LIGHT" + lightIndex);
  134. }
  135. if (defines["SHADOW" + lightIndex]) {
  136. fallbacks.addFallback(0, "SHADOW" + lightIndex);
  137. }
  138. if (defines["SHADOWPCF" + lightIndex]) {
  139. fallbacks.addFallback(0, "SHADOWPCF" + lightIndex);
  140. }
  141. if (defines["SHADOWESM" + lightIndex]) {
  142. fallbacks.addFallback(0, "SHADOWESM" + lightIndex);
  143. }
  144. }
  145. }
  146. public static PrepareAttributesForBones(attribs: string[], mesh: AbstractMesh, defines: MaterialDefines, fallbacks: EffectFallbacks): void {
  147. if (defines["NUM_BONE_INFLUENCERS"] > 0) {
  148. fallbacks.addCPUSkinningFallback(0, mesh);
  149. attribs.push(VertexBuffer.MatricesIndicesKind);
  150. attribs.push(VertexBuffer.MatricesWeightsKind);
  151. if (defines["NUM_BONE_INFLUENCERS"] > 4) {
  152. attribs.push(VertexBuffer.MatricesIndicesExtraKind);
  153. attribs.push(VertexBuffer.MatricesWeightsExtraKind);
  154. }
  155. }
  156. }
  157. public static PrepareAttributesForInstances(attribs: string[], defines: MaterialDefines): void {
  158. if (defines["INSTANCES"]) {
  159. attribs.push("world0");
  160. attribs.push("world1");
  161. attribs.push("world2");
  162. attribs.push("world3");
  163. }
  164. }
  165. // Bindings
  166. public static BindLightShadow(light: Light, scene: Scene, mesh: AbstractMesh, lightIndex: number, effect: Effect, depthValuesAlreadySet: boolean): boolean {
  167. var shadowGenerator = <ShadowGenerator>light.getShadowGenerator();
  168. if (mesh.receiveShadows && shadowGenerator) {
  169. if (!(<any>light).needCube()) {
  170. effect.setMatrix("lightMatrix" + lightIndex, shadowGenerator.getTransformMatrix());
  171. } else {
  172. if (!depthValuesAlreadySet) {
  173. depthValuesAlreadySet = true;
  174. effect.setFloat2("depthValues", scene.activeCamera.minZ, scene.activeCamera.maxZ);
  175. }
  176. }
  177. effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMapForRendering());
  178. effect.setFloat3("shadowsInfo" + lightIndex, shadowGenerator.getDarkness(), shadowGenerator.blurScale / shadowGenerator.getShadowMap().getSize().width, shadowGenerator.depthScale);
  179. }
  180. return depthValuesAlreadySet;
  181. }
  182. public static BindLightProperties(light: Light, effect: Effect, lightIndex: number): void {
  183. if (light instanceof PointLight) {
  184. // Point Light
  185. light.transferToEffect(effect, "vLightData" + lightIndex);
  186. } else if (light instanceof DirectionalLight) {
  187. // Directional Light
  188. light.transferToEffect(effect, "vLightData" + lightIndex);
  189. } else if (light instanceof SpotLight) {
  190. // Spot Light
  191. light.transferToEffect(effect, "vLightData" + lightIndex, "vLightDirection" + lightIndex);
  192. } else if (light instanceof HemisphericLight) {
  193. // Hemispheric Light
  194. light.transferToEffect(effect, "vLightData" + lightIndex, "vLightGround" + lightIndex);
  195. }
  196. }
  197. public static BindLights(scene: Scene, mesh: AbstractMesh, effect: Effect, defines: MaterialDefines, maxSimultaneousLights = 4) {
  198. var lightIndex = 0;
  199. var depthValuesAlreadySet = false;
  200. for (var light of mesh._lightSources) {
  201. MaterialHelper.BindLightProperties(light, effect, lightIndex);
  202. light.diffuse.scaleToRef(light.intensity, Tmp.Color3[0]);
  203. effect.setColor4("vLightDiffuse" + lightIndex, Tmp.Color3[0], light.range);
  204. if (defines["SPECULARTERM"]) {
  205. light.specular.scaleToRef(light.intensity, Tmp.Color3[1]);
  206. effect.setColor3("vLightSpecular" + lightIndex, Tmp.Color3[1]);
  207. }
  208. // Shadows
  209. if (scene.shadowsEnabled) {
  210. depthValuesAlreadySet = this.BindLightShadow(light, scene, mesh, lightIndex, effect, depthValuesAlreadySet);
  211. }
  212. lightIndex++;
  213. if (lightIndex === maxSimultaneousLights)
  214. break;
  215. }
  216. }
  217. public static BindFogParameters(scene: Scene, mesh: AbstractMesh, effect: Effect): void {
  218. if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
  219. effect.setFloat4("vFogInfos", scene.fogMode, scene.fogStart, scene.fogEnd, scene.fogDensity);
  220. effect.setColor3("vFogColor", scene.fogColor);
  221. }
  222. }
  223. public static BindBonesParameters(mesh: AbstractMesh, effect: Effect): void {
  224. if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
  225. var matrices = mesh.skeleton.getTransformMatrices(mesh);
  226. if (matrices) {
  227. effect.setMatrices("mBones", matrices);
  228. }
  229. }
  230. }
  231. public static BindLogDepth(defines: MaterialDefines, effect: Effect, scene: Scene): void {
  232. if (defines["LOGARITHMICDEPTH"]) {
  233. effect.setFloat("logarithmicDepthConstant", 2.0 / (Math.log(scene.activeCamera.maxZ + 1.0) / Math.LN2));
  234. }
  235. }
  236. public static BindClipPlane(effect: Effect, scene: Scene): void {
  237. if (scene.clipPlane) {
  238. var clipPlane = scene.clipPlane;
  239. effect.setFloat4("vClipPlane", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
  240. }
  241. }
  242. }
  243. }