babylon.materialHelper.ts 14 KB

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