babylon.materialHelper.ts 17 KB

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