From 9923267c6e44f324dbd229bd67144d7bde95b0c8 Mon Sep 17 00:00:00 2001 From: luaacro Date: Mon, 14 Dec 2015 15:01:21 +0100 Subject: [PATCH 1/7] Materials Library, adding tri-planar mapping material - Each axis can have its own texture (X, Y and Z) or share the same - Provides a Tangent Space calculation example for normal mapping support - Useful for procedural terrain generation (no UV coordinates needed) A good tutorial for more informations : http://gamedevelopment.tutsplus.com/articles/use-tri-planar-texture-mapping-for-better-terrain--gamedev-13821 --- materialsLibrary/config.json | 8 + .../dist/babylon.triPlanarMaterial.js | 509 ++++++++++++ .../dist/babylon.triPlanarMaterial.min.js | 1 + .../dist/dts/babylon.triPlanarMaterial.d.ts | 36 + .../triPlanar/babylon.triPlanarMaterial.ts | 622 +++++++++++++++ .../materials/triPlanar/triplanar.fragment.fx | 724 ++++++++++++++++++ .../materials/triPlanar/triplanar.vertex.fx | 190 +++++ materialsLibrary/test/add/addtriplanar.js | 19 + materialsLibrary/test/index.html | 13 +- 9 files changed, 2119 insertions(+), 3 deletions(-) create mode 100644 materialsLibrary/dist/babylon.triPlanarMaterial.js create mode 100644 materialsLibrary/dist/babylon.triPlanarMaterial.min.js create mode 100644 materialsLibrary/dist/dts/babylon.triPlanarMaterial.d.ts create mode 100644 materialsLibrary/materials/triPlanar/babylon.triPlanarMaterial.ts create mode 100644 materialsLibrary/materials/triPlanar/triplanar.fragment.fx create mode 100644 materialsLibrary/materials/triPlanar/triplanar.vertex.fx create mode 100644 materialsLibrary/test/add/addtriplanar.js diff --git a/materialsLibrary/config.json b/materialsLibrary/config.json index 566c0a167a1..c77525a149f 100644 --- a/materialsLibrary/config.json +++ b/materialsLibrary/config.json @@ -65,6 +65,14 @@ "materials/terrain/terrain.fragment.fx" ], "output": "babylon.terrainMaterial.js" + }, + { + "file": "materials/triPlanar/babylon.triPlanarMaterial.ts", + "shaderFiles": [ + "materials/triPlanar/triplanar.vertex.fx", + "materials/triPlanar/triplanar.fragment.fx" + ], + "output": "babylon.triPlanarMaterial.js" } ], "build": { diff --git a/materialsLibrary/dist/babylon.triPlanarMaterial.js b/materialsLibrary/dist/babylon.triPlanarMaterial.js new file mode 100644 index 00000000000..8837507b17e --- /dev/null +++ b/materialsLibrary/dist/babylon.triPlanarMaterial.js @@ -0,0 +1,509 @@ +/// + +var BABYLON; +(function (BABYLON) { + var maxSimultaneousLights = 4; + var TriPlanarMaterialDefines = (function (_super) { + __extends(TriPlanarMaterialDefines, _super); + function TriPlanarMaterialDefines() { + _super.call(this); + this.DIFFUSEX = false; + this.DIFFUSEY = false; + this.DIFFUSEZ = false; + this.BUMPX = false; + this.BUMPY = false; + this.BUMPZ = false; + this.CLIPPLANE = false; + this.ALPHATEST = false; + this.POINTSIZE = false; + this.FOG = false; + this.LIGHT0 = false; + this.LIGHT1 = false; + this.LIGHT2 = false; + this.LIGHT3 = false; + this.SPOTLIGHT0 = false; + this.SPOTLIGHT1 = false; + this.SPOTLIGHT2 = false; + this.SPOTLIGHT3 = false; + this.HEMILIGHT0 = false; + this.HEMILIGHT1 = false; + this.HEMILIGHT2 = false; + this.HEMILIGHT3 = false; + this.DIRLIGHT0 = false; + this.DIRLIGHT1 = false; + this.DIRLIGHT2 = false; + this.DIRLIGHT3 = false; + this.POINTLIGHT0 = false; + this.POINTLIGHT1 = false; + this.POINTLIGHT2 = false; + this.POINTLIGHT3 = false; + this.SHADOW0 = false; + this.SHADOW1 = false; + this.SHADOW2 = false; + this.SHADOW3 = false; + this.SHADOWS = false; + this.SHADOWVSM0 = false; + this.SHADOWVSM1 = false; + this.SHADOWVSM2 = false; + this.SHADOWVSM3 = false; + this.SHADOWPCF0 = false; + this.SHADOWPCF1 = false; + this.SHADOWPCF2 = false; + this.SHADOWPCF3 = false; + this.SPECULARTERM = false; + this.NORMAL = false; + this.VERTEXCOLOR = false; + this.VERTEXALPHA = false; + this.BONES = false; + this.BONES4 = false; + this.BonesPerMesh = 0; + this.INSTANCES = false; + this._keys = Object.keys(this); + } + return TriPlanarMaterialDefines; + })(BABYLON.MaterialDefines); + var TriPlanarMaterial = (function (_super) { + __extends(TriPlanarMaterial, _super); + function TriPlanarMaterial(name, scene) { + _super.call(this, name, scene); + this.tileSize = 1; + this.diffuseColor = new BABYLON.Color3(1, 1, 1); + this.specularColor = new BABYLON.Color3(0.2, 0.2, 0.2); + this.specularPower = 64; + this.disableLighting = false; + this._worldViewProjectionMatrix = BABYLON.Matrix.Zero(); + this._scaledDiffuse = new BABYLON.Color3(); + this._scaledSpecular = new BABYLON.Color3(); + this._defines = new TriPlanarMaterialDefines(); + this._cachedDefines = new TriPlanarMaterialDefines(); + this._cachedDefines.BonesPerMesh = -1; + } + TriPlanarMaterial.prototype.needAlphaBlending = function () { + return (this.alpha < 1.0); + }; + TriPlanarMaterial.prototype.needAlphaTesting = function () { + return false; + }; + TriPlanarMaterial.prototype.getAlphaTestTexture = function () { + return null; + }; + // Methods + TriPlanarMaterial.prototype._checkCache = function (scene, mesh, useInstances) { + if (!mesh) { + return true; + } + if (this._defines.INSTANCES !== useInstances) { + return false; + } + if (mesh._materialDefines && mesh._materialDefines.isEqual(this._defines)) { + return true; + } + return false; + }; + TriPlanarMaterial.prototype.isReady = function (mesh, useInstances) { + if (this.checkReadyOnlyOnce) { + if (this._wasPreviouslyReady) { + return true; + } + } + var scene = this.getScene(); + if (!this.checkReadyOnEveryCall) { + if (this._renderId === scene.getRenderId()) { + if (this._checkCache(scene, mesh, useInstances)) { + return true; + } + } + } + var engine = scene.getEngine(); + var needNormals = false; + this._defines.reset(); + // Textures + if (scene.texturesEnabled) { + if (BABYLON.StandardMaterial.DiffuseTextureEnabled) { + var textures = [this.diffuseTextureX, this.diffuseTextureY, this.diffuseTextureZ]; + var textureDefines = ["DIFFUSEX", "DIFFUSEY", "DIFFUSEZ"]; + for (var i = 0; i < textures.length; i++) { + if (textures[i]) { + if (!textures[i].isReady()) { + return false; + } + else { + this._defines[textureDefines[i]] = true; + } + } + } + } + if (BABYLON.StandardMaterial.BumpTextureEnabled) { + var textures = [this.normalTextureX, this.normalTextureY, this.normalTextureZ]; + var textureDefines = ["BUMPX", "BUMPY", "BUMPZ"]; + for (var i = 0; i < textures.length; i++) { + if (textures[i]) { + if (!textures[i].isReady()) { + return false; + } + else { + this._defines[textureDefines[i]] = true; + } + } + } + } + } + // Effect + if (scene.clipPlane) { + this._defines.CLIPPLANE = true; + } + if (engine.getAlphaTesting()) { + this._defines.ALPHATEST = true; + } + // Point size + if (this.pointsCloud || scene.forcePointsCloud) { + this._defines.POINTSIZE = true; + } + // Fog + if (scene.fogEnabled && mesh && mesh.applyFog && scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) { + this._defines.FOG = true; + } + var lightIndex = 0; + if (scene.lightsEnabled && !this.disableLighting) { + for (var index = 0; index < scene.lights.length; index++) { + var light = scene.lights[index]; + if (!light.isEnabled()) { + continue; + } + // Excluded check + if (light._excludedMeshesIds.length > 0) { + for (var excludedIndex = 0; excludedIndex < light._excludedMeshesIds.length; excludedIndex++) { + var excludedMesh = scene.getMeshByID(light._excludedMeshesIds[excludedIndex]); + if (excludedMesh) { + light.excludedMeshes.push(excludedMesh); + } + } + light._excludedMeshesIds = []; + } + // Included check + if (light._includedOnlyMeshesIds.length > 0) { + for (var includedOnlyIndex = 0; includedOnlyIndex < light._includedOnlyMeshesIds.length; includedOnlyIndex++) { + var includedOnlyMesh = scene.getMeshByID(light._includedOnlyMeshesIds[includedOnlyIndex]); + if (includedOnlyMesh) { + light.includedOnlyMeshes.push(includedOnlyMesh); + } + } + light._includedOnlyMeshesIds = []; + } + if (!light.canAffectMesh(mesh)) { + continue; + } + needNormals = true; + this._defines["LIGHT" + lightIndex] = true; + var type; + if (light instanceof BABYLON.SpotLight) { + type = "SPOTLIGHT" + lightIndex; + } + else if (light instanceof BABYLON.HemisphericLight) { + type = "HEMILIGHT" + lightIndex; + } + else if (light instanceof BABYLON.PointLight) { + type = "POINTLIGHT" + lightIndex; + } + else { + type = "DIRLIGHT" + lightIndex; + } + this._defines[type] = true; + // Specular + if (!light.specular.equalsFloats(0, 0, 0)) { + this._defines.SPECULARTERM = true; + } + // Shadows + if (scene.shadowsEnabled) { + var shadowGenerator = light.getShadowGenerator(); + if (mesh && mesh.receiveShadows && shadowGenerator) { + this._defines["SHADOW" + lightIndex] = true; + this._defines.SHADOWS = true; + if (shadowGenerator.useVarianceShadowMap || shadowGenerator.useBlurVarianceShadowMap) { + this._defines["SHADOWVSM" + lightIndex] = true; + } + if (shadowGenerator.usePoissonSampling) { + this._defines["SHADOWPCF" + lightIndex] = true; + } + } + } + lightIndex++; + if (lightIndex === maxSimultaneousLights) + break; + } + } + // Attribs + if (mesh) { + if (needNormals && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) { + this._defines.NORMAL = true; + } + if (mesh.useVertexColors && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) { + this._defines.VERTEXCOLOR = true; + if (mesh.hasVertexAlpha) { + this._defines.VERTEXALPHA = true; + } + } + if (mesh.useBones && mesh.computeBonesUsingShaders) { + this._defines.BONES = true; + this._defines.BonesPerMesh = (mesh.skeleton.bones.length + 1); + this._defines.BONES4 = true; + } + // Instances + if (useInstances) { + this._defines.INSTANCES = true; + } + } + // Get correct effect + if (!this._defines.isEqual(this._cachedDefines)) { + this._defines.cloneTo(this._cachedDefines); + scene.resetCachedMaterial(); + // Fallbacks + var fallbacks = new BABYLON.EffectFallbacks(); + if (this._defines.FOG) { + fallbacks.addFallback(1, "FOG"); + } + for (lightIndex = 0; lightIndex < maxSimultaneousLights; lightIndex++) { + if (!this._defines["LIGHT" + lightIndex]) { + continue; + } + if (lightIndex > 0) { + fallbacks.addFallback(lightIndex, "LIGHT" + lightIndex); + } + if (this._defines["SHADOW" + lightIndex]) { + fallbacks.addFallback(0, "SHADOW" + lightIndex); + } + if (this._defines["SHADOWPCF" + lightIndex]) { + fallbacks.addFallback(0, "SHADOWPCF" + lightIndex); + } + if (this._defines["SHADOWVSM" + lightIndex]) { + fallbacks.addFallback(0, "SHADOWVSM" + lightIndex); + } + } + if (this._defines.BONES4) { + fallbacks.addFallback(0, "BONES4"); + } + //Attributes + var attribs = [BABYLON.VertexBuffer.PositionKind]; + if (this._defines.NORMAL) { + attribs.push(BABYLON.VertexBuffer.NormalKind); + } + if (this._defines.VERTEXCOLOR) { + attribs.push(BABYLON.VertexBuffer.ColorKind); + } + if (this._defines.BONES) { + attribs.push(BABYLON.VertexBuffer.MatricesIndicesKind); + attribs.push(BABYLON.VertexBuffer.MatricesWeightsKind); + } + if (this._defines.INSTANCES) { + attribs.push("world0"); + attribs.push("world1"); + attribs.push("world2"); + attribs.push("world3"); + } + // Legacy browser patch + var shaderName = "triplanar"; + var join = this._defines.toString(); + this._effect = scene.getEngine().createEffect(shaderName, attribs, ["world", "view", "viewProjection", "vEyePosition", "vLightsType", "vDiffuseColor", "vSpecularColor", + "vLightData0", "vLightDiffuse0", "vLightSpecular0", "vLightDirection0", "vLightGround0", "lightMatrix0", + "vLightData1", "vLightDiffuse1", "vLightSpecular1", "vLightDirection1", "vLightGround1", "lightMatrix1", + "vLightData2", "vLightDiffuse2", "vLightSpecular2", "vLightDirection2", "vLightGround2", "lightMatrix2", + "vLightData3", "vLightDiffuse3", "vLightSpecular3", "vLightDirection3", "vLightGround3", "lightMatrix3", + "vFogInfos", "vFogColor", "pointSize", + "mBones", + "vClipPlane", + "shadowsInfo0", "shadowsInfo1", "shadowsInfo2", "shadowsInfo3", + "tileSize" + ], ["diffuseSamplerX", "diffuseSamplerY", "diffuseSamplerZ", + "normalSamplerX", "normalSamplerY", "normalSamplerZ", + "shadowSampler0", "shadowSampler1", "shadowSampler2", "shadowSampler3" + ], join, fallbacks, this.onCompiled, this.onError); + } + if (!this._effect.isReady()) { + return false; + } + this._renderId = scene.getRenderId(); + this._wasPreviouslyReady = true; + if (mesh) { + if (!mesh._materialDefines) { + mesh._materialDefines = new TriPlanarMaterialDefines(); + } + this._defines.cloneTo(mesh._materialDefines); + } + return true; + }; + TriPlanarMaterial.prototype.bindOnlyWorldMatrix = function (world) { + this._effect.setMatrix("world", world); + }; + TriPlanarMaterial.prototype.bind = function (world, mesh) { + var scene = this.getScene(); + // Matrices + this.bindOnlyWorldMatrix(world); + this._effect.setMatrix("viewProjection", scene.getTransformMatrix()); + // Bones + if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) { + this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices()); + } + this._effect.setFloat("tileSize", this.tileSize); + if (scene.getCachedMaterial() !== this) { + // Textures + if (this.diffuseTextureX) { + this._effect.setTexture("diffuseSamplerX", this.diffuseTextureX); + } + if (this.diffuseTextureY) { + this._effect.setTexture("diffuseSamplerY", this.diffuseTextureY); + } + if (this.diffuseTextureZ) { + this._effect.setTexture("diffuseSamplerZ", this.diffuseTextureZ); + } + if (this.normalTextureX) { + this._effect.setTexture("normalSamplerX", this.normalTextureX); + } + if (this.normalTextureY) { + this._effect.setTexture("normalSamplerY", this.normalTextureY); + } + if (this.normalTextureZ) { + this._effect.setTexture("normalSamplerZ", this.normalTextureZ); + } + // Clip plane + if (scene.clipPlane) { + var clipPlane = scene.clipPlane; + this._effect.setFloat4("vClipPlane", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d); + } + // Point size + if (this.pointsCloud) { + this._effect.setFloat("pointSize", this.pointSize); + } + this._effect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position); + } + this._effect.setColor4("vDiffuseColor", this._scaledDiffuse, this.alpha * mesh.visibility); + if (this._defines.SPECULARTERM) { + this._effect.setColor4("vSpecularColor", this.specularColor, this.specularPower); + } + if (scene.lightsEnabled && !this.disableLighting) { + var lightIndex = 0; + for (var index = 0; index < scene.lights.length; index++) { + var light = scene.lights[index]; + if (!light.isEnabled()) { + continue; + } + if (!light.canAffectMesh(mesh)) { + continue; + } + if (light instanceof BABYLON.PointLight) { + // Point Light + light.transferToEffect(this._effect, "vLightData" + lightIndex); + } + else if (light instanceof BABYLON.DirectionalLight) { + // Directional Light + light.transferToEffect(this._effect, "vLightData" + lightIndex); + } + else if (light instanceof BABYLON.SpotLight) { + // Spot Light + light.transferToEffect(this._effect, "vLightData" + lightIndex, "vLightDirection" + lightIndex); + } + else if (light instanceof BABYLON.HemisphericLight) { + // Hemispheric Light + light.transferToEffect(this._effect, "vLightData" + lightIndex, "vLightGround" + lightIndex); + } + light.diffuse.scaleToRef(light.intensity, this._scaledDiffuse); + this._effect.setColor4("vLightDiffuse" + lightIndex, this._scaledDiffuse, light.range); + if (this._defines.SPECULARTERM) { + light.specular.scaleToRef(light.intensity, this._scaledSpecular); + this._effect.setColor3("vLightSpecular" + lightIndex, this._scaledSpecular); + } + // Shadows + if (scene.shadowsEnabled) { + var shadowGenerator = light.getShadowGenerator(); + if (mesh.receiveShadows && shadowGenerator) { + this._effect.setMatrix("lightMatrix" + lightIndex, shadowGenerator.getTransformMatrix()); + this._effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMapForRendering()); + this._effect.setFloat3("shadowsInfo" + lightIndex, shadowGenerator.getDarkness(), shadowGenerator.getShadowMap().getSize().width, shadowGenerator.bias); + } + } + lightIndex++; + if (lightIndex === maxSimultaneousLights) + break; + } + } + // View + if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== BABYLON.Scene.FOGMODE_NONE) { + this._effect.setMatrix("view", scene.getViewMatrix()); + } + // Fog + if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== BABYLON.Scene.FOGMODE_NONE) { + this._effect.setFloat4("vFogInfos", scene.fogMode, scene.fogStart, scene.fogEnd, scene.fogDensity); + this._effect.setColor3("vFogColor", scene.fogColor); + } + _super.prototype.bind.call(this, world, mesh); + }; + TriPlanarMaterial.prototype.getAnimatables = function () { + var results = []; + if (this.mixTexture && this.mixTexture.animations && this.mixTexture.animations.length > 0) { + results.push(this.mixTexture); + } + return results; + }; + TriPlanarMaterial.prototype.dispose = function (forceDisposeEffect) { + if (this.mixTexture) { + this.mixTexture.dispose(); + } + _super.prototype.dispose.call(this, forceDisposeEffect); + }; + TriPlanarMaterial.prototype.clone = function (name) { + var newMaterial = new TriPlanarMaterial(name, this.getScene()); + // Base material + this.copyTo(newMaterial); + // Simple material + if (this.mixTexture && this.mixTexture.clone) { + newMaterial.mixTexture = this.mixTexture.clone(); + } + newMaterial.diffuseColor = this.diffuseColor.clone(); + return newMaterial; + }; + TriPlanarMaterial.prototype.serialize = function () { + var serializationObject = _super.prototype.serialize.call(this); + serializationObject.customType = "BABYLON.TerrainMaterial"; + serializationObject.diffuseColor = this.diffuseColor.asArray(); + serializationObject.specularColor = this.specularColor.asArray(); + serializationObject.specularPower = this.specularPower; + serializationObject.disableLighting = this.disableLighting; + if (this.diffuseTextureX) { + serializationObject.diffuseTextureX = this.diffuseTextureX.serialize(); + } + if (this.diffuseTextureY) { + serializationObject.diffuseTextureY = this.diffuseTextureY.serialize(); + } + if (this.diffuseTextureZ) { + serializationObject.diffuseTextureZ = this.diffuseTextureZ.serialize(); + } + return serializationObject; + }; + TriPlanarMaterial.Parse = function (source, scene, rootUrl) { + var material = new TriPlanarMaterial(source.name, scene); + material.diffuseColor = BABYLON.Color3.FromArray(source.diffuseColor); + material.specularColor = BABYLON.Color3.FromArray(source.specularColor); + material.specularPower = source.specularPower; + material.disableLighting = source.disableLighting; + material.alpha = source.alpha; + material.id = source.id; + BABYLON.Tags.AddTagsTo(material, source.tags); + material.backFaceCulling = source.backFaceCulling; + material.wireframe = source.wireframe; + if (source.diffuseTextureX) { + material.diffuseTextureX = BABYLON.Texture.Parse(source.diffuseTextureX, scene, rootUrl); + } + if (source.diffuseTextureY) { + material.diffuseTextureY = BABYLON.Texture.Parse(source.diffuseTextureY, scene, rootUrl); + } + if (source.diffuseTextureZ) { + material.diffuseTextureZ = BABYLON.Texture.Parse(source.diffuseTextureZ, scene, rootUrl); + } + return material; + }; + return TriPlanarMaterial; + })(BABYLON.Material); + BABYLON.TriPlanarMaterial = TriPlanarMaterial; +})(BABYLON || (BABYLON = {})); + +BABYLON.Effect.ShadersStore['triplanarVertexShader'] = "precision highp float;\r\n\r\n// Attributes\r\nattribute vec3 position;\r\n#ifdef NORMAL\r\nattribute vec3 normal;\r\n#endif\r\n#ifdef VERTEXCOLOR\r\nattribute vec4 color;\r\n#endif\r\n#ifdef BONES\r\nattribute vec4 matricesIndices;\r\nattribute vec4 matricesWeights;\r\n#endif\r\n\r\n// Uniforms\r\n\r\n#ifdef INSTANCES\r\nattribute vec4 world0;\r\nattribute vec4 world1;\r\nattribute vec4 world2;\r\nattribute vec4 world3;\r\n#else\r\nuniform mat4 world;\r\n#endif\r\n\r\nuniform mat4 view;\r\nuniform mat4 viewProjection;\r\n\r\n#ifdef DIFFUSEX\r\nvarying vec2 vTextureUVX;\r\n#endif\r\n\r\n#ifdef DIFFUSEY\r\nvarying vec2 vTextureUVY;\r\n#endif\r\n\r\n#ifdef DIFFUSEZ\r\nvarying vec2 vTextureUVZ;\r\n#endif\r\n\r\nuniform float tileSize;\r\n\r\n#ifdef BONES\r\nuniform mat4 mBones[BonesPerMesh];\r\n#endif\r\n\r\n#ifdef POINTSIZE\r\nuniform float pointSize;\r\n#endif\r\n\r\n// Output\r\nvarying vec3 vPositionW;\r\n#ifdef NORMAL\r\nvarying mat3 tangentSpace;\r\n#endif\r\n\r\n#ifdef VERTEXCOLOR\r\nvarying vec4 vColor;\r\n#endif\r\n\r\n#ifdef CLIPPLANE\r\nuniform vec4 vClipPlane;\r\nvarying float fClipDistance;\r\n#endif\r\n\r\n#ifdef FOG\r\nvarying float fFogDistance;\r\n#endif\r\n\r\n#ifdef SHADOWS\r\n#if defined(SPOTLIGHT0) || defined(DIRLIGHT0)\r\nuniform mat4 lightMatrix0;\r\nvarying vec4 vPositionFromLight0;\r\n#endif\r\n#if defined(SPOTLIGHT1) || defined(DIRLIGHT1)\r\nuniform mat4 lightMatrix1;\r\nvarying vec4 vPositionFromLight1;\r\n#endif\r\n#if defined(SPOTLIGHT2) || defined(DIRLIGHT2)\r\nuniform mat4 lightMatrix2;\r\nvarying vec4 vPositionFromLight2;\r\n#endif\r\n#if defined(SPOTLIGHT3) || defined(DIRLIGHT3)\r\nuniform mat4 lightMatrix3;\r\nvarying vec4 vPositionFromLight3;\r\n#endif\r\n#endif\r\n\r\nvoid main(void) {\r\n\tmat4 finalWorld;\r\n\r\n#ifdef INSTANCES\r\n\tfinalWorld = mat4(world0, world1, world2, world3);\r\n#else\r\n\tfinalWorld = world;\r\n#endif\r\n\r\n#ifdef BONES\r\n\tmat4 m0 = mBones[int(matricesIndices.x)] * matricesWeights.x;\r\n\tmat4 m1 = mBones[int(matricesIndices.y)] * matricesWeights.y;\r\n\tmat4 m2 = mBones[int(matricesIndices.z)] * matricesWeights.z;\r\n\r\n#ifdef BONES4\r\n\tmat4 m3 = mBones[int(matricesIndices.w)] * matricesWeights.w;\r\n\tfinalWorld = finalWorld * (m0 + m1 + m2 + m3);\r\n#else\r\n\tfinalWorld = finalWorld * (m0 + m1 + m2);\r\n#endif \r\n\r\n#endif\r\n\tgl_Position = viewProjection * finalWorld * vec4(position, 1.0);\r\n\r\n\tvec4 worldPos = finalWorld * vec4(position, 1.0);\r\n\tvPositionW = vec3(worldPos);\r\n\r\n#ifdef DIFFUSEX\r\n\tvTextureUVX = worldPos.zy / tileSize;\r\n#endif\r\n\r\n#ifdef DIFFUSEY\r\n\tvTextureUVY = worldPos.xz / tileSize;\r\n#endif\r\n\r\n#ifdef DIFFUSEZ\r\n\tvTextureUVZ = worldPos.xy / tileSize;\r\n#endif\r\n\r\n#ifdef NORMAL\r\n\t// Compute tangent space (used for normal mapping + tri planar color mapping)\r\n\tvec3 xtan = vec3(0,0,1);//tangent space for the X aligned plane\r\n \tvec3 xbin = vec3(0,1,0);\r\n \r\n \tvec3 ytan = vec3(1,0,0);//tangent space for the Y aligned plane\r\n \tvec3 ybin = vec3(0,0,1);\r\n \r\n \tvec3 ztan = vec3(1,0,0);//tangent space for the Z aligned plane\r\n \tvec3 zbin = vec3(0,1,0);\r\n\t \r\n\tvec3 normalizedNormal = normalize(normal);\r\n \tnormalizedNormal *= normalizedNormal;\r\n\r\n\tvec3 worldBinormal = normalize(xbin * normalizedNormal.x + ybin * normalizedNormal.y + zbin * normalizedNormal.z);\r\n \tvec3 worldTangent = normalize(xtan * normalizedNormal.x + ytan * normalizedNormal.y + ztan * normalizedNormal.z);\r\n\t \r\n\tworldTangent = (world * vec4(worldTangent, 1.0)).xyz;\r\n worldBinormal = (world * vec4(worldBinormal, 1.0)).xyz;\r\n\tvec3 worldNormal = normalize(cross(worldTangent, worldBinormal));\r\n\r\n\ttangentSpace[0] = worldTangent;\r\n tangentSpace[1] = worldBinormal;\r\n tangentSpace[2] = worldNormal;\r\n#endif\r\n\r\n\t// Clip plane\r\n#ifdef CLIPPLANE\r\n\tfClipDistance = dot(worldPos, vClipPlane);\r\n#endif\r\n\r\n\t// Fog\r\n#ifdef FOG\r\n\tfFogDistance = (view * worldPos).z;\r\n#endif\r\n\r\n\t// Shadows\r\n#ifdef SHADOWS\r\n#if defined(SPOTLIGHT0) || defined(DIRLIGHT0)\r\n\tvPositionFromLight0 = lightMatrix0 * worldPos;\r\n#endif\r\n#if defined(SPOTLIGHT1) || defined(DIRLIGHT1)\r\n\tvPositionFromLight1 = lightMatrix1 * worldPos;\r\n#endif\r\n#if defined(SPOTLIGHT2) || defined(DIRLIGHT2)\r\n\tvPositionFromLight2 = lightMatrix2 * worldPos;\r\n#endif\r\n#if defined(SPOTLIGHT3) || defined(DIRLIGHT3)\r\n\tvPositionFromLight3 = lightMatrix3 * worldPos;\r\n#endif\r\n#endif\r\n\r\n\t// Vertex color\r\n#ifdef VERTEXCOLOR\r\n\tvColor = color;\r\n#endif\r\n\r\n\t// Point size\r\n#ifdef POINTSIZE\r\n\tgl_PointSize = pointSize;\r\n#endif\r\n}\r\n"; +BABYLON.Effect.ShadersStore['triplanarPixelShader'] = "precision highp float;\r\n\r\n// Constants\r\nuniform vec3 vEyePosition;\r\nuniform vec4 vDiffuseColor;\r\n\r\n#ifdef SPECULARTERM\r\nuniform vec4 vSpecularColor;\r\n#endif\r\n\r\n// Input\r\nvarying vec3 vPositionW;\r\n\r\n#ifdef VERTEXCOLOR\r\nvarying vec4 vColor;\r\n#endif\r\n\r\n// Lights\r\n#ifdef LIGHT0\r\nuniform vec4 vLightData0;\r\nuniform vec4 vLightDiffuse0;\r\n#ifdef SPECULARTERM\r\nuniform vec3 vLightSpecular0;\r\n#endif\r\n#ifdef SHADOW0\r\n#if defined(SPOTLIGHT0) || defined(DIRLIGHT0)\r\nvarying vec4 vPositionFromLight0;\r\nuniform sampler2D shadowSampler0;\r\n#else\r\nuniform samplerCube shadowSampler0;\r\n#endif\r\nuniform vec3 shadowsInfo0;\r\n#endif\r\n#ifdef SPOTLIGHT0\r\nuniform vec4 vLightDirection0;\r\n#endif\r\n#ifdef HEMILIGHT0\r\nuniform vec3 vLightGround0;\r\n#endif\r\n#endif\r\n\r\n#ifdef LIGHT1\r\nuniform vec4 vLightData1;\r\nuniform vec4 vLightDiffuse1;\r\n#ifdef SPECULARTERM\r\nuniform vec3 vLightSpecular1;\r\n#endif\r\n#ifdef SHADOW1\r\n#if defined(SPOTLIGHT1) || defined(DIRLIGHT1)\r\nvarying vec4 vPositionFromLight1;\r\nuniform sampler2D shadowSampler1;\r\n#else\r\nuniform samplerCube shadowSampler1;\r\n#endif\r\nuniform vec3 shadowsInfo1;\r\n#endif\r\n#ifdef SPOTLIGHT1\r\nuniform vec4 vLightDirection1;\r\n#endif\r\n#ifdef HEMILIGHT1\r\nuniform vec3 vLightGround1;\r\n#endif\r\n#endif\r\n\r\n#ifdef LIGHT2\r\nuniform vec4 vLightData2;\r\nuniform vec4 vLightDiffuse2;\r\n#ifdef SPECULARTERM\r\nuniform vec3 vLightSpecular2;\r\n#endif\r\n#ifdef SHADOW2\r\n#if defined(SPOTLIGHT2) || defined(DIRLIGHT2)\r\nvarying vec4 vPositionFromLight2;\r\nuniform sampler2D shadowSampler2;\r\n#else\r\nuniform samplerCube shadowSampler2;\r\n#endif\r\nuniform vec3 shadowsInfo2;\r\n#endif\r\n#ifdef SPOTLIGHT2\r\nuniform vec4 vLightDirection2;\r\n#endif\r\n#ifdef HEMILIGHT2\r\nuniform vec3 vLightGround2;\r\n#endif\r\n#endif\r\n\r\n#ifdef LIGHT3\r\nuniform vec4 vLightData3;\r\nuniform vec4 vLightDiffuse3;\r\n#ifdef SPECULARTERM\r\nuniform vec3 vLightSpecular3;\r\n#endif\r\n#ifdef SHADOW3\r\n#if defined(SPOTLIGHT3) || defined(DIRLIGHT3)\r\nvarying vec4 vPositionFromLight3;\r\nuniform sampler2D shadowSampler3;\r\n#else\r\nuniform samplerCube shadowSampler3;\r\n#endif\r\nuniform vec3 shadowsInfo3;\r\n#endif\r\n#ifdef SPOTLIGHT3\r\nuniform vec4 vLightDirection3;\r\n#endif\r\n#ifdef HEMILIGHT3\r\nuniform vec3 vLightGround3;\r\n#endif\r\n#endif\r\n\r\n// Samplers\r\n#ifdef DIFFUSEX\r\nvarying vec2 vTextureUVX;\r\nuniform sampler2D diffuseSamplerX;\r\n#ifdef BUMPX\r\nuniform sampler2D normalSamplerX;\r\n#endif\r\n#endif\r\n\r\n#ifdef DIFFUSEY\r\nvarying vec2 vTextureUVY;\r\nuniform sampler2D diffuseSamplerY;\r\n#ifdef BUMPY\r\nuniform sampler2D normalSamplerY;\r\n#endif\r\n#endif\r\n\r\n#ifdef DIFFUSEZ\r\nvarying vec2 vTextureUVZ;\r\nuniform sampler2D diffuseSamplerZ;\r\n#ifdef BUMPZ\r\nuniform sampler2D normalSamplerZ;\r\n#endif\r\n#endif\r\n\r\n#ifdef NORMAL\r\nvarying mat3 tangentSpace;\r\n#endif\r\n\r\n// Shadows\r\n#ifdef SHADOWS\r\n\r\nfloat unpack(vec4 color)\r\n{\r\n\tconst vec4 bit_shift = vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0);\r\n\treturn dot(color, bit_shift);\r\n}\r\n\r\n#if defined(POINTLIGHT0) || defined(POINTLIGHT1) || defined(POINTLIGHT2) || defined(POINTLIGHT3)\r\nfloat computeShadowCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, float bias)\r\n{\r\n\tvec3 directionToLight = vPositionW - lightPosition;\r\n\tfloat depth = length(directionToLight);\r\n\r\n\tdepth = clamp(depth, 0., 1.);\r\n\r\n\tdirectionToLight.y = 1.0 - directionToLight.y;\r\n\r\n\tfloat shadow = unpack(textureCube(shadowSampler, directionToLight)) + bias;\r\n\r\n\tif (depth > shadow)\r\n\t{\r\n\t\treturn darkness;\r\n\t}\r\n\treturn 1.0;\r\n}\r\n\r\nfloat computeShadowWithPCFCube(vec3 lightPosition, samplerCube shadowSampler, float mapSize, float bias, float darkness)\r\n{\r\n\tvec3 directionToLight = vPositionW - lightPosition;\r\n\tfloat depth = length(directionToLight);\r\n\tfloat diskScale = (1.0 - (1.0 + depth * 3.0)) / mapSize;\r\n\r\n\tdepth = clamp(depth, 0., 1.);\r\n\r\n\tdirectionToLight.y = 1.0 - directionToLight.y;\r\n\r\n\tfloat visibility = 1.;\r\n\r\n\tvec3 poissonDisk[4];\r\n\tpoissonDisk[0] = vec3(-1.0, 1.0, -1.0);\r\n\tpoissonDisk[1] = vec3(1.0, -1.0, -1.0);\r\n\tpoissonDisk[2] = vec3(-1.0, -1.0, -1.0);\r\n\tpoissonDisk[3] = vec3(1.0, -1.0, 1.0);\r\n\r\n\t// Poisson Sampling\r\n\tfloat biasedDepth = depth - bias;\r\n\r\n\tif (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[0] * diskScale)) < biasedDepth) visibility -= 0.25;\r\n\tif (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[1] * diskScale)) < biasedDepth) visibility -= 0.25;\r\n\tif (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[2] * diskScale)) < biasedDepth) visibility -= 0.25;\r\n\tif (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[3] * diskScale)) < biasedDepth) visibility -= 0.25;\r\n\r\n\treturn min(1.0, visibility + darkness);\r\n}\r\n#endif\r\n\r\n#if defined(SPOTLIGHT0) || defined(SPOTLIGHT1) || defined(SPOTLIGHT2) || defined(SPOTLIGHT3) || defined(DIRLIGHT0) || defined(DIRLIGHT1) || defined(DIRLIGHT2) || defined(DIRLIGHT3)\r\nfloat computeShadow(vec4 vPositionFromLight, sampler2D shadowSampler, float darkness, float bias)\r\n{\r\n\tvec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;\r\n\tdepth = 0.5 * depth + vec3(0.5);\r\n\tvec2 uv = depth.xy;\r\n\r\n\tif (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)\r\n\t{\r\n\t\treturn 1.0;\r\n\t}\r\n\r\n\tfloat shadow = unpack(texture2D(shadowSampler, uv)) + bias;\r\n\r\n\tif (depth.z > shadow)\r\n\t{\r\n\t\treturn darkness;\r\n\t}\r\n\treturn 1.;\r\n}\r\n\r\nfloat computeShadowWithPCF(vec4 vPositionFromLight, sampler2D shadowSampler, float mapSize, float bias, float darkness)\r\n{\r\n\tvec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;\r\n\tdepth = 0.5 * depth + vec3(0.5);\r\n\tvec2 uv = depth.xy;\r\n\r\n\tif (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)\r\n\t{\r\n\t\treturn 1.0;\r\n\t}\r\n\r\n\tfloat visibility = 1.;\r\n\r\n\tvec2 poissonDisk[4];\r\n\tpoissonDisk[0] = vec2(-0.94201624, -0.39906216);\r\n\tpoissonDisk[1] = vec2(0.94558609, -0.76890725);\r\n\tpoissonDisk[2] = vec2(-0.094184101, -0.92938870);\r\n\tpoissonDisk[3] = vec2(0.34495938, 0.29387760);\r\n\r\n\t// Poisson Sampling\r\n\tfloat biasedDepth = depth.z - bias;\r\n\r\n\tif (unpack(texture2D(shadowSampler, uv + poissonDisk[0] / mapSize)) < biasedDepth) visibility -= 0.25;\r\n\tif (unpack(texture2D(shadowSampler, uv + poissonDisk[1] / mapSize)) < biasedDepth) visibility -= 0.25;\r\n\tif (unpack(texture2D(shadowSampler, uv + poissonDisk[2] / mapSize)) < biasedDepth) visibility -= 0.25;\r\n\tif (unpack(texture2D(shadowSampler, uv + poissonDisk[3] / mapSize)) < biasedDepth) visibility -= 0.25;\r\n\r\n\treturn min(1.0, visibility + darkness);\r\n}\r\n\r\n// Thanks to http://devmaster.net/\r\nfloat unpackHalf(vec2 color)\r\n{\r\n\treturn color.x + (color.y / 255.0);\r\n}\r\n\r\nfloat linstep(float low, float high, float v) {\r\n\treturn clamp((v - low) / (high - low), 0.0, 1.0);\r\n}\r\n\r\nfloat ChebychevInequality(vec2 moments, float compare, float bias)\r\n{\r\n\tfloat p = smoothstep(compare - bias, compare, moments.x);\r\n\tfloat variance = max(moments.y - moments.x * moments.x, 0.02);\r\n\tfloat d = compare - moments.x;\r\n\tfloat p_max = linstep(0.2, 1.0, variance / (variance + d * d));\r\n\r\n\treturn clamp(max(p, p_max), 0.0, 1.0);\r\n}\r\n\r\nfloat computeShadowWithVSM(vec4 vPositionFromLight, sampler2D shadowSampler, float bias, float darkness)\r\n{\r\n\tvec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;\r\n\tdepth = 0.5 * depth + vec3(0.5);\r\n\tvec2 uv = depth.xy;\r\n\r\n\tif (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0 || depth.z >= 1.0)\r\n\t{\r\n\t\treturn 1.0;\r\n\t}\r\n\r\n\tvec4 texel = texture2D(shadowSampler, uv);\r\n\r\n\tvec2 moments = vec2(unpackHalf(texel.xy), unpackHalf(texel.zw));\r\n\treturn min(1.0, 1.0 - ChebychevInequality(moments, depth.z, bias) + darkness);\r\n}\r\n#endif\r\n#endif\r\n\r\n\r\n#ifdef CLIPPLANE\r\nvarying float fClipDistance;\r\n#endif\r\n\r\n// Fog\r\n#ifdef FOG\r\n\r\n#define FOGMODE_NONE 0.\r\n#define FOGMODE_EXP 1.\r\n#define FOGMODE_EXP2 2.\r\n#define FOGMODE_LINEAR 3.\r\n#define E 2.71828\r\n\r\nuniform vec4 vFogInfos;\r\nuniform vec3 vFogColor;\r\nvarying float fFogDistance;\r\n\r\nfloat CalcFogFactor()\r\n{\r\n\tfloat fogCoeff = 1.0;\r\n\tfloat fogStart = vFogInfos.y;\r\n\tfloat fogEnd = vFogInfos.z;\r\n\tfloat fogDensity = vFogInfos.w;\r\n\r\n\tif (FOGMODE_LINEAR == vFogInfos.x)\r\n\t{\r\n\t\tfogCoeff = (fogEnd - fFogDistance) / (fogEnd - fogStart);\r\n\t}\r\n\telse if (FOGMODE_EXP == vFogInfos.x)\r\n\t{\r\n\t\tfogCoeff = 1.0 / pow(E, fFogDistance * fogDensity);\r\n\t}\r\n\telse if (FOGMODE_EXP2 == vFogInfos.x)\r\n\t{\r\n\t\tfogCoeff = 1.0 / pow(E, fFogDistance * fFogDistance * fogDensity * fogDensity);\r\n\t}\r\n\r\n\treturn clamp(fogCoeff, 0.0, 1.0);\r\n}\r\n#endif\r\n\r\n// Bump\r\n#ifdef BUMP\r\n#extension GL_OES_standard_derivatives : enable\r\n// Thanks to http://www.thetenthplanet.de/archives/1180\r\nmat3 cotangent_frame(vec3 normal, vec3 p, vec2 uv)\r\n{\r\n\t// get edge vectors of the pixel triangle\r\n\tvec3 dp1 = dFdx(p);\r\n\tvec3 dp2 = dFdy(p);\r\n\tvec2 duv1 = dFdx(uv);\r\n\tvec2 duv2 = dFdy(uv);\r\n\r\n\t// solve the linear system\r\n\tvec3 dp2perp = cross(dp2, normal);\r\n\tvec3 dp1perp = cross(normal, dp1);\r\n\tvec3 tangent = dp2perp * duv1.x + dp1perp * duv2.x;\r\n\tvec3 binormal = dp2perp * duv1.y + dp1perp * duv2.y;\r\n\r\n\t// construct a scale-invariant frame \r\n\tfloat invmax = inversesqrt(max(dot(tangent, tangent), dot(binormal, binormal)));\r\n\treturn mat3(tangent * invmax, binormal * invmax, normal);\r\n}\r\n\r\nvec3 perturbNormal(vec3 viewDir, vec3 mixColor)\r\n{\t\r\n\tvec3 bump1Color = texture2D(bump1Sampler, vTextureUV * diffuse1Infos).xyz;\r\n\tvec3 bump2Color = texture2D(bump2Sampler, vTextureUV * diffuse2Infos).xyz;\r\n\tvec3 bump3Color = texture2D(bump3Sampler, vTextureUV * diffuse3Infos).xyz;\r\n\t\r\n\tbump1Color.rgb *= mixColor.r;\r\n \tbump2Color.rgb = mix(bump1Color.rgb, bump2Color.rgb, mixColor.g);\r\n \tvec3 map = mix(bump2Color.rgb, bump3Color.rgb, mixColor.b);\r\n\t\r\n\tmap = map * 255. / 127. - 128. / 127.;\r\n\tmat3 TBN = cotangent_frame(vNormalW * vTextureInfos.y, -viewDir, vTextureUV);\r\n\treturn normalize(TBN * map);\r\n}\r\n#endif\r\n\r\n// Light Computing\r\nstruct lightingInfo\r\n{\r\n\tvec3 diffuse;\r\n#ifdef SPECULARTERM\r\n\tvec3 specular;\r\n#endif\r\n};\r\n\r\nlightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, float range, float glossiness) {\r\n\tlightingInfo result;\r\n\r\n\tvec3 lightVectorW;\r\n\tfloat attenuation = 1.0;\r\n\tif (lightData.w == 0.)\r\n\t{\r\n\t\tvec3 direction = lightData.xyz - vPositionW;\r\n\r\n\t\tattenuation = max(0., 1.0 - length(direction) / range);\r\n\t\tlightVectorW = normalize(direction);\r\n\t}\r\n\telse\r\n\t{\r\n\t\tlightVectorW = normalize(-lightData.xyz);\r\n\t}\r\n\r\n\t// diffuse\r\n\tfloat ndl = max(0., dot(vNormal, lightVectorW));\r\n\tresult.diffuse = ndl * diffuseColor * attenuation;\r\n\r\n#ifdef SPECULARTERM\r\n\t// Specular\r\n\tvec3 angleW = normalize(viewDirectionW + lightVectorW);\r\n\tfloat specComp = max(0., dot(vNormal, angleW));\r\n\tspecComp = pow(specComp, max(1., glossiness));\r\n\r\n\tresult.specular = specComp * specularColor * attenuation;\r\n#endif\r\n\treturn result;\r\n}\r\n\r\nlightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor, float range, float glossiness) {\r\n\tlightingInfo result;\r\n\r\n\tvec3 direction = lightData.xyz - vPositionW;\r\n\tvec3 lightVectorW = normalize(direction);\r\n\tfloat attenuation = max(0., 1.0 - length(direction) / range);\r\n\r\n\t// diffuse\r\n\tfloat cosAngle = max(0., dot(-lightDirection.xyz, lightVectorW));\r\n\tfloat spotAtten = 0.0;\r\n\r\n\tif (cosAngle >= lightDirection.w)\r\n\t{\r\n\t\tcosAngle = max(0., pow(cosAngle, lightData.w));\r\n\t\tspotAtten = clamp((cosAngle - lightDirection.w) / (1. - cosAngle), 0.0, 1.0);\r\n\r\n\t\t// Diffuse\r\n\t\tfloat ndl = max(0., dot(vNormal, -lightDirection.xyz));\r\n\t\tresult.diffuse = ndl * spotAtten * diffuseColor * attenuation;\r\n\r\n#ifdef SPECULARTERM\r\n\t\t// Specular\r\n\t\tvec3 angleW = normalize(viewDirectionW - lightDirection.xyz);\r\n\t\tfloat specComp = max(0., dot(vNormal, angleW));\r\n\t\tspecComp = pow(specComp, max(1., glossiness));\r\n\r\n\t\tresult.specular = specComp * specularColor * spotAtten * attenuation;\r\n#endif\r\n\r\n\t\treturn result;\r\n\t}\r\n\r\n\tresult.diffuse = vec3(0.);\r\n#ifdef SPECULARTERM\r\n\tresult.specular = vec3(0.);\r\n#endif\r\n\r\n\treturn result;\r\n}\r\n\r\nlightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, vec3 groundColor, float glossiness) {\r\n\tlightingInfo result;\r\n\r\n\t// Diffuse\r\n\tfloat ndl = dot(vNormal, lightData.xyz) * 0.5 + 0.5;\r\n\tresult.diffuse = mix(groundColor, diffuseColor, ndl);\r\n\r\n#ifdef SPECULARTERM\r\n\t// Specular\r\n\tvec3 angleW = normalize(viewDirectionW + lightData.xyz);\r\n\tfloat specComp = max(0., dot(vNormal, angleW));\r\n\tspecComp = pow(specComp, max(1., glossiness));\r\n\r\n\tresult.specular = specComp * specularColor;\r\n#endif\r\n\r\n\treturn result;\r\n}\r\n\r\nvoid main(void) {\r\n\t// Clip plane\r\n#ifdef CLIPPLANE\r\n\tif (fClipDistance > 0.0)\r\n\t\tdiscard;\r\n#endif\r\n\r\n\tvec3 viewDirectionW = normalize(vEyePosition - vPositionW);\r\n\r\n\t// Base color\r\n\tvec4 baseColor = vec4(0., 0., 0., 1.);\r\n\tvec3 diffuseColor = vDiffuseColor.rgb;\r\n\t\r\n#ifdef SPECULARTERM\r\n\tfloat glossiness = vSpecularColor.a;\r\n\tvec3 specularColor = vSpecularColor.rgb;\r\n#else\r\n\tfloat glossiness = 0.;\r\n#endif\r\n\r\n\t// Alpha\r\n\tfloat alpha = vDiffuseColor.a;\r\n\t\r\n\t// Bump\r\n#ifdef NORMAL\r\n\tvec3 normalW = tangentSpace[2];\r\n#else\r\n\tvec3 normalW = vec3(1.0, 1.0, 1.0);\r\n#endif\r\n\r\n\tvec4 baseNormal = vec4(0.0, 0.0, 0.0, 1.0);\r\n\tnormalW *= normalW;\r\n\r\n#ifdef DIFFUSEX\r\n\tbaseColor += texture2D(diffuseSamplerX, vTextureUVX) * normalW.x;\r\n#ifdef BUMPX\r\n\tbaseNormal += texture2D(normalSamplerX, vTextureUVX) * normalW.x;\r\n#endif\r\n#endif\r\n\r\n#ifdef DIFFUSEY\r\n\tbaseColor += texture2D(diffuseSamplerY, vTextureUVY) * normalW.y;\r\n#ifdef BUMPY\r\n\tbaseNormal += texture2D(normalSamplerY, vTextureUVY) * normalW.y;\r\n#endif\r\n#endif\r\n\r\n#ifdef DIFFUSEZ\r\n\tbaseColor += texture2D(diffuseSamplerZ, vTextureUVZ) * normalW.z;\r\n#ifdef BUMPZ\r\n\tbaseNormal += texture2D(normalSamplerZ, vTextureUVZ) * normalW.z;\r\n#endif\r\n#endif\r\n\r\n#ifdef NORMAL\r\n\tnormalW = normalize((2.0 * baseNormal.xyz - 1.0) * tangentSpace);\r\n#endif\r\n\r\n#ifdef ALPHATEST\r\n\tif (baseColor.a < 0.4)\r\n\t\tdiscard;\r\n#endif\r\n\r\n#ifdef VERTEXCOLOR\r\n\tbaseColor.rgb *= vColor.rgb;\r\n#endif\r\n\r\n\t// Lighting\r\n\tvec3 diffuseBase = vec3(0., 0., 0.);\r\n#ifdef SPECULARTERM\r\n\tvec3 specularBase = vec3(0., 0., 0.);\r\n#endif\r\n\tfloat shadow = 1.;\r\n\r\n#ifdef LIGHT0\r\n#ifndef SPECULARTERM\r\n\tvec3 vLightSpecular0 = vec3(0.0);\r\n#endif\r\n#ifdef SPOTLIGHT0\r\n\tlightingInfo info = computeSpotLighting(viewDirectionW, normalW, vLightData0, vLightDirection0, vLightDiffuse0.rgb, vLightSpecular0, vLightDiffuse0.a, glossiness);\r\n#endif\r\n#ifdef HEMILIGHT0\r\n\tlightingInfo info = computeHemisphericLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0.rgb, vLightSpecular0, vLightGround0, glossiness);\r\n#endif\r\n#if defined(POINTLIGHT0) || defined(DIRLIGHT0)\r\n\tlightingInfo info = computeLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0.rgb, vLightSpecular0, vLightDiffuse0.a, glossiness);\r\n#endif\r\n#ifdef SHADOW0\r\n#ifdef SHADOWVSM0\r\n\tshadow = computeShadowWithVSM(vPositionFromLight0, shadowSampler0, shadowsInfo0.z, shadowsInfo0.x);\r\n#else\r\n#ifdef SHADOWPCF0\r\n#if defined(POINTLIGHT0)\r\n\tshadow = computeShadowWithPCFCube(vLightData0.xyz, shadowSampler0, shadowsInfo0.y, shadowsInfo0.z, shadowsInfo0.x);\r\n#else\r\n\tshadow = computeShadowWithPCF(vPositionFromLight0, shadowSampler0, shadowsInfo0.y, shadowsInfo0.z, shadowsInfo0.x);\r\n#endif\r\n#else\r\n#if defined(POINTLIGHT0)\r\n\tshadow = computeShadowCube(vLightData0.xyz, shadowSampler0, shadowsInfo0.x, shadowsInfo0.z);\r\n#else\r\n\tshadow = computeShadow(vPositionFromLight0, shadowSampler0, shadowsInfo0.x, shadowsInfo0.z);\r\n#endif\r\n#endif\r\n#endif\r\n#else\r\n\tshadow = 1.;\r\n#endif\r\n\tdiffuseBase += info.diffuse * shadow;\r\n#ifdef SPECULARTERM\r\n\tspecularBase += info.specular * shadow;\r\n#endif\r\n#endif\r\n\r\n#ifdef LIGHT1\r\n#ifndef SPECULARTERM\r\n\tvec3 vLightSpecular1 = vec3(0.0);\r\n#endif\r\n#ifdef SPOTLIGHT1\r\n\tinfo = computeSpotLighting(viewDirectionW, normalW, vLightData1, vLightDirection1, vLightDiffuse1.rgb, vLightSpecular1, vLightDiffuse1.a, glossiness);\r\n#endif\r\n#ifdef HEMILIGHT1\r\n\tinfo = computeHemisphericLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1.rgb, vLightSpecular1, vLightGround1, glossiness);\r\n#endif\r\n#if defined(POINTLIGHT1) || defined(DIRLIGHT1)\r\n\tinfo = computeLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1.rgb, vLightSpecular1, vLightDiffuse1.a, glossiness);\r\n#endif\r\n#ifdef SHADOW1\r\n#ifdef SHADOWVSM1\r\n\tshadow = computeShadowWithVSM(vPositionFromLight1, shadowSampler1, shadowsInfo1.z, shadowsInfo1.x);\r\n#else\r\n#ifdef SHADOWPCF1\r\n#if defined(POINTLIGHT1)\r\n\tshadow = computeShadowWithPCFCube(vLightData1.xyz, shadowSampler1, shadowsInfo1.y, shadowsInfo1.z, shadowsInfo1.x);\r\n#else\r\n\tshadow = computeShadowWithPCF(vPositionFromLight1, shadowSampler1, shadowsInfo1.y, shadowsInfo1.z, shadowsInfo1.x);\r\n#endif\r\n#else\r\n#if defined(POINTLIGHT1)\r\n\tshadow = computeShadowCube(vLightData1.xyz, shadowSampler1, shadowsInfo1.x, shadowsInfo1.z);\r\n#else\r\n\tshadow = computeShadow(vPositionFromLight1, shadowSampler1, shadowsInfo1.x, shadowsInfo1.z);\r\n#endif\r\n#endif\r\n#endif\r\n#else\r\n\tshadow = 1.;\r\n#endif\r\n\tdiffuseBase += info.diffuse * shadow;\r\n#ifdef SPECULARTERM\r\n\tspecularBase += info.specular * shadow;\r\n#endif\r\n#endif\r\n\r\n#ifdef LIGHT2\r\n#ifndef SPECULARTERM\r\n\tvec3 vLightSpecular2 = vec3(0.0);\r\n#endif\r\n#ifdef SPOTLIGHT2\r\n\tinfo = computeSpotLighting(viewDirectionW, normalW, vLightData2, vLightDirection2, vLightDiffuse2.rgb, vLightSpecular2, vLightDiffuse2.a, glossiness);\r\n#endif\r\n#ifdef HEMILIGHT2\r\n\tinfo = computeHemisphericLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2.rgb, vLightSpecular2, vLightGround2, glossiness);\r\n#endif\r\n#if defined(POINTLIGHT2) || defined(DIRLIGHT2)\r\n\tinfo = computeLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2.rgb, vLightSpecular2, vLightDiffuse2.a, glossiness);\r\n#endif\r\n#ifdef SHADOW2\r\n#ifdef SHADOWVSM2\r\n\tshadow = computeShadowWithVSM(vPositionFromLight2, shadowSampler2, shadowsInfo2.z, shadowsInfo2.x);\r\n#else\r\n#ifdef SHADOWPCF2\r\n#if defined(POINTLIGHT2)\r\n\tshadow = computeShadowWithPCFCube(vLightData2.xyz, shadowSampler2, shadowsInfo2.y, shadowsInfo2.z, shadowsInfo2.x);\r\n#else\r\n\tshadow = computeShadowWithPCF(vPositionFromLight2, shadowSampler2, shadowsInfo2.y, shadowsInfo2.z, shadowsInfo2.x);\r\n#endif\r\n#else\r\n#if defined(POINTLIGHT2)\r\n\tshadow = computeShadowCube(vLightData2.xyz, shadowSampler2, shadowsInfo2.x, shadowsInfo2.z);\r\n#else\r\n\tshadow = computeShadow(vPositionFromLight2, shadowSampler2, shadowsInfo2.x, shadowsInfo2.z);\r\n#endif\r\n#endif\t\r\n#endif\t\r\n#else\r\n\tshadow = 1.;\r\n#endif\r\n\tdiffuseBase += info.diffuse * shadow;\r\n#ifdef SPECULARTERM\r\n\tspecularBase += info.specular * shadow;\r\n#endif\r\n#endif\r\n\r\n#ifdef LIGHT3\r\n#ifndef SPECULARTERM\r\n\tvec3 vLightSpecular3 = vec3(0.0);\r\n#endif\r\n#ifdef SPOTLIGHT3\r\n\tinfo = computeSpotLighting(viewDirectionW, normalW, vLightData3, vLightDirection3, vLightDiffuse3.rgb, vLightSpecular3, vLightDiffuse3.a, glossiness);\r\n#endif\r\n#ifdef HEMILIGHT3\r\n\tinfo = computeHemisphericLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3.rgb, vLightSpecular3, vLightGround3, glossiness);\r\n#endif\r\n#if defined(POINTLIGHT3) || defined(DIRLIGHT3)\r\n\tinfo = computeLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3.rgb, vLightSpecular3, vLightDiffuse3.a, glossiness);\r\n#endif\r\n#ifdef SHADOW3\r\n#ifdef SHADOWVSM3\r\n\tshadow = computeShadowWithVSM(vPositionFromLight3, shadowSampler3, shadowsInfo3.z, shadowsInfo3.x);\r\n#else\r\n#ifdef SHADOWPCF3\r\n#if defined(POINTLIGHT3)\r\n\tshadow = computeShadowWithPCFCube(vLightData3.xyz, shadowSampler3, shadowsInfo3.y, shadowsInfo3.z, shadowsInfo3.x);\r\n#else\r\n\tshadow = computeShadowWithPCF(vPositionFromLight3, shadowSampler3, shadowsInfo3.y, shadowsInfo3.z, shadowsInfo3.x);\r\n#endif\r\n#else\r\n#if defined(POINTLIGHT3)\r\n\tshadow = computeShadowCube(vLightData3.xyz, shadowSampler3, shadowsInfo3.x, shadowsInfo3.z);\r\n#else\r\n\tshadow = computeShadow(vPositionFromLight3, shadowSampler3, shadowsInfo3.x, shadowsInfo3.z);\r\n#endif\r\n#endif\t\r\n#endif\t\r\n#else\r\n\tshadow = 1.;\r\n#endif\r\n\tdiffuseBase += info.diffuse * shadow;\r\n#ifdef SPECULARTERM\r\n\tspecularBase += info.specular * shadow;\r\n#endif\r\n#endif\r\n\r\n#ifdef VERTEXALPHA\r\n\talpha *= vColor.a;\r\n#endif\r\n\r\n#ifdef SPECULARTERM\r\n\tvec3 finalSpecular = specularBase * specularColor;\r\n#else\r\n\tvec3 finalSpecular = vec3(0.0);\r\n#endif\r\n\r\n\tvec3 finalDiffuse = clamp(diffuseBase * diffuseColor, 0.0, 1.0) * baseColor.rgb;\r\n\r\n\t// Composition\r\n\tvec4 color = vec4(finalDiffuse + finalSpecular, alpha);\r\n\r\n#ifdef FOG\r\n\tfloat fog = CalcFogFactor();\r\n\tcolor.rgb = fog * color.rgb + (1.0 - fog) * vFogColor;\r\n#endif\r\n\r\n\tgl_FragColor = color;\r\n}\r\n"; diff --git a/materialsLibrary/dist/babylon.triPlanarMaterial.min.js b/materialsLibrary/dist/babylon.triPlanarMaterial.min.js new file mode 100644 index 00000000000..ad910b6f0bf --- /dev/null +++ b/materialsLibrary/dist/babylon.triPlanarMaterial.min.js @@ -0,0 +1 @@ +var BABYLON;!function(e){var n=4,r=function(e){function n(){e.call(this),this.DIFFUSEX=!1,this.DIFFUSEY=!1,this.DIFFUSEZ=!1,this.BUMPX=!1,this.BUMPY=!1,this.BUMPZ=!1,this.CLIPPLANE=!1,this.ALPHATEST=!1,this.POINTSIZE=!1,this.FOG=!1,this.LIGHT0=!1,this.LIGHT1=!1,this.LIGHT2=!1,this.LIGHT3=!1,this.SPOTLIGHT0=!1,this.SPOTLIGHT1=!1,this.SPOTLIGHT2=!1,this.SPOTLIGHT3=!1,this.HEMILIGHT0=!1,this.HEMILIGHT1=!1,this.HEMILIGHT2=!1,this.HEMILIGHT3=!1,this.DIRLIGHT0=!1,this.DIRLIGHT1=!1,this.DIRLIGHT2=!1,this.DIRLIGHT3=!1,this.POINTLIGHT0=!1,this.POINTLIGHT1=!1,this.POINTLIGHT2=!1,this.POINTLIGHT3=!1,this.SHADOW0=!1,this.SHADOW1=!1,this.SHADOW2=!1,this.SHADOW3=!1,this.SHADOWS=!1,this.SHADOWVSM0=!1,this.SHADOWVSM1=!1,this.SHADOWVSM2=!1,this.SHADOWVSM3=!1,this.SHADOWPCF0=!1,this.SHADOWPCF1=!1,this.SHADOWPCF2=!1,this.SHADOWPCF3=!1,this.SPECULARTERM=!1,this.NORMAL=!1,this.VERTEXCOLOR=!1,this.VERTEXALPHA=!1,this.BONES=!1,this.BONES4=!1,this.BonesPerMesh=0,this.INSTANCES=!1,this._keys=Object.keys(this)}return __extends(n,e),n}(e.MaterialDefines),i=function(i){function t(n,t){i.call(this,n,t),this.tileSize=1,this.diffuseColor=new e.Color3(1,1,1),this.specularColor=new e.Color3(.2,.2,.2),this.specularPower=64,this.disableLighting=!1,this._worldViewProjectionMatrix=e.Matrix.Zero(),this._scaledDiffuse=new e.Color3,this._scaledSpecular=new e.Color3,this._defines=new r,this._cachedDefines=new r,this._cachedDefines.BonesPerMesh=-1}return __extends(t,i),t.prototype.needAlphaBlending=function(){return this.alpha<1},t.prototype.needAlphaTesting=function(){return!1},t.prototype.getAlphaTestTexture=function(){return null},t.prototype._checkCache=function(e,n,r){return n?this._defines.INSTANCES!==r?!1:n._materialDefines&&n._materialDefines.isEqual(this._defines)?!0:!1:!0},t.prototype.isReady=function(i,t){if(this.checkReadyOnlyOnce&&this._wasPreviouslyReady)return!0;var o=this.getScene();if(!this.checkReadyOnEveryCall&&this._renderId===o.getRenderId()&&this._checkCache(o,i,t))return!0;var s=o.getEngine(),a=!1;if(this._defines.reset(),o.texturesEnabled){if(e.StandardMaterial.DiffuseTextureEnabled)for(var f=[this.diffuseTextureX,this.diffuseTextureY,this.diffuseTextureZ],d=["DIFFUSEX","DIFFUSEY","DIFFUSEZ"],l=0;l0){for(var v=0;v0){for(var p=0;ph;h++)this._defines["LIGHT"+h]&&(h>0&&T.addFallback(h,"LIGHT"+h),this._defines["SHADOW"+h]&&T.addFallback(0,"SHADOW"+h),this._defines["SHADOWPCF"+h]&&T.addFallback(0,"SHADOWPCF"+h),this._defines["SHADOWVSM"+h]&&T.addFallback(0,"SHADOWVSM"+h));this._defines.BONES4&&T.addFallback(0,"BONES4");var D=[e.VertexBuffer.PositionKind];this._defines.NORMAL&&D.push(e.VertexBuffer.NormalKind),this._defines.VERTEXCOLOR&&D.push(e.VertexBuffer.ColorKind),this._defines.BONES&&(D.push(e.VertexBuffer.MatricesIndicesKind),D.push(e.VertexBuffer.MatricesWeightsKind)),this._defines.INSTANCES&&(D.push("world0"),D.push("world1"),D.push("world2"),D.push("world3"));var I="triplanar",w=this._defines.toString();this._effect=o.getEngine().createEffect(I,D,["world","view","viewProjection","vEyePosition","vLightsType","vDiffuseColor","vSpecularColor","vLightData0","vLightDiffuse0","vLightSpecular0","vLightDirection0","vLightGround0","lightMatrix0","vLightData1","vLightDiffuse1","vLightSpecular1","vLightDirection1","vLightGround1","lightMatrix1","vLightData2","vLightDiffuse2","vLightSpecular2","vLightDirection2","vLightGround2","lightMatrix2","vLightData3","vLightDiffuse3","vLightSpecular3","vLightDirection3","vLightGround3","lightMatrix3","vFogInfos","vFogColor","pointSize","mBones","vClipPlane","shadowsInfo0","shadowsInfo1","shadowsInfo2","shadowsInfo3","tileSize"],["diffuseSamplerX","diffuseSamplerY","diffuseSamplerZ","normalSamplerX","normalSamplerY","normalSamplerZ","shadowSampler0","shadowSampler1","shadowSampler2","shadowSampler3"],w,T,this.onCompiled,this.onError)}return this._effect.isReady()?(this._renderId=o.getRenderId(),this._wasPreviouslyReady=!0,i&&(i._materialDefines||(i._materialDefines=new r),this._defines.cloneTo(i._materialDefines)),!0):!1},t.prototype.bindOnlyWorldMatrix=function(e){this._effect.setMatrix("world",e)},t.prototype.bind=function(r,t){var o=this.getScene();if(this.bindOnlyWorldMatrix(r),this._effect.setMatrix("viewProjection",o.getTransformMatrix()),t&&t.useBones&&t.computeBonesUsingShaders&&this._effect.setMatrices("mBones",t.skeleton.getTransformMatrices()),this._effect.setFloat("tileSize",this.tileSize),o.getCachedMaterial()!==this){if(this.diffuseTextureX&&this._effect.setTexture("diffuseSamplerX",this.diffuseTextureX),this.diffuseTextureY&&this._effect.setTexture("diffuseSamplerY",this.diffuseTextureY),this.diffuseTextureZ&&this._effect.setTexture("diffuseSamplerZ",this.diffuseTextureZ),this.normalTextureX&&this._effect.setTexture("normalSamplerX",this.normalTextureX),this.normalTextureY&&this._effect.setTexture("normalSamplerY",this.normalTextureY),this.normalTextureZ&&this._effect.setTexture("normalSamplerZ",this.normalTextureZ),o.clipPlane){var s=o.clipPlane;this._effect.setFloat4("vClipPlane",s.normal.x,s.normal.y,s.normal.z,s.d)}this.pointsCloud&&this._effect.setFloat("pointSize",this.pointSize),this._effect.setVector3("vEyePosition",o._mirroredCameraPosition?o._mirroredCameraPosition:o.activeCamera.position)}if(this._effect.setColor4("vDiffuseColor",this._scaledDiffuse,this.alpha*t.visibility),this._defines.SPECULARTERM&&this._effect.setColor4("vSpecularColor",this.specularColor,this.specularPower),o.lightsEnabled&&!this.disableLighting)for(var a=0,f=0;f0&&e.push(this.mixTexture),e},t.prototype.dispose=function(e){this.mixTexture&&this.mixTexture.dispose(),i.prototype.dispose.call(this,e)},t.prototype.clone=function(e){var n=new t(e,this.getScene());return this.copyTo(n),this.mixTexture&&this.mixTexture.clone&&(n.mixTexture=this.mixTexture.clone()),n.diffuseColor=this.diffuseColor.clone(),n},t.prototype.serialize=function(){var e=i.prototype.serialize.call(this);return e.customType="BABYLON.TerrainMaterial",e.diffuseColor=this.diffuseColor.asArray(),e.specularColor=this.specularColor.asArray(),e.specularPower=this.specularPower,e.disableLighting=this.disableLighting,this.diffuseTextureX&&(e.diffuseTextureX=this.diffuseTextureX.serialize()),this.diffuseTextureY&&(e.diffuseTextureY=this.diffuseTextureY.serialize()),this.diffuseTextureZ&&(e.diffuseTextureZ=this.diffuseTextureZ.serialize()),e},t.Parse=function(n,r,i){var o=new t(n.name,r);return o.diffuseColor=e.Color3.FromArray(n.diffuseColor),o.specularColor=e.Color3.FromArray(n.specularColor),o.specularPower=n.specularPower,o.disableLighting=n.disableLighting,o.alpha=n.alpha,o.id=n.id,e.Tags.AddTagsTo(o,n.tags),o.backFaceCulling=n.backFaceCulling,o.wireframe=n.wireframe,n.diffuseTextureX&&(o.diffuseTextureX=e.Texture.Parse(n.diffuseTextureX,r,i)),n.diffuseTextureY&&(o.diffuseTextureY=e.Texture.Parse(n.diffuseTextureY,r,i)),n.diffuseTextureZ&&(o.diffuseTextureZ=e.Texture.Parse(n.diffuseTextureZ,r,i)),o},t}(e.Material);e.TriPlanarMaterial=i}(BABYLON||(BABYLON={})),BABYLON.Effect.ShadersStore.triplanarVertexShader="precision highp float;\r\n\r\n// Attributes\r\nattribute vec3 position;\r\n#ifdef NORMAL\r\nattribute vec3 normal;\r\n#endif\r\n#ifdef VERTEXCOLOR\r\nattribute vec4 color;\r\n#endif\r\n#ifdef BONES\r\nattribute vec4 matricesIndices;\r\nattribute vec4 matricesWeights;\r\n#endif\r\n\r\n// Uniforms\r\n\r\n#ifdef INSTANCES\r\nattribute vec4 world0;\r\nattribute vec4 world1;\r\nattribute vec4 world2;\r\nattribute vec4 world3;\r\n#else\r\nuniform mat4 world;\r\n#endif\r\n\r\nuniform mat4 view;\r\nuniform mat4 viewProjection;\r\n\r\n#ifdef DIFFUSEX\r\nvarying vec2 vTextureUVX;\r\n#endif\r\n\r\n#ifdef DIFFUSEY\r\nvarying vec2 vTextureUVY;\r\n#endif\r\n\r\n#ifdef DIFFUSEZ\r\nvarying vec2 vTextureUVZ;\r\n#endif\r\n\r\nuniform float tileSize;\r\n\r\n#ifdef BONES\r\nuniform mat4 mBones[BonesPerMesh];\r\n#endif\r\n\r\n#ifdef POINTSIZE\r\nuniform float pointSize;\r\n#endif\r\n\r\n// Output\r\nvarying vec3 vPositionW;\r\n#ifdef NORMAL\r\nvarying mat3 tangentSpace;\r\n#endif\r\n\r\n#ifdef VERTEXCOLOR\r\nvarying vec4 vColor;\r\n#endif\r\n\r\n#ifdef CLIPPLANE\r\nuniform vec4 vClipPlane;\r\nvarying float fClipDistance;\r\n#endif\r\n\r\n#ifdef FOG\r\nvarying float fFogDistance;\r\n#endif\r\n\r\n#ifdef SHADOWS\r\n#if defined(SPOTLIGHT0) || defined(DIRLIGHT0)\r\nuniform mat4 lightMatrix0;\r\nvarying vec4 vPositionFromLight0;\r\n#endif\r\n#if defined(SPOTLIGHT1) || defined(DIRLIGHT1)\r\nuniform mat4 lightMatrix1;\r\nvarying vec4 vPositionFromLight1;\r\n#endif\r\n#if defined(SPOTLIGHT2) || defined(DIRLIGHT2)\r\nuniform mat4 lightMatrix2;\r\nvarying vec4 vPositionFromLight2;\r\n#endif\r\n#if defined(SPOTLIGHT3) || defined(DIRLIGHT3)\r\nuniform mat4 lightMatrix3;\r\nvarying vec4 vPositionFromLight3;\r\n#endif\r\n#endif\r\n\r\nvoid main(void) {\r\n mat4 finalWorld;\r\n\r\n#ifdef INSTANCES\r\n finalWorld = mat4(world0, world1, world2, world3);\r\n#else\r\n finalWorld = world;\r\n#endif\r\n\r\n#ifdef BONES\r\n mat4 m0 = mBones[int(matricesIndices.x)] * matricesWeights.x;\r\n mat4 m1 = mBones[int(matricesIndices.y)] * matricesWeights.y;\r\n mat4 m2 = mBones[int(matricesIndices.z)] * matricesWeights.z;\r\n\r\n#ifdef BONES4\r\n mat4 m3 = mBones[int(matricesIndices.w)] * matricesWeights.w;\r\n finalWorld = finalWorld * (m0 + m1 + m2 + m3);\r\n#else\r\n finalWorld = finalWorld * (m0 + m1 + m2);\r\n#endif \r\n\r\n#endif\r\n gl_Position = viewProjection * finalWorld * vec4(position, 1.0);\r\n\r\n vec4 worldPos = finalWorld * vec4(position, 1.0);\r\n vPositionW = vec3(worldPos);\r\n\r\n#ifdef DIFFUSEX\r\n vTextureUVX = worldPos.zy / tileSize;\r\n#endif\r\n\r\n#ifdef DIFFUSEY\r\n vTextureUVY = worldPos.xz / tileSize;\r\n#endif\r\n\r\n#ifdef DIFFUSEZ\r\n vTextureUVZ = worldPos.xy / tileSize;\r\n#endif\r\n\r\n#ifdef NORMAL\r\n // Compute tangent space (used for normal mapping + tri planar color mapping)\r\n vec3 xtan = vec3(0,0,1);//tangent space for the X aligned plane\r\n vec3 xbin = vec3(0,1,0);\r\n \r\n vec3 ytan = vec3(1,0,0);//tangent space for the Y aligned plane\r\n vec3 ybin = vec3(0,0,1);\r\n \r\n vec3 ztan = vec3(1,0,0);//tangent space for the Z aligned plane\r\n vec3 zbin = vec3(0,1,0);\r\n \r\n vec3 normalizedNormal = normalize(normal);\r\n normalizedNormal *= normalizedNormal;\r\n\r\n vec3 worldBinormal = normalize(xbin * normalizedNormal.x + ybin * normalizedNormal.y + zbin * normalizedNormal.z);\r\n vec3 worldTangent = normalize(xtan * normalizedNormal.x + ytan * normalizedNormal.y + ztan * normalizedNormal.z);\r\n \r\n worldTangent = (world * vec4(worldTangent, 1.0)).xyz;\r\n worldBinormal = (world * vec4(worldBinormal, 1.0)).xyz;\r\n vec3 worldNormal = normalize(cross(worldTangent, worldBinormal));\r\n\r\n tangentSpace[0] = worldTangent;\r\n tangentSpace[1] = worldBinormal;\r\n tangentSpace[2] = worldNormal;\r\n#endif\r\n\r\n // Clip plane\r\n#ifdef CLIPPLANE\r\n fClipDistance = dot(worldPos, vClipPlane);\r\n#endif\r\n\r\n // Fog\r\n#ifdef FOG\r\n fFogDistance = (view * worldPos).z;\r\n#endif\r\n\r\n // Shadows\r\n#ifdef SHADOWS\r\n#if defined(SPOTLIGHT0) || defined(DIRLIGHT0)\r\n vPositionFromLight0 = lightMatrix0 * worldPos;\r\n#endif\r\n#if defined(SPOTLIGHT1) || defined(DIRLIGHT1)\r\n vPositionFromLight1 = lightMatrix1 * worldPos;\r\n#endif\r\n#if defined(SPOTLIGHT2) || defined(DIRLIGHT2)\r\n vPositionFromLight2 = lightMatrix2 * worldPos;\r\n#endif\r\n#if defined(SPOTLIGHT3) || defined(DIRLIGHT3)\r\n vPositionFromLight3 = lightMatrix3 * worldPos;\r\n#endif\r\n#endif\r\n\r\n // Vertex color\r\n#ifdef VERTEXCOLOR\r\n vColor = color;\r\n#endif\r\n\r\n // Point size\r\n#ifdef POINTSIZE\r\n gl_PointSize = pointSize;\r\n#endif\r\n}\r\n",BABYLON.Effect.ShadersStore.triplanarPixelShader="precision highp float;\r\n\r\n// Constants\r\nuniform vec3 vEyePosition;\r\nuniform vec4 vDiffuseColor;\r\n\r\n#ifdef SPECULARTERM\r\nuniform vec4 vSpecularColor;\r\n#endif\r\n\r\n// Input\r\nvarying vec3 vPositionW;\r\n\r\n#ifdef VERTEXCOLOR\r\nvarying vec4 vColor;\r\n#endif\r\n\r\n// Lights\r\n#ifdef LIGHT0\r\nuniform vec4 vLightData0;\r\nuniform vec4 vLightDiffuse0;\r\n#ifdef SPECULARTERM\r\nuniform vec3 vLightSpecular0;\r\n#endif\r\n#ifdef SHADOW0\r\n#if defined(SPOTLIGHT0) || defined(DIRLIGHT0)\r\nvarying vec4 vPositionFromLight0;\r\nuniform sampler2D shadowSampler0;\r\n#else\r\nuniform samplerCube shadowSampler0;\r\n#endif\r\nuniform vec3 shadowsInfo0;\r\n#endif\r\n#ifdef SPOTLIGHT0\r\nuniform vec4 vLightDirection0;\r\n#endif\r\n#ifdef HEMILIGHT0\r\nuniform vec3 vLightGround0;\r\n#endif\r\n#endif\r\n\r\n#ifdef LIGHT1\r\nuniform vec4 vLightData1;\r\nuniform vec4 vLightDiffuse1;\r\n#ifdef SPECULARTERM\r\nuniform vec3 vLightSpecular1;\r\n#endif\r\n#ifdef SHADOW1\r\n#if defined(SPOTLIGHT1) || defined(DIRLIGHT1)\r\nvarying vec4 vPositionFromLight1;\r\nuniform sampler2D shadowSampler1;\r\n#else\r\nuniform samplerCube shadowSampler1;\r\n#endif\r\nuniform vec3 shadowsInfo1;\r\n#endif\r\n#ifdef SPOTLIGHT1\r\nuniform vec4 vLightDirection1;\r\n#endif\r\n#ifdef HEMILIGHT1\r\nuniform vec3 vLightGround1;\r\n#endif\r\n#endif\r\n\r\n#ifdef LIGHT2\r\nuniform vec4 vLightData2;\r\nuniform vec4 vLightDiffuse2;\r\n#ifdef SPECULARTERM\r\nuniform vec3 vLightSpecular2;\r\n#endif\r\n#ifdef SHADOW2\r\n#if defined(SPOTLIGHT2) || defined(DIRLIGHT2)\r\nvarying vec4 vPositionFromLight2;\r\nuniform sampler2D shadowSampler2;\r\n#else\r\nuniform samplerCube shadowSampler2;\r\n#endif\r\nuniform vec3 shadowsInfo2;\r\n#endif\r\n#ifdef SPOTLIGHT2\r\nuniform vec4 vLightDirection2;\r\n#endif\r\n#ifdef HEMILIGHT2\r\nuniform vec3 vLightGround2;\r\n#endif\r\n#endif\r\n\r\n#ifdef LIGHT3\r\nuniform vec4 vLightData3;\r\nuniform vec4 vLightDiffuse3;\r\n#ifdef SPECULARTERM\r\nuniform vec3 vLightSpecular3;\r\n#endif\r\n#ifdef SHADOW3\r\n#if defined(SPOTLIGHT3) || defined(DIRLIGHT3)\r\nvarying vec4 vPositionFromLight3;\r\nuniform sampler2D shadowSampler3;\r\n#else\r\nuniform samplerCube shadowSampler3;\r\n#endif\r\nuniform vec3 shadowsInfo3;\r\n#endif\r\n#ifdef SPOTLIGHT3\r\nuniform vec4 vLightDirection3;\r\n#endif\r\n#ifdef HEMILIGHT3\r\nuniform vec3 vLightGround3;\r\n#endif\r\n#endif\r\n\r\n// Samplers\r\n#ifdef DIFFUSEX\r\nvarying vec2 vTextureUVX;\r\nuniform sampler2D diffuseSamplerX;\r\n#ifdef BUMPX\r\nuniform sampler2D normalSamplerX;\r\n#endif\r\n#endif\r\n\r\n#ifdef DIFFUSEY\r\nvarying vec2 vTextureUVY;\r\nuniform sampler2D diffuseSamplerY;\r\n#ifdef BUMPY\r\nuniform sampler2D normalSamplerY;\r\n#endif\r\n#endif\r\n\r\n#ifdef DIFFUSEZ\r\nvarying vec2 vTextureUVZ;\r\nuniform sampler2D diffuseSamplerZ;\r\n#ifdef BUMPZ\r\nuniform sampler2D normalSamplerZ;\r\n#endif\r\n#endif\r\n\r\n#ifdef NORMAL\r\nvarying mat3 tangentSpace;\r\n#endif\r\n\r\n// Shadows\r\n#ifdef SHADOWS\r\n\r\nfloat unpack(vec4 color)\r\n{\r\n const vec4 bit_shift = vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0);\r\n return dot(color, bit_shift);\r\n}\r\n\r\n#if defined(POINTLIGHT0) || defined(POINTLIGHT1) || defined(POINTLIGHT2) || defined(POINTLIGHT3)\r\nfloat computeShadowCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, float bias)\r\n{\r\n vec3 directionToLight = vPositionW - lightPosition;\r\n float depth = length(directionToLight);\r\n\r\n depth = clamp(depth, 0., 1.);\r\n\r\n directionToLight.y = 1.0 - directionToLight.y;\r\n\r\n float shadow = unpack(textureCube(shadowSampler, directionToLight)) + bias;\r\n\r\n if (depth > shadow)\r\n {\r\n return darkness;\r\n }\r\n return 1.0;\r\n}\r\n\r\nfloat computeShadowWithPCFCube(vec3 lightPosition, samplerCube shadowSampler, float mapSize, float bias, float darkness)\r\n{\r\n vec3 directionToLight = vPositionW - lightPosition;\r\n float depth = length(directionToLight);\r\n float diskScale = (1.0 - (1.0 + depth * 3.0)) / mapSize;\r\n\r\n depth = clamp(depth, 0., 1.);\r\n\r\n directionToLight.y = 1.0 - directionToLight.y;\r\n\r\n float visibility = 1.;\r\n\r\n vec3 poissonDisk[4];\r\n poissonDisk[0] = vec3(-1.0, 1.0, -1.0);\r\n poissonDisk[1] = vec3(1.0, -1.0, -1.0);\r\n poissonDisk[2] = vec3(-1.0, -1.0, -1.0);\r\n poissonDisk[3] = vec3(1.0, -1.0, 1.0);\r\n\r\n // Poisson Sampling\r\n float biasedDepth = depth - bias;\r\n\r\n if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[0] * diskScale)) < biasedDepth) visibility -= 0.25;\r\n if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[1] * diskScale)) < biasedDepth) visibility -= 0.25;\r\n if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[2] * diskScale)) < biasedDepth) visibility -= 0.25;\r\n if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[3] * diskScale)) < biasedDepth) visibility -= 0.25;\r\n\r\n return min(1.0, visibility + darkness);\r\n}\r\n#endif\r\n\r\n#if defined(SPOTLIGHT0) || defined(SPOTLIGHT1) || defined(SPOTLIGHT2) || defined(SPOTLIGHT3) || defined(DIRLIGHT0) || defined(DIRLIGHT1) || defined(DIRLIGHT2) || defined(DIRLIGHT3)\r\nfloat computeShadow(vec4 vPositionFromLight, sampler2D shadowSampler, float darkness, float bias)\r\n{\r\n vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;\r\n depth = 0.5 * depth + vec3(0.5);\r\n vec2 uv = depth.xy;\r\n\r\n if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)\r\n {\r\n return 1.0;\r\n }\r\n\r\n float shadow = unpack(texture2D(shadowSampler, uv)) + bias;\r\n\r\n if (depth.z > shadow)\r\n {\r\n return darkness;\r\n }\r\n return 1.;\r\n}\r\n\r\nfloat computeShadowWithPCF(vec4 vPositionFromLight, sampler2D shadowSampler, float mapSize, float bias, float darkness)\r\n{\r\n vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;\r\n depth = 0.5 * depth + vec3(0.5);\r\n vec2 uv = depth.xy;\r\n\r\n if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)\r\n {\r\n return 1.0;\r\n }\r\n\r\n float visibility = 1.;\r\n\r\n vec2 poissonDisk[4];\r\n poissonDisk[0] = vec2(-0.94201624, -0.39906216);\r\n poissonDisk[1] = vec2(0.94558609, -0.76890725);\r\n poissonDisk[2] = vec2(-0.094184101, -0.92938870);\r\n poissonDisk[3] = vec2(0.34495938, 0.29387760);\r\n\r\n // Poisson Sampling\r\n float biasedDepth = depth.z - bias;\r\n\r\n if (unpack(texture2D(shadowSampler, uv + poissonDisk[0] / mapSize)) < biasedDepth) visibility -= 0.25;\r\n if (unpack(texture2D(shadowSampler, uv + poissonDisk[1] / mapSize)) < biasedDepth) visibility -= 0.25;\r\n if (unpack(texture2D(shadowSampler, uv + poissonDisk[2] / mapSize)) < biasedDepth) visibility -= 0.25;\r\n if (unpack(texture2D(shadowSampler, uv + poissonDisk[3] / mapSize)) < biasedDepth) visibility -= 0.25;\r\n\r\n return min(1.0, visibility + darkness);\r\n}\r\n\r\n// Thanks to http://devmaster.net/\r\nfloat unpackHalf(vec2 color)\r\n{\r\n return color.x + (color.y / 255.0);\r\n}\r\n\r\nfloat linstep(float low, float high, float v) {\r\n return clamp((v - low) / (high - low), 0.0, 1.0);\r\n}\r\n\r\nfloat ChebychevInequality(vec2 moments, float compare, float bias)\r\n{\r\n float p = smoothstep(compare - bias, compare, moments.x);\r\n float variance = max(moments.y - moments.x * moments.x, 0.02);\r\n float d = compare - moments.x;\r\n float p_max = linstep(0.2, 1.0, variance / (variance + d * d));\r\n\r\n return clamp(max(p, p_max), 0.0, 1.0);\r\n}\r\n\r\nfloat computeShadowWithVSM(vec4 vPositionFromLight, sampler2D shadowSampler, float bias, float darkness)\r\n{\r\n vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;\r\n depth = 0.5 * depth + vec3(0.5);\r\n vec2 uv = depth.xy;\r\n\r\n if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0 || depth.z >= 1.0)\r\n {\r\n return 1.0;\r\n }\r\n\r\n vec4 texel = texture2D(shadowSampler, uv);\r\n\r\n vec2 moments = vec2(unpackHalf(texel.xy), unpackHalf(texel.zw));\r\n return min(1.0, 1.0 - ChebychevInequality(moments, depth.z, bias) + darkness);\r\n}\r\n#endif\r\n#endif\r\n\r\n\r\n#ifdef CLIPPLANE\r\nvarying float fClipDistance;\r\n#endif\r\n\r\n// Fog\r\n#ifdef FOG\r\n\r\n#define FOGMODE_NONE 0.\r\n#define FOGMODE_EXP 1.\r\n#define FOGMODE_EXP2 2.\r\n#define FOGMODE_LINEAR 3.\r\n#define E 2.71828\r\n\r\nuniform vec4 vFogInfos;\r\nuniform vec3 vFogColor;\r\nvarying float fFogDistance;\r\n\r\nfloat CalcFogFactor()\r\n{\r\n float fogCoeff = 1.0;\r\n float fogStart = vFogInfos.y;\r\n float fogEnd = vFogInfos.z;\r\n float fogDensity = vFogInfos.w;\r\n\r\n if (FOGMODE_LINEAR == vFogInfos.x)\r\n {\r\n fogCoeff = (fogEnd - fFogDistance) / (fogEnd - fogStart);\r\n }\r\n else if (FOGMODE_EXP == vFogInfos.x)\r\n {\r\n fogCoeff = 1.0 / pow(E, fFogDistance * fogDensity);\r\n }\r\n else if (FOGMODE_EXP2 == vFogInfos.x)\r\n {\r\n fogCoeff = 1.0 / pow(E, fFogDistance * fFogDistance * fogDensity * fogDensity);\r\n }\r\n\r\n return clamp(fogCoeff, 0.0, 1.0);\r\n}\r\n#endif\r\n\r\n// Bump\r\n#ifdef BUMP\r\n#extension GL_OES_standard_derivatives : enable\r\n// Thanks to http://www.thetenthplanet.de/archives/1180\r\nmat3 cotangent_frame(vec3 normal, vec3 p, vec2 uv)\r\n{\r\n // get edge vectors of the pixel triangle\r\n vec3 dp1 = dFdx(p);\r\n vec3 dp2 = dFdy(p);\r\n vec2 duv1 = dFdx(uv);\r\n vec2 duv2 = dFdy(uv);\r\n\r\n // solve the linear system\r\n vec3 dp2perp = cross(dp2, normal);\r\n vec3 dp1perp = cross(normal, dp1);\r\n vec3 tangent = dp2perp * duv1.x + dp1perp * duv2.x;\r\n vec3 binormal = dp2perp * duv1.y + dp1perp * duv2.y;\r\n\r\n // construct a scale-invariant frame \r\n float invmax = inversesqrt(max(dot(tangent, tangent), dot(binormal, binormal)));\r\n return mat3(tangent * invmax, binormal * invmax, normal);\r\n}\r\n\r\nvec3 perturbNormal(vec3 viewDir, vec3 mixColor)\r\n{ \r\n vec3 bump1Color = texture2D(bump1Sampler, vTextureUV * diffuse1Infos).xyz;\r\n vec3 bump2Color = texture2D(bump2Sampler, vTextureUV * diffuse2Infos).xyz;\r\n vec3 bump3Color = texture2D(bump3Sampler, vTextureUV * diffuse3Infos).xyz;\r\n \r\n bump1Color.rgb *= mixColor.r;\r\n bump2Color.rgb = mix(bump1Color.rgb, bump2Color.rgb, mixColor.g);\r\n vec3 map = mix(bump2Color.rgb, bump3Color.rgb, mixColor.b);\r\n \r\n map = map * 255. / 127. - 128. / 127.;\r\n mat3 TBN = cotangent_frame(vNormalW * vTextureInfos.y, -viewDir, vTextureUV);\r\n return normalize(TBN * map);\r\n}\r\n#endif\r\n\r\n// Light Computing\r\nstruct lightingInfo\r\n{\r\n vec3 diffuse;\r\n#ifdef SPECULARTERM\r\n vec3 specular;\r\n#endif\r\n};\r\n\r\nlightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, float range, float glossiness) {\r\n lightingInfo result;\r\n\r\n vec3 lightVectorW;\r\n float attenuation = 1.0;\r\n if (lightData.w == 0.)\r\n {\r\n vec3 direction = lightData.xyz - vPositionW;\r\n\r\n attenuation = max(0., 1.0 - length(direction) / range);\r\n lightVectorW = normalize(direction);\r\n }\r\n else\r\n {\r\n lightVectorW = normalize(-lightData.xyz);\r\n }\r\n\r\n // diffuse\r\n float ndl = max(0., dot(vNormal, lightVectorW));\r\n result.diffuse = ndl * diffuseColor * attenuation;\r\n\r\n#ifdef SPECULARTERM\r\n // Specular\r\n vec3 angleW = normalize(viewDirectionW + lightVectorW);\r\n float specComp = max(0., dot(vNormal, angleW));\r\n specComp = pow(specComp, max(1., glossiness));\r\n\r\n result.specular = specComp * specularColor * attenuation;\r\n#endif\r\n return result;\r\n}\r\n\r\nlightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor, float range, float glossiness) {\r\n lightingInfo result;\r\n\r\n vec3 direction = lightData.xyz - vPositionW;\r\n vec3 lightVectorW = normalize(direction);\r\n float attenuation = max(0., 1.0 - length(direction) / range);\r\n\r\n // diffuse\r\n float cosAngle = max(0., dot(-lightDirection.xyz, lightVectorW));\r\n float spotAtten = 0.0;\r\n\r\n if (cosAngle >= lightDirection.w)\r\n {\r\n cosAngle = max(0., pow(cosAngle, lightData.w));\r\n spotAtten = clamp((cosAngle - lightDirection.w) / (1. - cosAngle), 0.0, 1.0);\r\n\r\n // Diffuse\r\n float ndl = max(0., dot(vNormal, -lightDirection.xyz));\r\n result.diffuse = ndl * spotAtten * diffuseColor * attenuation;\r\n\r\n#ifdef SPECULARTERM\r\n // Specular\r\n vec3 angleW = normalize(viewDirectionW - lightDirection.xyz);\r\n float specComp = max(0., dot(vNormal, angleW));\r\n specComp = pow(specComp, max(1., glossiness));\r\n\r\n result.specular = specComp * specularColor * spotAtten * attenuation;\r\n#endif\r\n\r\n return result;\r\n }\r\n\r\n result.diffuse = vec3(0.);\r\n#ifdef SPECULARTERM\r\n result.specular = vec3(0.);\r\n#endif\r\n\r\n return result;\r\n}\r\n\r\nlightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, vec3 groundColor, float glossiness) {\r\n lightingInfo result;\r\n\r\n // Diffuse\r\n float ndl = dot(vNormal, lightData.xyz) * 0.5 + 0.5;\r\n result.diffuse = mix(groundColor, diffuseColor, ndl);\r\n\r\n#ifdef SPECULARTERM\r\n // Specular\r\n vec3 angleW = normalize(viewDirectionW + lightData.xyz);\r\n float specComp = max(0., dot(vNormal, angleW));\r\n specComp = pow(specComp, max(1., glossiness));\r\n\r\n result.specular = specComp * specularColor;\r\n#endif\r\n\r\n return result;\r\n}\r\n\r\nvoid main(void) {\r\n // Clip plane\r\n#ifdef CLIPPLANE\r\n if (fClipDistance > 0.0)\r\n discard;\r\n#endif\r\n\r\n vec3 viewDirectionW = normalize(vEyePosition - vPositionW);\r\n\r\n // Base color\r\n vec4 baseColor = vec4(0., 0., 0., 1.);\r\n vec3 diffuseColor = vDiffuseColor.rgb;\r\n \r\n#ifdef SPECULARTERM\r\n float glossiness = vSpecularColor.a;\r\n vec3 specularColor = vSpecularColor.rgb;\r\n#else\r\n float glossiness = 0.;\r\n#endif\r\n\r\n // Alpha\r\n float alpha = vDiffuseColor.a;\r\n \r\n // Bump\r\n#ifdef NORMAL\r\n vec3 normalW = tangentSpace[2];\r\n#else\r\n vec3 normalW = vec3(1.0, 1.0, 1.0);\r\n#endif\r\n\r\n vec4 baseNormal = vec4(0.0, 0.0, 0.0, 1.0);\r\n normalW *= normalW;\r\n\r\n#ifdef DIFFUSEX\r\n baseColor += texture2D(diffuseSamplerX, vTextureUVX) * normalW.x;\r\n#ifdef BUMPX\r\n baseNormal += texture2D(normalSamplerX, vTextureUVX) * normalW.x;\r\n#endif\r\n#endif\r\n\r\n#ifdef DIFFUSEY\r\n baseColor += texture2D(diffuseSamplerY, vTextureUVY) * normalW.y;\r\n#ifdef BUMPY\r\n baseNormal += texture2D(normalSamplerY, vTextureUVY) * normalW.y;\r\n#endif\r\n#endif\r\n\r\n#ifdef DIFFUSEZ\r\n baseColor += texture2D(diffuseSamplerZ, vTextureUVZ) * normalW.z;\r\n#ifdef BUMPZ\r\n baseNormal += texture2D(normalSamplerZ, vTextureUVZ) * normalW.z;\r\n#endif\r\n#endif\r\n\r\n#ifdef NORMAL\r\n normalW = normalize((2.0 * baseNormal.xyz - 1.0) * tangentSpace);\r\n#endif\r\n\r\n#ifdef ALPHATEST\r\n if (baseColor.a < 0.4)\r\n discard;\r\n#endif\r\n\r\n#ifdef VERTEXCOLOR\r\n baseColor.rgb *= vColor.rgb;\r\n#endif\r\n\r\n // Lighting\r\n vec3 diffuseBase = vec3(0., 0., 0.);\r\n#ifdef SPECULARTERM\r\n vec3 specularBase = vec3(0., 0., 0.);\r\n#endif\r\n float shadow = 1.;\r\n\r\n#ifdef LIGHT0\r\n#ifndef SPECULARTERM\r\n vec3 vLightSpecular0 = vec3(0.0);\r\n#endif\r\n#ifdef SPOTLIGHT0\r\n lightingInfo info = computeSpotLighting(viewDirectionW, normalW, vLightData0, vLightDirection0, vLightDiffuse0.rgb, vLightSpecular0, vLightDiffuse0.a, glossiness);\r\n#endif\r\n#ifdef HEMILIGHT0\r\n lightingInfo info = computeHemisphericLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0.rgb, vLightSpecular0, vLightGround0, glossiness);\r\n#endif\r\n#if defined(POINTLIGHT0) || defined(DIRLIGHT0)\r\n lightingInfo info = computeLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0.rgb, vLightSpecular0, vLightDiffuse0.a, glossiness);\r\n#endif\r\n#ifdef SHADOW0\r\n#ifdef SHADOWVSM0\r\n shadow = computeShadowWithVSM(vPositionFromLight0, shadowSampler0, shadowsInfo0.z, shadowsInfo0.x);\r\n#else\r\n#ifdef SHADOWPCF0\r\n#if defined(POINTLIGHT0)\r\n shadow = computeShadowWithPCFCube(vLightData0.xyz, shadowSampler0, shadowsInfo0.y, shadowsInfo0.z, shadowsInfo0.x);\r\n#else\r\n shadow = computeShadowWithPCF(vPositionFromLight0, shadowSampler0, shadowsInfo0.y, shadowsInfo0.z, shadowsInfo0.x);\r\n#endif\r\n#else\r\n#if defined(POINTLIGHT0)\r\n shadow = computeShadowCube(vLightData0.xyz, shadowSampler0, shadowsInfo0.x, shadowsInfo0.z);\r\n#else\r\n shadow = computeShadow(vPositionFromLight0, shadowSampler0, shadowsInfo0.x, shadowsInfo0.z);\r\n#endif\r\n#endif\r\n#endif\r\n#else\r\n shadow = 1.;\r\n#endif\r\n diffuseBase += info.diffuse * shadow;\r\n#ifdef SPECULARTERM\r\n specularBase += info.specular * shadow;\r\n#endif\r\n#endif\r\n\r\n#ifdef LIGHT1\r\n#ifndef SPECULARTERM\r\n vec3 vLightSpecular1 = vec3(0.0);\r\n#endif\r\n#ifdef SPOTLIGHT1\r\n info = computeSpotLighting(viewDirectionW, normalW, vLightData1, vLightDirection1, vLightDiffuse1.rgb, vLightSpecular1, vLightDiffuse1.a, glossiness);\r\n#endif\r\n#ifdef HEMILIGHT1\r\n info = computeHemisphericLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1.rgb, vLightSpecular1, vLightGround1, glossiness);\r\n#endif\r\n#if defined(POINTLIGHT1) || defined(DIRLIGHT1)\r\n info = computeLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1.rgb, vLightSpecular1, vLightDiffuse1.a, glossiness);\r\n#endif\r\n#ifdef SHADOW1\r\n#ifdef SHADOWVSM1\r\n shadow = computeShadowWithVSM(vPositionFromLight1, shadowSampler1, shadowsInfo1.z, shadowsInfo1.x);\r\n#else\r\n#ifdef SHADOWPCF1\r\n#if defined(POINTLIGHT1)\r\n shadow = computeShadowWithPCFCube(vLightData1.xyz, shadowSampler1, shadowsInfo1.y, shadowsInfo1.z, shadowsInfo1.x);\r\n#else\r\n shadow = computeShadowWithPCF(vPositionFromLight1, shadowSampler1, shadowsInfo1.y, shadowsInfo1.z, shadowsInfo1.x);\r\n#endif\r\n#else\r\n#if defined(POINTLIGHT1)\r\n shadow = computeShadowCube(vLightData1.xyz, shadowSampler1, shadowsInfo1.x, shadowsInfo1.z);\r\n#else\r\n shadow = computeShadow(vPositionFromLight1, shadowSampler1, shadowsInfo1.x, shadowsInfo1.z);\r\n#endif\r\n#endif\r\n#endif\r\n#else\r\n shadow = 1.;\r\n#endif\r\n diffuseBase += info.diffuse * shadow;\r\n#ifdef SPECULARTERM\r\n specularBase += info.specular * shadow;\r\n#endif\r\n#endif\r\n\r\n#ifdef LIGHT2\r\n#ifndef SPECULARTERM\r\n vec3 vLightSpecular2 = vec3(0.0);\r\n#endif\r\n#ifdef SPOTLIGHT2\r\n info = computeSpotLighting(viewDirectionW, normalW, vLightData2, vLightDirection2, vLightDiffuse2.rgb, vLightSpecular2, vLightDiffuse2.a, glossiness);\r\n#endif\r\n#ifdef HEMILIGHT2\r\n info = computeHemisphericLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2.rgb, vLightSpecular2, vLightGround2, glossiness);\r\n#endif\r\n#if defined(POINTLIGHT2) || defined(DIRLIGHT2)\r\n info = computeLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2.rgb, vLightSpecular2, vLightDiffuse2.a, glossiness);\r\n#endif\r\n#ifdef SHADOW2\r\n#ifdef SHADOWVSM2\r\n shadow = computeShadowWithVSM(vPositionFromLight2, shadowSampler2, shadowsInfo2.z, shadowsInfo2.x);\r\n#else\r\n#ifdef SHADOWPCF2\r\n#if defined(POINTLIGHT2)\r\n shadow = computeShadowWithPCFCube(vLightData2.xyz, shadowSampler2, shadowsInfo2.y, shadowsInfo2.z, shadowsInfo2.x);\r\n#else\r\n shadow = computeShadowWithPCF(vPositionFromLight2, shadowSampler2, shadowsInfo2.y, shadowsInfo2.z, shadowsInfo2.x);\r\n#endif\r\n#else\r\n#if defined(POINTLIGHT2)\r\n shadow = computeShadowCube(vLightData2.xyz, shadowSampler2, shadowsInfo2.x, shadowsInfo2.z);\r\n#else\r\n shadow = computeShadow(vPositionFromLight2, shadowSampler2, shadowsInfo2.x, shadowsInfo2.z);\r\n#endif\r\n#endif \r\n#endif \r\n#else\r\n shadow = 1.;\r\n#endif\r\n diffuseBase += info.diffuse * shadow;\r\n#ifdef SPECULARTERM\r\n specularBase += info.specular * shadow;\r\n#endif\r\n#endif\r\n\r\n#ifdef LIGHT3\r\n#ifndef SPECULARTERM\r\n vec3 vLightSpecular3 = vec3(0.0);\r\n#endif\r\n#ifdef SPOTLIGHT3\r\n info = computeSpotLighting(viewDirectionW, normalW, vLightData3, vLightDirection3, vLightDiffuse3.rgb, vLightSpecular3, vLightDiffuse3.a, glossiness);\r\n#endif\r\n#ifdef HEMILIGHT3\r\n info = computeHemisphericLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3.rgb, vLightSpecular3, vLightGround3, glossiness);\r\n#endif\r\n#if defined(POINTLIGHT3) || defined(DIRLIGHT3)\r\n info = computeLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3.rgb, vLightSpecular3, vLightDiffuse3.a, glossiness);\r\n#endif\r\n#ifdef SHADOW3\r\n#ifdef SHADOWVSM3\r\n shadow = computeShadowWithVSM(vPositionFromLight3, shadowSampler3, shadowsInfo3.z, shadowsInfo3.x);\r\n#else\r\n#ifdef SHADOWPCF3\r\n#if defined(POINTLIGHT3)\r\n shadow = computeShadowWithPCFCube(vLightData3.xyz, shadowSampler3, shadowsInfo3.y, shadowsInfo3.z, shadowsInfo3.x);\r\n#else\r\n shadow = computeShadowWithPCF(vPositionFromLight3, shadowSampler3, shadowsInfo3.y, shadowsInfo3.z, shadowsInfo3.x);\r\n#endif\r\n#else\r\n#if defined(POINTLIGHT3)\r\n shadow = computeShadowCube(vLightData3.xyz, shadowSampler3, shadowsInfo3.x, shadowsInfo3.z);\r\n#else\r\n shadow = computeShadow(vPositionFromLight3, shadowSampler3, shadowsInfo3.x, shadowsInfo3.z);\r\n#endif\r\n#endif \r\n#endif \r\n#else\r\n shadow = 1.;\r\n#endif\r\n diffuseBase += info.diffuse * shadow;\r\n#ifdef SPECULARTERM\r\n specularBase += info.specular * shadow;\r\n#endif\r\n#endif\r\n\r\n#ifdef VERTEXALPHA\r\n alpha *= vColor.a;\r\n#endif\r\n\r\n#ifdef SPECULARTERM\r\n vec3 finalSpecular = specularBase * specularColor;\r\n#else\r\n vec3 finalSpecular = vec3(0.0);\r\n#endif\r\n\r\n vec3 finalDiffuse = clamp(diffuseBase * diffuseColor, 0.0, 1.0) * baseColor.rgb;\r\n\r\n // Composition\r\n vec4 color = vec4(finalDiffuse + finalSpecular, alpha);\r\n\r\n#ifdef FOG\r\n float fog = CalcFogFactor();\r\n color.rgb = fog * color.rgb + (1.0 - fog) * vFogColor;\r\n#endif\r\n\r\n gl_FragColor = color;\r\n}\r\n"; \ No newline at end of file diff --git a/materialsLibrary/dist/dts/babylon.triPlanarMaterial.d.ts b/materialsLibrary/dist/dts/babylon.triPlanarMaterial.d.ts new file mode 100644 index 00000000000..60a70a36472 --- /dev/null +++ b/materialsLibrary/dist/dts/babylon.triPlanarMaterial.d.ts @@ -0,0 +1,36 @@ +/// +declare module BABYLON { + class TriPlanarMaterial extends Material { + mixTexture: BaseTexture; + diffuseTextureX: Texture; + diffuseTextureY: Texture; + diffuseTextureZ: Texture; + normalTextureX: Texture; + normalTextureY: Texture; + normalTextureZ: Texture; + tileSize: number; + diffuseColor: Color3; + specularColor: Color3; + specularPower: number; + disableLighting: boolean; + private _worldViewProjectionMatrix; + private _scaledDiffuse; + private _scaledSpecular; + private _renderId; + private _defines; + private _cachedDefines; + constructor(name: string, scene: Scene); + needAlphaBlending(): boolean; + needAlphaTesting(): boolean; + getAlphaTestTexture(): BaseTexture; + private _checkCache(scene, mesh?, useInstances?); + isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean; + bindOnlyWorldMatrix(world: Matrix): void; + bind(world: Matrix, mesh?: Mesh): void; + getAnimatables(): IAnimatable[]; + dispose(forceDisposeEffect?: boolean): void; + clone(name: string): TriPlanarMaterial; + serialize(): any; + static Parse(source: any, scene: Scene, rootUrl: string): TriPlanarMaterial; + } +} diff --git a/materialsLibrary/materials/triPlanar/babylon.triPlanarMaterial.ts b/materialsLibrary/materials/triPlanar/babylon.triPlanarMaterial.ts new file mode 100644 index 00000000000..37bf0667bd7 --- /dev/null +++ b/materialsLibrary/materials/triPlanar/babylon.triPlanarMaterial.ts @@ -0,0 +1,622 @@ +/// + +module BABYLON { + var maxSimultaneousLights = 4; + + class TriPlanarMaterialDefines extends MaterialDefines { + public DIFFUSEX = false; + public DIFFUSEY = false; + public DIFFUSEZ = false; + + public BUMPX = false; + public BUMPY = false; + public BUMPZ = false; + + public CLIPPLANE = false; + public ALPHATEST = false; + public POINTSIZE = false; + public FOG = false; + public LIGHT0 = false; + public LIGHT1 = false; + public LIGHT2 = false; + public LIGHT3 = false; + public SPOTLIGHT0 = false; + public SPOTLIGHT1 = false; + public SPOTLIGHT2 = false; + public SPOTLIGHT3 = false; + public HEMILIGHT0 = false; + public HEMILIGHT1 = false; + public HEMILIGHT2 = false; + public HEMILIGHT3 = false; + public DIRLIGHT0 = false; + public DIRLIGHT1 = false; + public DIRLIGHT2 = false; + public DIRLIGHT3 = false; + public POINTLIGHT0 = false; + public POINTLIGHT1 = false; + public POINTLIGHT2 = false; + public POINTLIGHT3 = false; + public SHADOW0 = false; + public SHADOW1 = false; + public SHADOW2 = false; + public SHADOW3 = false; + public SHADOWS = false; + public SHADOWVSM0 = false; + public SHADOWVSM1 = false; + public SHADOWVSM2 = false; + public SHADOWVSM3 = false; + public SHADOWPCF0 = false; + public SHADOWPCF1 = false; + public SHADOWPCF2 = false; + public SHADOWPCF3 = false; + public SPECULARTERM = false; + public NORMAL = false; + public VERTEXCOLOR = false; + public VERTEXALPHA = false; + public BONES = false; + public BONES4 = false; + public BonesPerMesh = 0; + public INSTANCES = false; + + constructor() { + super(); + this._keys = Object.keys(this); + } + } + + export class TriPlanarMaterial extends Material { + public mixTexture: BaseTexture; + + public diffuseTextureX: Texture; + public diffuseTextureY: Texture; + public diffuseTextureZ: Texture; + + public normalTextureX: Texture; + public normalTextureY: Texture; + public normalTextureZ: Texture; + + public tileSize: number = 1; + + public diffuseColor = new Color3(1, 1, 1); + public specularColor = new Color3(0.2, 0.2, 0.2); + public specularPower = 64; + public disableLighting = false; + + private _worldViewProjectionMatrix = Matrix.Zero(); + private _scaledDiffuse = new Color3(); + private _scaledSpecular = new Color3(); + private _renderId: number; + + private _defines = new TriPlanarMaterialDefines(); + private _cachedDefines = new TriPlanarMaterialDefines(); + + constructor(name: string, scene: Scene) { + super(name, scene); + + this._cachedDefines.BonesPerMesh = -1; + } + + public needAlphaBlending(): boolean { + return (this.alpha < 1.0); + } + + public needAlphaTesting(): boolean { + return false; + } + + public getAlphaTestTexture(): BaseTexture { + return null; + } + + // Methods + private _checkCache(scene: Scene, mesh?: AbstractMesh, useInstances?: boolean): boolean { + if (!mesh) { + return true; + } + + if (this._defines.INSTANCES !== useInstances) { + return false; + } + + if (mesh._materialDefines && mesh._materialDefines.isEqual(this._defines)) { + return true; + } + + return false; + } + + public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean { + if (this.checkReadyOnlyOnce) { + if (this._wasPreviouslyReady) { + return true; + } + } + + var scene = this.getScene(); + + if (!this.checkReadyOnEveryCall) { + if (this._renderId === scene.getRenderId()) { + if (this._checkCache(scene, mesh, useInstances)) { + return true; + } + } + } + + var engine = scene.getEngine(); + var needNormals = false; + + this._defines.reset(); + + // Textures + if (scene.texturesEnabled) { + if (StandardMaterial.DiffuseTextureEnabled) { + var textures = [this.diffuseTextureX, this.diffuseTextureY, this.diffuseTextureZ]; + var textureDefines = ["DIFFUSEX", "DIFFUSEY", "DIFFUSEZ"]; + + for (var i=0; i < textures.length; i++) { + if (textures[i]) { + if (!textures[i].isReady()) { + return false; + } else { + this._defines[textureDefines[i]] = true; + } + } + } + } + if (StandardMaterial.BumpTextureEnabled) { + var textures = [this.normalTextureX, this.normalTextureY, this.normalTextureZ]; + var textureDefines = ["BUMPX", "BUMPY", "BUMPZ"]; + + for (var i=0; i < textures.length; i++) { + if (textures[i]) { + if (!textures[i].isReady()) { + return false; + } else { + this._defines[textureDefines[i]] = true; + } + } + } + } + } + + // Effect + if (scene.clipPlane) { + this._defines.CLIPPLANE = true; + } + + if (engine.getAlphaTesting()) { + this._defines.ALPHATEST = true; + } + + // Point size + if (this.pointsCloud || scene.forcePointsCloud) { + this._defines.POINTSIZE = true; + } + + // Fog + if (scene.fogEnabled && mesh && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE && this.fogEnabled) { + this._defines.FOG = true; + } + + var lightIndex = 0; + if (scene.lightsEnabled && !this.disableLighting) { + for (var index = 0; index < scene.lights.length; index++) { + var light = scene.lights[index]; + + if (!light.isEnabled()) { + continue; + } + + // Excluded check + if (light._excludedMeshesIds.length > 0) { + for (var excludedIndex = 0; excludedIndex < light._excludedMeshesIds.length; excludedIndex++) { + var excludedMesh = scene.getMeshByID(light._excludedMeshesIds[excludedIndex]); + + if (excludedMesh) { + light.excludedMeshes.push(excludedMesh); + } + } + + light._excludedMeshesIds = []; + } + + // Included check + if (light._includedOnlyMeshesIds.length > 0) { + for (var includedOnlyIndex = 0; includedOnlyIndex < light._includedOnlyMeshesIds.length; includedOnlyIndex++) { + var includedOnlyMesh = scene.getMeshByID(light._includedOnlyMeshesIds[includedOnlyIndex]); + + if (includedOnlyMesh) { + light.includedOnlyMeshes.push(includedOnlyMesh); + } + } + + light._includedOnlyMeshesIds = []; + } + + if (!light.canAffectMesh(mesh)) { + continue; + } + needNormals = true; + this._defines["LIGHT" + lightIndex] = true; + + var type; + if (light instanceof SpotLight) { + type = "SPOTLIGHT" + lightIndex; + } else if (light instanceof HemisphericLight) { + type = "HEMILIGHT" + lightIndex; + } else if (light instanceof PointLight) { + type = "POINTLIGHT" + lightIndex; + } else { + type = "DIRLIGHT" + lightIndex; + } + + this._defines[type] = true; + + // Specular + if (!light.specular.equalsFloats(0, 0, 0)) { + this._defines.SPECULARTERM = true; + } + + // Shadows + if (scene.shadowsEnabled) { + var shadowGenerator = light.getShadowGenerator(); + if (mesh && mesh.receiveShadows && shadowGenerator) { + this._defines["SHADOW" + lightIndex] = true; + + this._defines.SHADOWS = true; + + if (shadowGenerator.useVarianceShadowMap || shadowGenerator.useBlurVarianceShadowMap) { + this._defines["SHADOWVSM" + lightIndex] = true; + } + + if (shadowGenerator.usePoissonSampling) { + this._defines["SHADOWPCF" + lightIndex] = true; + } + } + } + + lightIndex++; + if (lightIndex === maxSimultaneousLights) + break; + } + } + + // Attribs + if (mesh) { + if (needNormals && mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) { + this._defines.NORMAL = true; + } + if (mesh.useVertexColors && mesh.isVerticesDataPresent(VertexBuffer.ColorKind)) { + this._defines.VERTEXCOLOR = true; + + if (mesh.hasVertexAlpha) { + this._defines.VERTEXALPHA = true; + } + } + if (mesh.useBones && mesh.computeBonesUsingShaders) { + this._defines.BONES = true; + this._defines.BonesPerMesh = (mesh.skeleton.bones.length + 1); + this._defines.BONES4 = true; + } + + // Instances + if (useInstances) { + this._defines.INSTANCES = true; + } + } + + // Get correct effect + if (!this._defines.isEqual(this._cachedDefines)) { + this._defines.cloneTo(this._cachedDefines); + + scene.resetCachedMaterial(); + + // Fallbacks + var fallbacks = new EffectFallbacks(); + if (this._defines.FOG) { + fallbacks.addFallback(1, "FOG"); + } + + for (lightIndex = 0; lightIndex < maxSimultaneousLights; lightIndex++) { + if (!this._defines["LIGHT" + lightIndex]) { + continue; + } + + if (lightIndex > 0) { + fallbacks.addFallback(lightIndex, "LIGHT" + lightIndex); + } + + if (this._defines["SHADOW" + lightIndex]) { + fallbacks.addFallback(0, "SHADOW" + lightIndex); + } + + if (this._defines["SHADOWPCF" + lightIndex]) { + fallbacks.addFallback(0, "SHADOWPCF" + lightIndex); + } + + if (this._defines["SHADOWVSM" + lightIndex]) { + fallbacks.addFallback(0, "SHADOWVSM" + lightIndex); + } + } + + if (this._defines.BONES4) { + fallbacks.addFallback(0, "BONES4"); + } + + //Attributes + var attribs = [VertexBuffer.PositionKind]; + + if (this._defines.NORMAL) { + attribs.push(VertexBuffer.NormalKind); + } + + if (this._defines.VERTEXCOLOR) { + attribs.push(VertexBuffer.ColorKind); + } + + if (this._defines.BONES) { + attribs.push(VertexBuffer.MatricesIndicesKind); + attribs.push(VertexBuffer.MatricesWeightsKind); + } + + if (this._defines.INSTANCES) { + attribs.push("world0"); + attribs.push("world1"); + attribs.push("world2"); + attribs.push("world3"); + } + + // Legacy browser patch + var shaderName = "triplanar"; + var join = this._defines.toString(); + this._effect = scene.getEngine().createEffect(shaderName, + attribs, + ["world", "view", "viewProjection", "vEyePosition", "vLightsType", "vDiffuseColor", "vSpecularColor", + "vLightData0", "vLightDiffuse0", "vLightSpecular0", "vLightDirection0", "vLightGround0", "lightMatrix0", + "vLightData1", "vLightDiffuse1", "vLightSpecular1", "vLightDirection1", "vLightGround1", "lightMatrix1", + "vLightData2", "vLightDiffuse2", "vLightSpecular2", "vLightDirection2", "vLightGround2", "lightMatrix2", + "vLightData3", "vLightDiffuse3", "vLightSpecular3", "vLightDirection3", "vLightGround3", "lightMatrix3", + "vFogInfos", "vFogColor", "pointSize", + "mBones", + "vClipPlane", + "shadowsInfo0", "shadowsInfo1", "shadowsInfo2", "shadowsInfo3", + "tileSize" + ], + ["diffuseSamplerX", "diffuseSamplerY", "diffuseSamplerZ", + "normalSamplerX", "normalSamplerY", "normalSamplerZ", + "shadowSampler0", "shadowSampler1", "shadowSampler2", "shadowSampler3" + ], + join, fallbacks, this.onCompiled, this.onError); + } + if (!this._effect.isReady()) { + return false; + } + + this._renderId = scene.getRenderId(); + this._wasPreviouslyReady = true; + + if (mesh) { + if (!mesh._materialDefines) { + mesh._materialDefines = new TriPlanarMaterialDefines(); + } + + this._defines.cloneTo(mesh._materialDefines); + } + + return true; + } + + public bindOnlyWorldMatrix(world: Matrix): void { + this._effect.setMatrix("world", world); + } + + public bind(world: Matrix, mesh?: Mesh): void { + var scene = this.getScene(); + + // Matrices + this.bindOnlyWorldMatrix(world); + this._effect.setMatrix("viewProjection", scene.getTransformMatrix()); + + // Bones + if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) { + this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices()); + } + + this._effect.setFloat("tileSize", this.tileSize); + + if (scene.getCachedMaterial() !== this) { + // Textures + if (this.diffuseTextureX) { + this._effect.setTexture("diffuseSamplerX", this.diffuseTextureX); + } + if (this.diffuseTextureY) { + this._effect.setTexture("diffuseSamplerY", this.diffuseTextureY); + } + if (this.diffuseTextureZ) { + this._effect.setTexture("diffuseSamplerZ", this.diffuseTextureZ); + } + if (this.normalTextureX) { + this._effect.setTexture("normalSamplerX", this.normalTextureX); + } + if (this.normalTextureY) { + this._effect.setTexture("normalSamplerY", this.normalTextureY); + } + if (this.normalTextureZ) { + this._effect.setTexture("normalSamplerZ", this.normalTextureZ); + } + // Clip plane + if (scene.clipPlane) { + var clipPlane = scene.clipPlane; + this._effect.setFloat4("vClipPlane", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d); + } + + // Point size + if (this.pointsCloud) { + this._effect.setFloat("pointSize", this.pointSize); + } + + this._effect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position); + } + + this._effect.setColor4("vDiffuseColor", this._scaledDiffuse, this.alpha * mesh.visibility); + + if (this._defines.SPECULARTERM) { + this._effect.setColor4("vSpecularColor", this.specularColor, this.specularPower); + } + + if (scene.lightsEnabled && !this.disableLighting) { + var lightIndex = 0; + for (var index = 0; index < scene.lights.length; index++) { + var light = scene.lights[index]; + + if (!light.isEnabled()) { + continue; + } + + if (!light.canAffectMesh(mesh)) { + continue; + } + + if (light instanceof PointLight) { + // Point Light + light.transferToEffect(this._effect, "vLightData" + lightIndex); + } else if (light instanceof DirectionalLight) { + // Directional Light + light.transferToEffect(this._effect, "vLightData" + lightIndex); + } else if (light instanceof SpotLight) { + // Spot Light + light.transferToEffect(this._effect, "vLightData" + lightIndex, "vLightDirection" + lightIndex); + } else if (light instanceof HemisphericLight) { + // Hemispheric Light + light.transferToEffect(this._effect, "vLightData" + lightIndex, "vLightGround" + lightIndex); + } + + light.diffuse.scaleToRef(light.intensity, this._scaledDiffuse); + this._effect.setColor4("vLightDiffuse" + lightIndex, this._scaledDiffuse, light.range); + + if (this._defines.SPECULARTERM) { + light.specular.scaleToRef(light.intensity, this._scaledSpecular); + this._effect.setColor3("vLightSpecular" + lightIndex, this._scaledSpecular); + } + + // Shadows + if (scene.shadowsEnabled) { + var shadowGenerator = light.getShadowGenerator(); + if (mesh.receiveShadows && shadowGenerator) { + this._effect.setMatrix("lightMatrix" + lightIndex, shadowGenerator.getTransformMatrix()); + this._effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMapForRendering()); + this._effect.setFloat3("shadowsInfo" + lightIndex, shadowGenerator.getDarkness(), shadowGenerator.getShadowMap().getSize().width, shadowGenerator.bias); + } + } + + lightIndex++; + + if (lightIndex === maxSimultaneousLights) + break; + } + } + + // View + if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) { + this._effect.setMatrix("view", scene.getViewMatrix()); + } + + // Fog + if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) { + this._effect.setFloat4("vFogInfos", scene.fogMode, scene.fogStart, scene.fogEnd, scene.fogDensity); + this._effect.setColor3("vFogColor", scene.fogColor); + } + + super.bind(world, mesh); + } + + public getAnimatables(): IAnimatable[] { + var results = []; + + if (this.mixTexture && this.mixTexture.animations && this.mixTexture.animations.length > 0) { + results.push(this.mixTexture); + } + + return results; + } + + public dispose(forceDisposeEffect?: boolean): void { + if (this.mixTexture) { + this.mixTexture.dispose(); + } + + super.dispose(forceDisposeEffect); + } + + public clone(name: string): TriPlanarMaterial { + var newMaterial = new TriPlanarMaterial(name, this.getScene()); + + // Base material + this.copyTo(newMaterial); + + // Simple material + if (this.mixTexture && this.mixTexture.clone) { + newMaterial.mixTexture = this.mixTexture.clone(); + } + + newMaterial.diffuseColor = this.diffuseColor.clone(); + return newMaterial; + } + + public serialize(): any { + + var serializationObject = super.serialize(); + serializationObject.customType = "BABYLON.TerrainMaterial"; + serializationObject.diffuseColor = this.diffuseColor.asArray(); + serializationObject.specularColor = this.specularColor.asArray(); + serializationObject.specularPower = this.specularPower; + serializationObject.disableLighting = this.disableLighting; + + if (this.diffuseTextureX) { + serializationObject.diffuseTextureX = this.diffuseTextureX.serialize(); + } + + if (this.diffuseTextureY) { + serializationObject.diffuseTextureY = this.diffuseTextureY.serialize(); + } + + if (this.diffuseTextureZ) { + serializationObject.diffuseTextureZ = this.diffuseTextureZ.serialize(); + } + + return serializationObject; + } + + public static Parse(source: any, scene: Scene, rootUrl: string): TriPlanarMaterial { + var material = new TriPlanarMaterial(source.name, scene); + + material.diffuseColor = Color3.FromArray(source.diffuseColor); + material.specularColor = Color3.FromArray(source.specularColor); + material.specularPower = source.specularPower; + material.disableLighting = source.disableLighting; + + material.alpha = source.alpha; + + material.id = source.id; + + Tags.AddTagsTo(material, source.tags); + material.backFaceCulling = source.backFaceCulling; + material.wireframe = source.wireframe; + + if (source.diffuseTextureX) { + material.diffuseTextureX = Texture.Parse(source.diffuseTextureX, scene, rootUrl); + } + + if (source.diffuseTextureY) { + material.diffuseTextureY = Texture.Parse(source.diffuseTextureY, scene, rootUrl); + } + + if (source.diffuseTextureZ) { + material.diffuseTextureZ = Texture.Parse(source.diffuseTextureZ, scene, rootUrl); + } + + return material; + } + } +} + diff --git a/materialsLibrary/materials/triPlanar/triplanar.fragment.fx b/materialsLibrary/materials/triPlanar/triplanar.fragment.fx new file mode 100644 index 00000000000..608d71e8f07 --- /dev/null +++ b/materialsLibrary/materials/triPlanar/triplanar.fragment.fx @@ -0,0 +1,724 @@ +precision highp float; + +// Constants +uniform vec3 vEyePosition; +uniform vec4 vDiffuseColor; + +#ifdef SPECULARTERM +uniform vec4 vSpecularColor; +#endif + +// Input +varying vec3 vPositionW; + +#ifdef VERTEXCOLOR +varying vec4 vColor; +#endif + +// Lights +#ifdef LIGHT0 +uniform vec4 vLightData0; +uniform vec4 vLightDiffuse0; +#ifdef SPECULARTERM +uniform vec3 vLightSpecular0; +#endif +#ifdef SHADOW0 +#if defined(SPOTLIGHT0) || defined(DIRLIGHT0) +varying vec4 vPositionFromLight0; +uniform sampler2D shadowSampler0; +#else +uniform samplerCube shadowSampler0; +#endif +uniform vec3 shadowsInfo0; +#endif +#ifdef SPOTLIGHT0 +uniform vec4 vLightDirection0; +#endif +#ifdef HEMILIGHT0 +uniform vec3 vLightGround0; +#endif +#endif + +#ifdef LIGHT1 +uniform vec4 vLightData1; +uniform vec4 vLightDiffuse1; +#ifdef SPECULARTERM +uniform vec3 vLightSpecular1; +#endif +#ifdef SHADOW1 +#if defined(SPOTLIGHT1) || defined(DIRLIGHT1) +varying vec4 vPositionFromLight1; +uniform sampler2D shadowSampler1; +#else +uniform samplerCube shadowSampler1; +#endif +uniform vec3 shadowsInfo1; +#endif +#ifdef SPOTLIGHT1 +uniform vec4 vLightDirection1; +#endif +#ifdef HEMILIGHT1 +uniform vec3 vLightGround1; +#endif +#endif + +#ifdef LIGHT2 +uniform vec4 vLightData2; +uniform vec4 vLightDiffuse2; +#ifdef SPECULARTERM +uniform vec3 vLightSpecular2; +#endif +#ifdef SHADOW2 +#if defined(SPOTLIGHT2) || defined(DIRLIGHT2) +varying vec4 vPositionFromLight2; +uniform sampler2D shadowSampler2; +#else +uniform samplerCube shadowSampler2; +#endif +uniform vec3 shadowsInfo2; +#endif +#ifdef SPOTLIGHT2 +uniform vec4 vLightDirection2; +#endif +#ifdef HEMILIGHT2 +uniform vec3 vLightGround2; +#endif +#endif + +#ifdef LIGHT3 +uniform vec4 vLightData3; +uniform vec4 vLightDiffuse3; +#ifdef SPECULARTERM +uniform vec3 vLightSpecular3; +#endif +#ifdef SHADOW3 +#if defined(SPOTLIGHT3) || defined(DIRLIGHT3) +varying vec4 vPositionFromLight3; +uniform sampler2D shadowSampler3; +#else +uniform samplerCube shadowSampler3; +#endif +uniform vec3 shadowsInfo3; +#endif +#ifdef SPOTLIGHT3 +uniform vec4 vLightDirection3; +#endif +#ifdef HEMILIGHT3 +uniform vec3 vLightGround3; +#endif +#endif + +// Samplers +#ifdef DIFFUSEX +varying vec2 vTextureUVX; +uniform sampler2D diffuseSamplerX; +#ifdef BUMPX +uniform sampler2D normalSamplerX; +#endif +#endif + +#ifdef DIFFUSEY +varying vec2 vTextureUVY; +uniform sampler2D diffuseSamplerY; +#ifdef BUMPY +uniform sampler2D normalSamplerY; +#endif +#endif + +#ifdef DIFFUSEZ +varying vec2 vTextureUVZ; +uniform sampler2D diffuseSamplerZ; +#ifdef BUMPZ +uniform sampler2D normalSamplerZ; +#endif +#endif + +#ifdef NORMAL +varying mat3 tangentSpace; +#endif + +// Shadows +#ifdef SHADOWS + +float unpack(vec4 color) +{ + const vec4 bit_shift = vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0); + return dot(color, bit_shift); +} + +#if defined(POINTLIGHT0) || defined(POINTLIGHT1) || defined(POINTLIGHT2) || defined(POINTLIGHT3) +float computeShadowCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, float bias) +{ + vec3 directionToLight = vPositionW - lightPosition; + float depth = length(directionToLight); + + depth = clamp(depth, 0., 1.); + + directionToLight.y = 1.0 - directionToLight.y; + + float shadow = unpack(textureCube(shadowSampler, directionToLight)) + bias; + + if (depth > shadow) + { + return darkness; + } + return 1.0; +} + +float computeShadowWithPCFCube(vec3 lightPosition, samplerCube shadowSampler, float mapSize, float bias, float darkness) +{ + vec3 directionToLight = vPositionW - lightPosition; + float depth = length(directionToLight); + float diskScale = (1.0 - (1.0 + depth * 3.0)) / mapSize; + + depth = clamp(depth, 0., 1.); + + directionToLight.y = 1.0 - directionToLight.y; + + float visibility = 1.; + + vec3 poissonDisk[4]; + poissonDisk[0] = vec3(-1.0, 1.0, -1.0); + poissonDisk[1] = vec3(1.0, -1.0, -1.0); + poissonDisk[2] = vec3(-1.0, -1.0, -1.0); + poissonDisk[3] = vec3(1.0, -1.0, 1.0); + + // Poisson Sampling + float biasedDepth = depth - bias; + + if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[0] * diskScale)) < biasedDepth) visibility -= 0.25; + if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[1] * diskScale)) < biasedDepth) visibility -= 0.25; + if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[2] * diskScale)) < biasedDepth) visibility -= 0.25; + if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[3] * diskScale)) < biasedDepth) visibility -= 0.25; + + return min(1.0, visibility + darkness); +} +#endif + +#if defined(SPOTLIGHT0) || defined(SPOTLIGHT1) || defined(SPOTLIGHT2) || defined(SPOTLIGHT3) || defined(DIRLIGHT0) || defined(DIRLIGHT1) || defined(DIRLIGHT2) || defined(DIRLIGHT3) +float computeShadow(vec4 vPositionFromLight, sampler2D shadowSampler, float darkness, float bias) +{ + vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w; + depth = 0.5 * depth + vec3(0.5); + vec2 uv = depth.xy; + + if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0) + { + return 1.0; + } + + float shadow = unpack(texture2D(shadowSampler, uv)) + bias; + + if (depth.z > shadow) + { + return darkness; + } + return 1.; +} + +float computeShadowWithPCF(vec4 vPositionFromLight, sampler2D shadowSampler, float mapSize, float bias, float darkness) +{ + vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w; + depth = 0.5 * depth + vec3(0.5); + vec2 uv = depth.xy; + + if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0) + { + return 1.0; + } + + float visibility = 1.; + + vec2 poissonDisk[4]; + poissonDisk[0] = vec2(-0.94201624, -0.39906216); + poissonDisk[1] = vec2(0.94558609, -0.76890725); + poissonDisk[2] = vec2(-0.094184101, -0.92938870); + poissonDisk[3] = vec2(0.34495938, 0.29387760); + + // Poisson Sampling + float biasedDepth = depth.z - bias; + + if (unpack(texture2D(shadowSampler, uv + poissonDisk[0] / mapSize)) < biasedDepth) visibility -= 0.25; + if (unpack(texture2D(shadowSampler, uv + poissonDisk[1] / mapSize)) < biasedDepth) visibility -= 0.25; + if (unpack(texture2D(shadowSampler, uv + poissonDisk[2] / mapSize)) < biasedDepth) visibility -= 0.25; + if (unpack(texture2D(shadowSampler, uv + poissonDisk[3] / mapSize)) < biasedDepth) visibility -= 0.25; + + return min(1.0, visibility + darkness); +} + +// Thanks to http://devmaster.net/ +float unpackHalf(vec2 color) +{ + return color.x + (color.y / 255.0); +} + +float linstep(float low, float high, float v) { + return clamp((v - low) / (high - low), 0.0, 1.0); +} + +float ChebychevInequality(vec2 moments, float compare, float bias) +{ + float p = smoothstep(compare - bias, compare, moments.x); + float variance = max(moments.y - moments.x * moments.x, 0.02); + float d = compare - moments.x; + float p_max = linstep(0.2, 1.0, variance / (variance + d * d)); + + return clamp(max(p, p_max), 0.0, 1.0); +} + +float computeShadowWithVSM(vec4 vPositionFromLight, sampler2D shadowSampler, float bias, float darkness) +{ + vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w; + depth = 0.5 * depth + vec3(0.5); + vec2 uv = depth.xy; + + if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0 || depth.z >= 1.0) + { + return 1.0; + } + + vec4 texel = texture2D(shadowSampler, uv); + + vec2 moments = vec2(unpackHalf(texel.xy), unpackHalf(texel.zw)); + return min(1.0, 1.0 - ChebychevInequality(moments, depth.z, bias) + darkness); +} +#endif +#endif + + +#ifdef CLIPPLANE +varying float fClipDistance; +#endif + +// Fog +#ifdef FOG + +#define FOGMODE_NONE 0. +#define FOGMODE_EXP 1. +#define FOGMODE_EXP2 2. +#define FOGMODE_LINEAR 3. +#define E 2.71828 + +uniform vec4 vFogInfos; +uniform vec3 vFogColor; +varying float fFogDistance; + +float CalcFogFactor() +{ + float fogCoeff = 1.0; + float fogStart = vFogInfos.y; + float fogEnd = vFogInfos.z; + float fogDensity = vFogInfos.w; + + if (FOGMODE_LINEAR == vFogInfos.x) + { + fogCoeff = (fogEnd - fFogDistance) / (fogEnd - fogStart); + } + else if (FOGMODE_EXP == vFogInfos.x) + { + fogCoeff = 1.0 / pow(E, fFogDistance * fogDensity); + } + else if (FOGMODE_EXP2 == vFogInfos.x) + { + fogCoeff = 1.0 / pow(E, fFogDistance * fFogDistance * fogDensity * fogDensity); + } + + return clamp(fogCoeff, 0.0, 1.0); +} +#endif + +// Bump +#ifdef BUMP +#extension GL_OES_standard_derivatives : enable +// Thanks to http://www.thetenthplanet.de/archives/1180 +mat3 cotangent_frame(vec3 normal, vec3 p, vec2 uv) +{ + // get edge vectors of the pixel triangle + vec3 dp1 = dFdx(p); + vec3 dp2 = dFdy(p); + vec2 duv1 = dFdx(uv); + vec2 duv2 = dFdy(uv); + + // solve the linear system + vec3 dp2perp = cross(dp2, normal); + vec3 dp1perp = cross(normal, dp1); + vec3 tangent = dp2perp * duv1.x + dp1perp * duv2.x; + vec3 binormal = dp2perp * duv1.y + dp1perp * duv2.y; + + // construct a scale-invariant frame + float invmax = inversesqrt(max(dot(tangent, tangent), dot(binormal, binormal))); + return mat3(tangent * invmax, binormal * invmax, normal); +} + +vec3 perturbNormal(vec3 viewDir, vec3 mixColor) +{ + vec3 bump1Color = texture2D(bump1Sampler, vTextureUV * diffuse1Infos).xyz; + vec3 bump2Color = texture2D(bump2Sampler, vTextureUV * diffuse2Infos).xyz; + vec3 bump3Color = texture2D(bump3Sampler, vTextureUV * diffuse3Infos).xyz; + + bump1Color.rgb *= mixColor.r; + bump2Color.rgb = mix(bump1Color.rgb, bump2Color.rgb, mixColor.g); + vec3 map = mix(bump2Color.rgb, bump3Color.rgb, mixColor.b); + + map = map * 255. / 127. - 128. / 127.; + mat3 TBN = cotangent_frame(vNormalW * vTextureInfos.y, -viewDir, vTextureUV); + return normalize(TBN * map); +} +#endif + +// Light Computing +struct lightingInfo +{ + vec3 diffuse; +#ifdef SPECULARTERM + vec3 specular; +#endif +}; + +lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, float range, float glossiness) { + lightingInfo result; + + vec3 lightVectorW; + float attenuation = 1.0; + if (lightData.w == 0.) + { + vec3 direction = lightData.xyz - vPositionW; + + attenuation = max(0., 1.0 - length(direction) / range); + lightVectorW = normalize(direction); + } + else + { + lightVectorW = normalize(-lightData.xyz); + } + + // diffuse + float ndl = max(0., dot(vNormal, lightVectorW)); + result.diffuse = ndl * diffuseColor * attenuation; + +#ifdef SPECULARTERM + // Specular + vec3 angleW = normalize(viewDirectionW + lightVectorW); + float specComp = max(0., dot(vNormal, angleW)); + specComp = pow(specComp, max(1., glossiness)); + + result.specular = specComp * specularColor * attenuation; +#endif + return result; +} + +lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor, float range, float glossiness) { + lightingInfo result; + + vec3 direction = lightData.xyz - vPositionW; + vec3 lightVectorW = normalize(direction); + float attenuation = max(0., 1.0 - length(direction) / range); + + // diffuse + float cosAngle = max(0., dot(-lightDirection.xyz, lightVectorW)); + float spotAtten = 0.0; + + if (cosAngle >= lightDirection.w) + { + cosAngle = max(0., pow(cosAngle, lightData.w)); + spotAtten = clamp((cosAngle - lightDirection.w) / (1. - cosAngle), 0.0, 1.0); + + // Diffuse + float ndl = max(0., dot(vNormal, -lightDirection.xyz)); + result.diffuse = ndl * spotAtten * diffuseColor * attenuation; + +#ifdef SPECULARTERM + // Specular + vec3 angleW = normalize(viewDirectionW - lightDirection.xyz); + float specComp = max(0., dot(vNormal, angleW)); + specComp = pow(specComp, max(1., glossiness)); + + result.specular = specComp * specularColor * spotAtten * attenuation; +#endif + + return result; + } + + result.diffuse = vec3(0.); +#ifdef SPECULARTERM + result.specular = vec3(0.); +#endif + + return result; +} + +lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, vec3 groundColor, float glossiness) { + lightingInfo result; + + // Diffuse + float ndl = dot(vNormal, lightData.xyz) * 0.5 + 0.5; + result.diffuse = mix(groundColor, diffuseColor, ndl); + +#ifdef SPECULARTERM + // Specular + vec3 angleW = normalize(viewDirectionW + lightData.xyz); + float specComp = max(0., dot(vNormal, angleW)); + specComp = pow(specComp, max(1., glossiness)); + + result.specular = specComp * specularColor; +#endif + + return result; +} + +void main(void) { + // Clip plane +#ifdef CLIPPLANE + if (fClipDistance > 0.0) + discard; +#endif + + vec3 viewDirectionW = normalize(vEyePosition - vPositionW); + + // Base color + vec4 baseColor = vec4(0., 0., 0., 1.); + vec3 diffuseColor = vDiffuseColor.rgb; + +#ifdef SPECULARTERM + float glossiness = vSpecularColor.a; + vec3 specularColor = vSpecularColor.rgb; +#else + float glossiness = 0.; +#endif + + // Alpha + float alpha = vDiffuseColor.a; + + // Bump +#ifdef NORMAL + vec3 normalW = tangentSpace[2]; +#else + vec3 normalW = vec3(1.0, 1.0, 1.0); +#endif + + vec4 baseNormal = vec4(0.0, 0.0, 0.0, 1.0); + normalW *= normalW; + +#ifdef DIFFUSEX + baseColor += texture2D(diffuseSamplerX, vTextureUVX) * normalW.x; +#ifdef BUMPX + baseNormal += texture2D(normalSamplerX, vTextureUVX) * normalW.x; +#endif +#endif + +#ifdef DIFFUSEY + baseColor += texture2D(diffuseSamplerY, vTextureUVY) * normalW.y; +#ifdef BUMPY + baseNormal += texture2D(normalSamplerY, vTextureUVY) * normalW.y; +#endif +#endif + +#ifdef DIFFUSEZ + baseColor += texture2D(diffuseSamplerZ, vTextureUVZ) * normalW.z; +#ifdef BUMPZ + baseNormal += texture2D(normalSamplerZ, vTextureUVZ) * normalW.z; +#endif +#endif + +#ifdef NORMAL + normalW = normalize((2.0 * baseNormal.xyz - 1.0) * tangentSpace); +#endif + +#ifdef ALPHATEST + if (baseColor.a < 0.4) + discard; +#endif + +#ifdef VERTEXCOLOR + baseColor.rgb *= vColor.rgb; +#endif + + // Lighting + vec3 diffuseBase = vec3(0., 0., 0.); +#ifdef SPECULARTERM + vec3 specularBase = vec3(0., 0., 0.); +#endif + float shadow = 1.; + +#ifdef LIGHT0 +#ifndef SPECULARTERM + vec3 vLightSpecular0 = vec3(0.0); +#endif +#ifdef SPOTLIGHT0 + lightingInfo info = computeSpotLighting(viewDirectionW, normalW, vLightData0, vLightDirection0, vLightDiffuse0.rgb, vLightSpecular0, vLightDiffuse0.a, glossiness); +#endif +#ifdef HEMILIGHT0 + lightingInfo info = computeHemisphericLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0.rgb, vLightSpecular0, vLightGround0, glossiness); +#endif +#if defined(POINTLIGHT0) || defined(DIRLIGHT0) + lightingInfo info = computeLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0.rgb, vLightSpecular0, vLightDiffuse0.a, glossiness); +#endif +#ifdef SHADOW0 +#ifdef SHADOWVSM0 + shadow = computeShadowWithVSM(vPositionFromLight0, shadowSampler0, shadowsInfo0.z, shadowsInfo0.x); +#else +#ifdef SHADOWPCF0 +#if defined(POINTLIGHT0) + shadow = computeShadowWithPCFCube(vLightData0.xyz, shadowSampler0, shadowsInfo0.y, shadowsInfo0.z, shadowsInfo0.x); +#else + shadow = computeShadowWithPCF(vPositionFromLight0, shadowSampler0, shadowsInfo0.y, shadowsInfo0.z, shadowsInfo0.x); +#endif +#else +#if defined(POINTLIGHT0) + shadow = computeShadowCube(vLightData0.xyz, shadowSampler0, shadowsInfo0.x, shadowsInfo0.z); +#else + shadow = computeShadow(vPositionFromLight0, shadowSampler0, shadowsInfo0.x, shadowsInfo0.z); +#endif +#endif +#endif +#else + shadow = 1.; +#endif + diffuseBase += info.diffuse * shadow; +#ifdef SPECULARTERM + specularBase += info.specular * shadow; +#endif +#endif + +#ifdef LIGHT1 +#ifndef SPECULARTERM + vec3 vLightSpecular1 = vec3(0.0); +#endif +#ifdef SPOTLIGHT1 + info = computeSpotLighting(viewDirectionW, normalW, vLightData1, vLightDirection1, vLightDiffuse1.rgb, vLightSpecular1, vLightDiffuse1.a, glossiness); +#endif +#ifdef HEMILIGHT1 + info = computeHemisphericLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1.rgb, vLightSpecular1, vLightGround1, glossiness); +#endif +#if defined(POINTLIGHT1) || defined(DIRLIGHT1) + info = computeLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1.rgb, vLightSpecular1, vLightDiffuse1.a, glossiness); +#endif +#ifdef SHADOW1 +#ifdef SHADOWVSM1 + shadow = computeShadowWithVSM(vPositionFromLight1, shadowSampler1, shadowsInfo1.z, shadowsInfo1.x); +#else +#ifdef SHADOWPCF1 +#if defined(POINTLIGHT1) + shadow = computeShadowWithPCFCube(vLightData1.xyz, shadowSampler1, shadowsInfo1.y, shadowsInfo1.z, shadowsInfo1.x); +#else + shadow = computeShadowWithPCF(vPositionFromLight1, shadowSampler1, shadowsInfo1.y, shadowsInfo1.z, shadowsInfo1.x); +#endif +#else +#if defined(POINTLIGHT1) + shadow = computeShadowCube(vLightData1.xyz, shadowSampler1, shadowsInfo1.x, shadowsInfo1.z); +#else + shadow = computeShadow(vPositionFromLight1, shadowSampler1, shadowsInfo1.x, shadowsInfo1.z); +#endif +#endif +#endif +#else + shadow = 1.; +#endif + diffuseBase += info.diffuse * shadow; +#ifdef SPECULARTERM + specularBase += info.specular * shadow; +#endif +#endif + +#ifdef LIGHT2 +#ifndef SPECULARTERM + vec3 vLightSpecular2 = vec3(0.0); +#endif +#ifdef SPOTLIGHT2 + info = computeSpotLighting(viewDirectionW, normalW, vLightData2, vLightDirection2, vLightDiffuse2.rgb, vLightSpecular2, vLightDiffuse2.a, glossiness); +#endif +#ifdef HEMILIGHT2 + info = computeHemisphericLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2.rgb, vLightSpecular2, vLightGround2, glossiness); +#endif +#if defined(POINTLIGHT2) || defined(DIRLIGHT2) + info = computeLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2.rgb, vLightSpecular2, vLightDiffuse2.a, glossiness); +#endif +#ifdef SHADOW2 +#ifdef SHADOWVSM2 + shadow = computeShadowWithVSM(vPositionFromLight2, shadowSampler2, shadowsInfo2.z, shadowsInfo2.x); +#else +#ifdef SHADOWPCF2 +#if defined(POINTLIGHT2) + shadow = computeShadowWithPCFCube(vLightData2.xyz, shadowSampler2, shadowsInfo2.y, shadowsInfo2.z, shadowsInfo2.x); +#else + shadow = computeShadowWithPCF(vPositionFromLight2, shadowSampler2, shadowsInfo2.y, shadowsInfo2.z, shadowsInfo2.x); +#endif +#else +#if defined(POINTLIGHT2) + shadow = computeShadowCube(vLightData2.xyz, shadowSampler2, shadowsInfo2.x, shadowsInfo2.z); +#else + shadow = computeShadow(vPositionFromLight2, shadowSampler2, shadowsInfo2.x, shadowsInfo2.z); +#endif +#endif +#endif +#else + shadow = 1.; +#endif + diffuseBase += info.diffuse * shadow; +#ifdef SPECULARTERM + specularBase += info.specular * shadow; +#endif +#endif + +#ifdef LIGHT3 +#ifndef SPECULARTERM + vec3 vLightSpecular3 = vec3(0.0); +#endif +#ifdef SPOTLIGHT3 + info = computeSpotLighting(viewDirectionW, normalW, vLightData3, vLightDirection3, vLightDiffuse3.rgb, vLightSpecular3, vLightDiffuse3.a, glossiness); +#endif +#ifdef HEMILIGHT3 + info = computeHemisphericLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3.rgb, vLightSpecular3, vLightGround3, glossiness); +#endif +#if defined(POINTLIGHT3) || defined(DIRLIGHT3) + info = computeLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3.rgb, vLightSpecular3, vLightDiffuse3.a, glossiness); +#endif +#ifdef SHADOW3 +#ifdef SHADOWVSM3 + shadow = computeShadowWithVSM(vPositionFromLight3, shadowSampler3, shadowsInfo3.z, shadowsInfo3.x); +#else +#ifdef SHADOWPCF3 +#if defined(POINTLIGHT3) + shadow = computeShadowWithPCFCube(vLightData3.xyz, shadowSampler3, shadowsInfo3.y, shadowsInfo3.z, shadowsInfo3.x); +#else + shadow = computeShadowWithPCF(vPositionFromLight3, shadowSampler3, shadowsInfo3.y, shadowsInfo3.z, shadowsInfo3.x); +#endif +#else +#if defined(POINTLIGHT3) + shadow = computeShadowCube(vLightData3.xyz, shadowSampler3, shadowsInfo3.x, shadowsInfo3.z); +#else + shadow = computeShadow(vPositionFromLight3, shadowSampler3, shadowsInfo3.x, shadowsInfo3.z); +#endif +#endif +#endif +#else + shadow = 1.; +#endif + diffuseBase += info.diffuse * shadow; +#ifdef SPECULARTERM + specularBase += info.specular * shadow; +#endif +#endif + +#ifdef VERTEXALPHA + alpha *= vColor.a; +#endif + +#ifdef SPECULARTERM + vec3 finalSpecular = specularBase * specularColor; +#else + vec3 finalSpecular = vec3(0.0); +#endif + + vec3 finalDiffuse = clamp(diffuseBase * diffuseColor, 0.0, 1.0) * baseColor.rgb; + + // Composition + vec4 color = vec4(finalDiffuse + finalSpecular, alpha); + +#ifdef FOG + float fog = CalcFogFactor(); + color.rgb = fog * color.rgb + (1.0 - fog) * vFogColor; +#endif + + gl_FragColor = color; +} diff --git a/materialsLibrary/materials/triPlanar/triplanar.vertex.fx b/materialsLibrary/materials/triPlanar/triplanar.vertex.fx new file mode 100644 index 00000000000..374c2b82600 --- /dev/null +++ b/materialsLibrary/materials/triPlanar/triplanar.vertex.fx @@ -0,0 +1,190 @@ +precision highp float; + +// Attributes +attribute vec3 position; +#ifdef NORMAL +attribute vec3 normal; +#endif +#ifdef VERTEXCOLOR +attribute vec4 color; +#endif +#ifdef BONES +attribute vec4 matricesIndices; +attribute vec4 matricesWeights; +#endif + +// Uniforms + +#ifdef INSTANCES +attribute vec4 world0; +attribute vec4 world1; +attribute vec4 world2; +attribute vec4 world3; +#else +uniform mat4 world; +#endif + +uniform mat4 view; +uniform mat4 viewProjection; + +#ifdef DIFFUSEX +varying vec2 vTextureUVX; +#endif + +#ifdef DIFFUSEY +varying vec2 vTextureUVY; +#endif + +#ifdef DIFFUSEZ +varying vec2 vTextureUVZ; +#endif + +uniform float tileSize; + +#ifdef BONES +uniform mat4 mBones[BonesPerMesh]; +#endif + +#ifdef POINTSIZE +uniform float pointSize; +#endif + +// Output +varying vec3 vPositionW; +#ifdef NORMAL +varying mat3 tangentSpace; +#endif + +#ifdef VERTEXCOLOR +varying vec4 vColor; +#endif + +#ifdef CLIPPLANE +uniform vec4 vClipPlane; +varying float fClipDistance; +#endif + +#ifdef FOG +varying float fFogDistance; +#endif + +#ifdef SHADOWS +#if defined(SPOTLIGHT0) || defined(DIRLIGHT0) +uniform mat4 lightMatrix0; +varying vec4 vPositionFromLight0; +#endif +#if defined(SPOTLIGHT1) || defined(DIRLIGHT1) +uniform mat4 lightMatrix1; +varying vec4 vPositionFromLight1; +#endif +#if defined(SPOTLIGHT2) || defined(DIRLIGHT2) +uniform mat4 lightMatrix2; +varying vec4 vPositionFromLight2; +#endif +#if defined(SPOTLIGHT3) || defined(DIRLIGHT3) +uniform mat4 lightMatrix3; +varying vec4 vPositionFromLight3; +#endif +#endif + +void main(void) { + mat4 finalWorld; + +#ifdef INSTANCES + finalWorld = mat4(world0, world1, world2, world3); +#else + finalWorld = world; +#endif + +#ifdef BONES + mat4 m0 = mBones[int(matricesIndices.x)] * matricesWeights.x; + mat4 m1 = mBones[int(matricesIndices.y)] * matricesWeights.y; + mat4 m2 = mBones[int(matricesIndices.z)] * matricesWeights.z; + +#ifdef BONES4 + mat4 m3 = mBones[int(matricesIndices.w)] * matricesWeights.w; + finalWorld = finalWorld * (m0 + m1 + m2 + m3); +#else + finalWorld = finalWorld * (m0 + m1 + m2); +#endif + +#endif + gl_Position = viewProjection * finalWorld * vec4(position, 1.0); + + vec4 worldPos = finalWorld * vec4(position, 1.0); + vPositionW = vec3(worldPos); + +#ifdef DIFFUSEX + vTextureUVX = worldPos.zy / tileSize; +#endif + +#ifdef DIFFUSEY + vTextureUVY = worldPos.xz / tileSize; +#endif + +#ifdef DIFFUSEZ + vTextureUVZ = worldPos.xy / tileSize; +#endif + +#ifdef NORMAL + // Compute tangent space (used for normal mapping + tri planar color mapping) + vec3 xtan = vec3(0,0,1);//tangent space for the X aligned plane + vec3 xbin = vec3(0,1,0); + + vec3 ytan = vec3(1,0,0);//tangent space for the Y aligned plane + vec3 ybin = vec3(0,0,1); + + vec3 ztan = vec3(1,0,0);//tangent space for the Z aligned plane + vec3 zbin = vec3(0,1,0); + + vec3 normalizedNormal = normalize(normal); + normalizedNormal *= normalizedNormal; + + vec3 worldBinormal = normalize(xbin * normalizedNormal.x + ybin * normalizedNormal.y + zbin * normalizedNormal.z); + vec3 worldTangent = normalize(xtan * normalizedNormal.x + ytan * normalizedNormal.y + ztan * normalizedNormal.z); + + worldTangent = (world * vec4(worldTangent, 1.0)).xyz; + worldBinormal = (world * vec4(worldBinormal, 1.0)).xyz; + vec3 worldNormal = normalize(cross(worldTangent, worldBinormal)); + + tangentSpace[0] = worldTangent; + tangentSpace[1] = worldBinormal; + tangentSpace[2] = worldNormal; +#endif + + // Clip plane +#ifdef CLIPPLANE + fClipDistance = dot(worldPos, vClipPlane); +#endif + + // Fog +#ifdef FOG + fFogDistance = (view * worldPos).z; +#endif + + // Shadows +#ifdef SHADOWS +#if defined(SPOTLIGHT0) || defined(DIRLIGHT0) + vPositionFromLight0 = lightMatrix0 * worldPos; +#endif +#if defined(SPOTLIGHT1) || defined(DIRLIGHT1) + vPositionFromLight1 = lightMatrix1 * worldPos; +#endif +#if defined(SPOTLIGHT2) || defined(DIRLIGHT2) + vPositionFromLight2 = lightMatrix2 * worldPos; +#endif +#if defined(SPOTLIGHT3) || defined(DIRLIGHT3) + vPositionFromLight3 = lightMatrix3 * worldPos; +#endif +#endif + + // Vertex color +#ifdef VERTEXCOLOR + vColor = color; +#endif + + // Point size +#ifdef POINTSIZE + gl_PointSize = pointSize; +#endif +} diff --git a/materialsLibrary/test/add/addtriplanar.js b/materialsLibrary/test/add/addtriplanar.js new file mode 100644 index 00000000000..25ded29a6e1 --- /dev/null +++ b/materialsLibrary/test/add/addtriplanar.js @@ -0,0 +1,19 @@ +window.prepareTriPlanar = function() { + var triPlanar = new BABYLON.TriPlanarMaterial("triplanar", scene); + triPlanar.diffuseTextureX = new BABYLON.Texture("textures/rock.png", scene); + triPlanar.diffuseTextureY = new BABYLON.Texture("textures/grass.png", scene); + triPlanar.diffuseTextureZ = triPlanar.diffuseTextureX; + triPlanar.normalTextureX = new BABYLON.Texture("textures/rockn.png", scene); + triPlanar.normalTextureY = new BABYLON.Texture("textures/grassn.png", scene); + triPlanar.normalTextureZ = triPlanar.normalTextureX; + triPlanar.specularPower = 64; + triPlanar.tileSize = 2.5; + + registerRangeUI("triPlanar", "tileSize", 0, 20, function(value) { + triPlanar.tileSize = value; + }, function() { + return triPlanar.tileSize; + }); + + return triPlanar; +}; \ No newline at end of file diff --git a/materialsLibrary/test/index.html b/materialsLibrary/test/index.html index 29212dea04f..e67cc664434 100644 --- a/materialsLibrary/test/index.html +++ b/materialsLibrary/test/index.html @@ -12,6 +12,7 @@ +