diff --git a/jme3-core/src/main/java/com/jme3/material/Material.java b/jme3-core/src/main/java/com/jme3/material/Material.java index 20fcd1e9a..489139ef5 100644 --- a/jme3-core/src/main/java/com/jme3/material/Material.java +++ b/jme3-core/src/main/java/com/jme3/material/Material.java @@ -42,7 +42,6 @@ import com.jme3.material.TechniqueDef.LightMode; import com.jme3.material.TechniqueDef.ShadowMode; import com.jme3.math.*; import com.jme3.renderer.Caps; -import com.jme3.renderer.GL1Renderer; import com.jme3.renderer.RenderManager; import com.jme3.renderer.Renderer; import com.jme3.renderer.RendererException; @@ -52,7 +51,6 @@ import com.jme3.scene.Mesh; import com.jme3.scene.instancing.InstancedGeometry; import com.jme3.shader.Shader; import com.jme3.shader.Uniform; -import com.jme3.shader.UniformBindingManager; import com.jme3.shader.VarType; import com.jme3.texture.Texture; import com.jme3.texture.image.ColorSpace; @@ -697,12 +695,15 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { setParam(name, VarType.Vector4, value); } - private ColorRGBA getAmbientColor(LightList lightList) { + private ColorRGBA getAmbientColor(LightList lightList, boolean removeLights) { ambientLightColor.set(0, 0, 0, 1); for (int j = 0; j < lightList.size(); j++) { Light l = lightList.get(j); if (l instanceof AmbientLight) { ambientLightColor.addLocal(l.getColor()); + if(removeLights){ + lightList.remove(l); + } } } ambientLightColor.a = 1.0f; @@ -741,75 +742,106 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { * g_LightPosition.w is the inverse radius (1/r) of the light (for * attenuation)

*/ - protected void updateLightListUniforms(Shader shader, Geometry g, LightList lightList, int numLights) { + protected int updateLightListUniforms(Shader shader, Geometry g, LightList lightList, int numLights, RenderManager rm, int startIndex) { if (numLights == 0) { // this shader does not do lighting, ignore. - return; + return 0; } - Uniform lightColor = shader.getUniform("g_LightColor"); - Uniform lightPos = shader.getUniform("g_LightPosition"); - Uniform lightDir = shader.getUniform("g_LightDirection"); - lightColor.setVector4Length(numLights); - lightPos.setVector4Length(numLights); - lightDir.setVector4Length(numLights); - + Uniform lightData = shader.getUniform("g_LightData"); + lightData.setVector4Length(numLights * 3);//8 lights * max 3 Uniform ambientColor = shader.getUniform("g_AmbientLightColor"); - ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList)); - - int lightIndex = 0; + - for (int i = 0; i < numLights; i++) { - if (lightList.size() <= i) { - lightColor.setVector4InArray(0f, 0f, 0f, 0f, lightIndex); - lightPos.setVector4InArray(0f, 0f, 0f, 0f, lightIndex); - } else { - Light l = lightList.get(i); + if (startIndex != 0) { + // apply additive blending for 2nd and future passes + rm.getRenderer().applyRenderState(additiveLight); + ambientColor.setValue(VarType.Vector4, ColorRGBA.Black); + }else{ + ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList,true)); + } + + int lightDataIndex = 0; + TempVars vars = TempVars.get(); + Vector4f tmpVec = vars.vect4f1; + int curIndex; + int endIndex = numLights + startIndex; + for (curIndex = startIndex; curIndex < endIndex && curIndex < lightList.size(); curIndex++) { + + + Light l = lightList.get(curIndex); + if(l.getType() == Light.Type.Ambient){ + endIndex++; + continue; + } ColorRGBA color = l.getColor(); - lightColor.setVector4InArray(color.getRed(), + //Color + lightData.setVector4InArray(color.getRed(), color.getGreen(), color.getBlue(), l.getType().getId(), - i); - + lightDataIndex); + lightDataIndex++; + switch (l.getType()) { case Directional: DirectionalLight dl = (DirectionalLight) l; - Vector3f dir = dl.getDirection(); - lightPos.setVector4InArray(dir.getX(), dir.getY(), dir.getZ(), -1, lightIndex); + Vector3f dir = dl.getDirection(); + //Data directly sent in view space to avoid a matrix mult for each pixel + tmpVec.set(dir.getX(), dir.getY(), dir.getZ(), 0.0f); + rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); +// tmpVec.divideLocal(tmpVec.w); +// tmpVec.normalizeLocal(); + lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), -1, lightDataIndex); + lightDataIndex++; + //PADDING + lightData.setVector4InArray(0,0,0,0, lightDataIndex); + lightDataIndex++; break; case Point: PointLight pl = (PointLight) l; Vector3f pos = pl.getPosition(); float invRadius = pl.getInvRadius(); - lightPos.setVector4InArray(pos.getX(), pos.getY(), pos.getZ(), invRadius, lightIndex); + tmpVec.set(pos.getX(), pos.getY(), pos.getZ(), 1.0f); + rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); + //tmpVec.divideLocal(tmpVec.w); + lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRadius, lightDataIndex); + lightDataIndex++; + //PADDING + lightData.setVector4InArray(0,0,0,0, lightDataIndex); + lightDataIndex++; break; - case Spot: + case Spot: SpotLight sl = (SpotLight) l; Vector3f pos2 = sl.getPosition(); Vector3f dir2 = sl.getDirection(); float invRange = sl.getInvSpotRange(); float spotAngleCos = sl.getPackedAngleCos(); - - lightPos.setVector4InArray(pos2.getX(), pos2.getY(), pos2.getZ(), invRange, lightIndex); - lightDir.setVector4InArray(dir2.getX(), dir2.getY(), dir2.getZ(), spotAngleCos, lightIndex); - break; - case Ambient: - // skip this light. Does not increase lightIndex - continue; + tmpVec.set(pos2.getX(), pos2.getY(), pos2.getZ(), 1.0f); + rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); + // tmpVec.divideLocal(tmpVec.w); + lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRange, lightDataIndex); + lightDataIndex++; + + //We transform the spot direction in view space here to save 5 varying later in the lighting shader + //one vec4 less and a vec4 that becomes a vec3 + //the downside is that spotAngleCos decoding happens now in the frag shader. + tmpVec.set(dir2.getX(), dir2.getY(), dir2.getZ(), 0.0f); + rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); + tmpVec.normalizeLocal(); + lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), spotAngleCos, lightDataIndex); + lightDataIndex++; + break; default: throw new UnsupportedOperationException("Unknown type of light: " + l.getType()); } - } - - lightIndex++; - } - - while (lightIndex < numLights) { - lightColor.setVector4InArray(0f, 0f, 0f, 0f, lightIndex); - lightPos.setVector4InArray(0f, 0f, 0f, 0f, lightIndex); - - lightIndex++; } + vars.release(); + //Padding of unsued buffer space + while(lightDataIndex < numLights * 3) { + lightData.setVector4InArray(0f, 0f, 0f, 0f, lightDataIndex); + lightDataIndex++; + } + return curIndex; } protected void renderMultipassLighting(Shader shader, Geometry g, LightList lightList, RenderManager rm) { @@ -830,7 +862,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { if (isFirstLight) { // set ambient color for first light only - ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList)); + ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, false)); isFirstLight = false; isSecondLight = true; } else if (isSecondLight) { @@ -885,9 +917,9 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { tmpLightPosition.set(pos2.getX(), pos2.getY(), pos2.getZ(), invRange); lightPos.setValue(VarType.Vector4, tmpLightPosition); - //We transform the spot directoin in view space here to save 5 varying later in the lighting shader + //We transform the spot direction in view space here to save 5 varying later in the lighting shader //one vec4 less and a vec4 that becomes a vec3 - //the downside is that spotAngleCos decoding happen now in the frag shader. + //the downside is that spotAngleCos decoding happens now in the frag shader. tmpVec.set(dir2.getX(), dir2.getY(), dir2.getZ(), 0); rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); tmpLightDirection.set(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), spotAngleCos); @@ -906,7 +938,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { if (isFirstLight && lightList.size() > 0) { // There are only ambient lights in the scene. Render // a dummy "normal light" so we can see the ambient - ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList)); + ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, false)); lightColor.setValue(VarType.Vector4, ColorRGBA.BlackNoAlpha); lightPos.setValue(VarType.Vector4, nullDirLight); r.setShader(shader); @@ -955,9 +987,12 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { for (TechniqueDef techDef : techDefs) { if (rendererCaps.containsAll(techDef.getRequiredCaps())) { // use the first one that supports all the caps - tech = new Technique(this, techDef); + tech = new Technique(this, techDef); techniques.put(name, tech); - break; + if(tech.getDef().getLightMode() == renderManager.getPreferredLightMode() || + tech.getDef().getLightMode() == LightMode.Disable){ + break; + } } lastTech = techDef; } @@ -990,7 +1025,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { } technique = tech; - tech.makeCurrent(def.getAssetManager(), true, rendererCaps); + tech.makeCurrent(def.getAssetManager(), true, rendererCaps, renderManager); // shader was changed sortingId = -1; @@ -1000,7 +1035,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { if (technique == null) { selectTechnique("Default", rm); } else { - technique.makeCurrent(def.getAssetManager(), false, rm.getRenderer().getCaps()); + technique.makeCurrent(def.getAssetManager(), false, rm.getRenderer().getCaps(), rm); } } @@ -1162,8 +1197,14 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { r.setLighting(null); break; case SinglePass: - updateLightListUniforms(shader, geom, lights, 4); - break; + int nbRenderedLights = 0; + resetUniformsNotSetByCurrent(shader); + while(nbRenderedLights < lights.size()){ + nbRenderedLights = updateLightListUniforms(shader, geom, lights, rm.getSinglePassLightBatchSize(), rm, nbRenderedLights); + r.setShader(shader); + renderMeshFromGeometry(r, geom); + } + return; case FixedPipeline: r.setLighting(lights); break; diff --git a/jme3-core/src/main/java/com/jme3/material/Technique.java b/jme3-core/src/main/java/com/jme3/material/Technique.java index b99cbc3bb..024311551 100644 --- a/jme3-core/src/main/java/com/jme3/material/Technique.java +++ b/jme3-core/src/main/java/com/jme3/material/Technique.java @@ -33,8 +33,8 @@ package com.jme3.material; import com.jme3.asset.AssetManager; import com.jme3.renderer.Caps; +import com.jme3.renderer.RenderManager; import com.jme3.shader.*; -import com.jme3.util.ListMap; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; @@ -172,7 +172,7 @@ public class Technique /* implements Savable */ { * * @param assetManager The asset manager to use for loading shaders. */ - public void makeCurrent(AssetManager assetManager, boolean techniqueSwitched, EnumSet rendererCaps) { + public void makeCurrent(AssetManager assetManager, boolean techniqueSwitched, EnumSet rendererCaps, RenderManager rm) { if (!def.isUsingShaders()) { // No shaders are used, no processing is neccessary. return; @@ -182,6 +182,13 @@ public class Technique /* implements Savable */ { if (defines.update(owner.getParamsMap(), def)) { needReload = true; } + if(getDef().getLightMode()== TechniqueDef.LightMode.SinglePass){ + defines.set("SINGLE_PASS_LIGHTING", VarType.Boolean, true); + defines.set("NB_LIGHTS", VarType.Int, rm.getSinglePassLightBatchSize()*3 ); + }else{ + defines.set("SINGLE_PASS_LIGHTING", VarType.Boolean, null); + } + } if (needReload) { diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java index b8aa705fb..592ecf3cf 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -38,6 +38,7 @@ import com.jme3.material.Material; import com.jme3.material.MaterialDef; import com.jme3.material.RenderState; import com.jme3.material.Technique; +import com.jme3.material.TechniqueDef; import com.jme3.math.*; import com.jme3.post.SceneProcessor; import com.jme3.profile.AppProfiler; @@ -89,6 +90,8 @@ public class RenderManager { private boolean handleTranlucentBucket = true; private AppProfiler prof; private LightFilter lightFilter = new DefaultLightFilter(); + private TechniqueDef.LightMode preferredLightMode = TechniqueDef.LightMode.MultiPass; + private int singlePassLightBatchSize = 1; /** * Create a high-level rendering interface over the @@ -780,6 +783,33 @@ public class RenderManager { vp.getQueue().clear(); } + /** + * Sets the light filter to use when rendering Lighted Geometries + * + * @see LightFilter + * @param lightFilter The light filter tose. Set it to null if you want all lights to be rendered + */ + public void setLightFilter(LightFilter lightFilter) { + this.lightFilter = lightFilter; + } + + public void setPreferredLightMode(TechniqueDef.LightMode preferredLightMode) { + this.preferredLightMode = preferredLightMode; + } + + public TechniqueDef.LightMode getPreferredLightMode() { + return preferredLightMode; + } + + public int getSinglePassLightBatchSize() { + return singlePassLightBatchSize; + } + + public void setSinglePassLightBatchSize(int singlePassLightBatchSize) { + this.singlePassLightBatchSize = singlePassLightBatchSize; + } + + /** * Render the given viewport queues. *

diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag index e4773c8cf..370c62bc9 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag @@ -1,7 +1,9 @@ #import "Common/ShaderLib/Parallax.glsllib" #import "Common/ShaderLib/Optics.glsllib" -#define ATTENUATION -//#define HQ_ATTENUATION +#ifndef VERTEX_LIGHTING + #import "Common/ShaderLib/PhongLighting.glsllib" + #import "Common/ShaderLib/Lighting.glsllib" +#endif varying vec2 texCoord; #ifdef SEPARATE_TEXCOORD @@ -58,82 +60,14 @@ varying vec3 SpecularSum; uniform float m_AlphaDiscardThreshold; #ifndef VERTEX_LIGHTING -uniform float m_Shininess; - -#ifdef HQ_ATTENUATION -uniform vec4 g_LightPosition; -#endif - -#ifdef USE_REFLECTION - uniform float m_ReflectionPower; - uniform float m_ReflectionIntensity; - varying vec4 refVec; - - uniform ENVMAP m_EnvMap; -#endif - -float tangDot(in vec3 v1, in vec3 v2){ - float d = dot(v1,v2); - #ifdef V_TANGENT - d = 1.0 - d*d; - return step(0.0, d) * sqrt(d); - #else - return d; - #endif -} - -float lightComputeDiffuse(in vec3 norm, in vec3 lightdir, in vec3 viewdir){ - #ifdef MINNAERT - float NdotL = max(0.0, dot(norm, lightdir)); - float NdotV = max(0.0, dot(norm, viewdir)); - return NdotL * pow(max(NdotL * NdotV, 0.1), -1.0) * 0.5; - #else - return max(0.0, dot(norm, lightdir)); - #endif -} + uniform float m_Shininess; + #ifdef USE_REFLECTION + uniform float m_ReflectionPower; + uniform float m_ReflectionIntensity; + varying vec4 refVec; -float lightComputeSpecular(in vec3 norm, in vec3 viewdir, in vec3 lightdir, in float shiny){ - // NOTE: check for shiny <= 1 removed since shininess is now - // 1.0 by default (uses matdefs default vals) - #ifdef LOW_QUALITY - // Blinn-Phong - // Note: preferably, H should be computed in the vertex shader - vec3 H = (viewdir + lightdir) * vec3(0.5); - return pow(max(tangDot(H, norm), 0.0), shiny); - #elif defined(WARDISO) - // Isotropic Ward - vec3 halfVec = normalize(viewdir + lightdir); - float NdotH = max(0.001, tangDot(norm, halfVec)); - float NdotV = max(0.001, tangDot(norm, viewdir)); - float NdotL = max(0.001, tangDot(norm, lightdir)); - float a = tan(acos(NdotH)); - float p = max(shiny/128.0, 0.001); - return NdotL * (1.0 / (4.0*3.14159265*p*p)) * (exp(-(a*a)/(p*p)) / (sqrt(NdotV * NdotL))); - #else - // Standard Phong - vec3 R = reflect(-lightdir, norm); - return pow(max(tangDot(R, viewdir), 0.0), shiny); + uniform ENVMAP m_EnvMap; #endif -} - -vec2 computeLighting(in vec3 wvNorm, in vec3 wvViewDir, in vec3 wvLightDir){ - float diffuseFactor = lightComputeDiffuse(wvNorm, wvLightDir, wvViewDir); - float specularFactor = lightComputeSpecular(wvNorm, wvViewDir, wvLightDir, m_Shininess); - - #ifdef HQ_ATTENUATION - float att = clamp(1.0 - g_LightPosition.w * length(lightVec), 0.0, 1.0); - #else - float att = vLightDir.w; - #endif - - if (m_Shininess <= 1.0) { - specularFactor = 0.0; // should be one instruction on most cards .. - } - - specularFactor *= diffuseFactor; - - return vec2(diffuseFactor, specularFactor) * vec2(att); -} #endif void main(){ @@ -176,36 +110,7 @@ void main(){ discard; } - #ifndef VERTEX_LIGHTING - float spotFallOff = 1.0; - - #if __VERSION__ >= 110 - // allow use of control flow - if(g_LightDirection.w != 0.0){ - #endif - - vec3 L = normalize(lightVec.xyz); - vec3 spotdir = normalize(g_LightDirection.xyz); - float curAngleCos = dot(-L, spotdir); - float innerAngleCos = floor(g_LightDirection.w) * 0.001; - float outerAngleCos = fract(g_LightDirection.w); - float innerMinusOuter = innerAngleCos - outerAngleCos; - spotFallOff = (curAngleCos - outerAngleCos) / innerMinusOuter; - #if __VERSION__ >= 110 - if(spotFallOff <= 0.0){ - gl_FragColor.rgb = AmbientSum * diffuseColor.rgb; - gl_FragColor.a = alpha; - return; - }else{ - spotFallOff = clamp(spotFallOff, 0.0, 1.0); - } - } - #else - spotFallOff = clamp(spotFallOff, step(g_LightDirection.w, 0.001), 1.0); - #endif - #endif - // *********************** // Read from textures // *********************** @@ -257,8 +162,23 @@ void main(){ vec4 lightDir = vLightDir; lightDir.xyz = normalize(lightDir.xyz); vec3 viewDir = normalize(vViewDir); + float spotFallOff = 1.0; + + #if __VERSION__ >= 110 + // allow use of control flow + if(g_LightDirection.w != 0.0){ + #endif + spotFallOff = computeSpotFalloff(g_LightDirection, lightVec); + #if __VERSION__ >= 110 + if(spotFallOff <= 0.0){ + gl_FragColor.rgb = AmbientSum * diffuseColor.rgb; + gl_FragColor.a = alpha; + return; + } + } + #endif - vec2 light = computeLighting(normal, viewDir, lightDir.xyz) * spotFallOff; + vec2 light = computeLighting(normal, viewDir, lightDir.xyz, lightDir.w * spotFallOff, m_Shininess) ; #ifdef COLORRAMP diffuseColor.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb; specularColor.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb; diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md index 779242445..e5613f040 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md @@ -6,34 +6,12 @@ MaterialDef Phong Lighting { // For better performance Boolean VertexLighting - // Use more efficent algorithms to improve performance - Boolean LowQuality - - // Improve quality at the cost of performance - Boolean HighQuality - - // Output alpha from the diffuse map - Boolean UseAlpha - // Alpha threshold for fragment discarding Float AlphaDiscardThreshold (AlphaTestFallOff) - // Normal map is in BC5/ATI2n/LATC/3Dc compression format - Boolean LATC - // Use the provided ambient, diffuse, and specular colors Boolean UseMaterialColors - // Activate shading along the tangent, instead of the normal - // Requires tangent data to be available on the model. - Boolean VTangent - - // Use minnaert diffuse instead of lambert - Boolean Minnaert - - // Use ward specular instead of phong - Boolean WardIso - // Use vertex color as an additional diffuse color. Boolean UseVertexColor @@ -133,9 +111,48 @@ MaterialDef Phong Lighting { Int NumberOfBones Matrix4Array BoneMatrices + //For instancing Boolean UseInstancing } + Technique { + LightMode SinglePass + + VertexShader GLSL100: Common/MatDefs/Light/SPLighting.vert + FragmentShader GLSL100: Common/MatDefs/Light/SPLighting.frag + + WorldParameters { + WorldViewProjectionMatrix + NormalMatrix + WorldViewMatrix + ViewMatrix + CameraPosition + WorldMatrix + ViewProjectionMatrix + } + + Defines { + VERTEX_COLOR : UseVertexColor + VERTEX_LIGHTING : VertexLighting + MATERIAL_COLORS : UseMaterialColors + DIFFUSEMAP : DiffuseMap + NORMALMAP : NormalMap + SPECULARMAP : SpecularMap + PARALLAXMAP : ParallaxMap + NORMALMAP_PARALLAX : PackedNormalParallax + STEEP_PARALLAX : SteepParallax + ALPHAMAP : AlphaMap + COLORRAMP : ColorRamp + LIGHTMAP : LightMap + SEPARATE_TEXCOORD : SeparateTexCoord + DISCARD_ALPHA : AlphaDiscardThreshold + USE_REFLECTION : EnvMap + SPHERE_MAP : SphereMap + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + } + } + Technique { LightMode MultiPass @@ -154,17 +171,9 @@ MaterialDef Phong Lighting { } Defines { - LATC : LATC VERTEX_COLOR : UseVertexColor - VERTEX_LIGHTING : VertexLighting - ATTENUATION : Attenuation + VERTEX_LIGHTING : VertexLighting MATERIAL_COLORS : UseMaterialColors - V_TANGENT : VTangent - MINNAERT : Minnaert - WARDISO : WardIso - LOW_QUALITY : LowQuality - HQ_ATTENUATION : HighQuality - DIFFUSEMAP : DiffuseMap NORMALMAP : NormalMap SPECULARMAP : SpecularMap @@ -175,16 +184,16 @@ MaterialDef Phong Lighting { COLORRAMP : ColorRamp LIGHTMAP : LightMap SEPARATE_TEXCOORD : SeparateTexCoord - + DISCARD_ALPHA : AlphaDiscardThreshold USE_REFLECTION : EnvMap SPHERE_MAP : SphereMap - - NUM_BONES : NumberOfBones - + NUM_BONES : NumberOfBones INSTANCING : UseInstancing } } + + Technique PreShadow { VertexShader GLSL100 : Common/MatDefs/Shadow/PreShadow.vert @@ -373,4 +382,4 @@ MaterialDef Phong Lighting { } } -} \ No newline at end of file +} diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert index 737786fb4..1901ebc67 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert @@ -1,8 +1,10 @@ #import "Common/ShaderLib/Instancing.glsllib" -#define ATTENUATION -//#define HQ_ATTENUATION - #import "Common/ShaderLib/Skinning.glsllib" +#import "Common/ShaderLib/Lighting.glsllib" +#ifdef VERTEX_LIGHTING + #import "Common/ShaderLib/PhongLighting.glsllib" +#endif + uniform vec4 m_Ambient; uniform vec4 m_Diffuse; @@ -28,7 +30,6 @@ attribute vec2 inTexCoord; attribute vec3 inNormal; varying vec3 lightVec; -//varying vec4 spotVec; #ifdef VERTEX_COLOR attribute vec4 inColor; @@ -39,8 +40,7 @@ varying vec3 lightVec; #ifndef NORMALMAP varying vec3 vNormal; - #endif - //varying vec3 vPosition; + #endif varying vec3 vViewDir; varying vec4 vLightDir; #else @@ -77,57 +77,6 @@ varying vec3 lightVec; } #endif -// JME3 lights in world space -void lightComputeDir(in vec3 worldPos, in vec4 color, in vec4 position, out vec4 lightDir){ - float posLight = step(0.5, color.w); - vec3 tempVec = position.xyz * sign(posLight - 0.5) - (worldPos * posLight); - lightVec = tempVec; - #ifdef ATTENUATION - float dist = length(tempVec); - lightDir.w = clamp(1.0 - position.w * dist * posLight, 0.0, 1.0); - lightDir.xyz = tempVec / vec3(dist); - #else - lightDir = vec4(normalize(tempVec), 1.0); - #endif -} - -#ifdef VERTEX_LIGHTING - float lightComputeDiffuse(in vec3 norm, in vec3 lightdir){ - return max(0.0, dot(norm, lightdir)); - } - - float lightComputeSpecular(in vec3 norm, in vec3 viewdir, in vec3 lightdir, in float shiny){ - if (shiny <= 1.0){ - return 0.0; - } - #ifndef LOW_QUALITY - vec3 H = (viewdir + lightdir) * vec3(0.5); - return pow(max(dot(H, norm), 0.0), shiny); - #else - return 0.0; - #endif - } - -vec2 computeLighting(in vec3 wvPos, in vec3 wvNorm, in vec3 wvViewDir, in vec4 wvLightPos){ - vec4 lightDir; - lightComputeDir(wvPos, g_LightColor, wvLightPos, lightDir); - float spotFallOff = 1.0; - if(g_LightDirection.w != 0.0){ - vec3 L=normalize(lightVec.xyz); - vec3 spotdir = normalize(g_LightDirection.xyz); - float curAngleCos = dot(-L, spotdir); - float innerAngleCos = floor(g_LightDirection.w) * 0.001; - float outerAngleCos = fract(g_LightDirection.w); - float innerMinusOuter = innerAngleCos - outerAngleCos; - spotFallOff = clamp((curAngleCos - outerAngleCos) / innerMinusOuter, 0.0, 1.0); - } - float diffuseFactor = lightComputeDiffuse(wvNorm, lightDir.xyz); - float specularFactor = lightComputeSpecular(wvNorm, wvViewDir, lightDir.xyz, m_Shininess); - //specularFactor *= step(0.01, diffuseFactor); - return vec2(diffuseFactor, specularFactor) * vec2(lightDir.w)*spotFallOff; - } -#endif - void main(){ vec4 modelSpacePos = vec4(inPosition, 1.0); vec3 modelSpaceNorm = inNormal; @@ -154,11 +103,6 @@ void main(){ vec3 wvNormal = normalize(TransformNormal(modelSpaceNorm));//normalize(g_NormalMatrix * modelSpaceNorm); vec3 viewDir = normalize(-wvPosition); - //vec4 lightColor = g_LightColor[gl_InstanceID]; - //vec4 lightPos = g_LightPosition[gl_InstanceID]; - //vec4 wvLightPos = (g_ViewMatrix * vec4(lightPos.xyz, lightColor.w)); - //wvLightPos.w = lightPos.w; - vec4 wvLightPos = (g_ViewMatrix * vec4(g_LightPosition.xyz,clamp(g_LightColor.w,0.0,1.0))); wvLightPos.w = g_LightPosition.w; vec4 lightColor = g_LightColor; @@ -166,41 +110,24 @@ void main(){ #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING) vec3 wvTangent = normalize(TransformNormal(modelSpaceTan)); vec3 wvBinormal = cross(wvNormal, wvTangent); - mat3 tbnMat = mat3(wvTangent, wvBinormal * inTangent.w,wvNormal); - - //vPosition = wvPosition * tbnMat; - //vViewDir = viewDir * tbnMat; + vViewDir = -wvPosition * tbnMat; - lightComputeDir(wvPosition, lightColor, wvLightPos, vLightDir); + lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec); vLightDir.xyz = (vLightDir.xyz * tbnMat).xyz; #elif !defined(VERTEX_LIGHTING) vNormal = wvNormal; - - //vPosition = wvPosition; vViewDir = viewDir; - - lightComputeDir(wvPosition, lightColor, wvLightPos, vLightDir); - - #ifdef V_TANGENT - vNormal = normalize(TransformNormal(inTangent.xyz)); - vNormal = -cross(cross(vLightDir.xyz, vNormal), vNormal); - #endif + lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec); #endif - //computing spot direction in view space and unpacking spotlight cos -// spotVec = (g_ViewMatrix * vec4(g_LightDirection.xyz, 0.0) ); -// spotVec.w = floor(g_LightDirection.w) * 0.001; -// lightVec.w = fract(g_LightDirection.w); - - lightColor.w = 1.0; #ifdef MATERIAL_COLORS AmbientSum = (m_Ambient * g_AmbientLightColor).rgb; - DiffuseSum = m_Diffuse * lightColor; + DiffuseSum = m_Diffuse * vec4(lightColor.rgb, 1.0); SpecularSum = (m_Specular * lightColor).rgb; #else - AmbientSum = vec3(0.2, 0.2, 0.2) * g_AmbientLightColor.rgb; // Default: ambient color is dark gray - DiffuseSum = lightColor; + AmbientSum = g_AmbientLightColor.rgb; // Default: ambient color is dark gray + DiffuseSum = vec4(lightColor.rgb, 1.0); SpecularSum = vec3(0.0); #endif @@ -210,10 +137,22 @@ void main(){ #endif #ifdef VERTEX_LIGHTING - vertexLightValues = computeLighting(wvPosition, wvNormal, viewDir, wvLightPos); + float spotFallOff = 1.0; + vec4 vLightDir; + lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec); + #if __VERSION__ >= 110 + // allow use of control flow + if(lightColor.w > 1.0){ + #endif + spotFallOff = computeSpotFalloff(g_LightDirection, lightVec); + #if __VERSION__ >= 110 + } + #endif + + vertexLightValues = computeLighting(wvNormal, viewDir, vLightDir.xyz, vLightDir.w * spotFallOff, m_Shininess); #endif - #ifdef USE_REFLECTION + #ifdef USE_REFLECTION computeRef(modelSpacePos); #endif } \ No newline at end of file diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag new file mode 100644 index 000000000..09478c6e8 --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag @@ -0,0 +1,218 @@ +#import "Common/ShaderLib/Parallax.glsllib" +#import "Common/ShaderLib/Optics.glsllib" +#ifndef VERTEX_LIGHTING + #import "Common/ShaderLib/PhongLighting.glsllib" + #import "Common/ShaderLib/Lighting.glsllib" +#endif + +varying vec2 texCoord; +#ifdef SEPARATE_TEXCOORD + varying vec2 texCoord2; +#endif + +varying vec3 AmbientSum; +varying vec4 DiffuseSum; +varying vec3 SpecularSum; + +#ifndef VERTEX_LIGHTING + uniform mat4 g_ViewMatrix; + uniform vec4 g_LightData[NB_LIGHTS]; + varying vec3 vPos; +#else + varying vec3 specularAccum; + varying vec4 diffuseAccum; +#endif + +#ifdef DIFFUSEMAP + uniform sampler2D m_DiffuseMap; +#endif + +#ifdef SPECULARMAP + uniform sampler2D m_SpecularMap; +#endif + +#ifdef PARALLAXMAP + uniform sampler2D m_ParallaxMap; +#endif +#if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) && !defined(VERTEX_LIGHTING) + uniform float m_ParallaxHeight; +#endif + +#ifdef LIGHTMAP + uniform sampler2D m_LightMap; +#endif + +#ifdef NORMALMAP + uniform sampler2D m_NormalMap; + varying vec3 vTangent; + varying vec3 vBinormal; +#endif +varying vec3 vNormal; + +#ifdef ALPHAMAP + uniform sampler2D m_AlphaMap; +#endif + +#ifdef COLORRAMP + uniform sampler2D m_ColorRamp; +#endif + +uniform float m_AlphaDiscardThreshold; + +#ifndef VERTEX_LIGHTING +uniform float m_Shininess; + + #ifdef USE_REFLECTION + uniform float m_ReflectionPower; + uniform float m_ReflectionIntensity; + varying vec4 refVec; + + uniform ENVMAP m_EnvMap; + #endif +#endif + +void main(){ + vec2 newTexCoord; + + #if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) && !defined(VERTEX_LIGHTING) + + #ifdef STEEP_PARALLAX + #ifdef NORMALMAP_PARALLAX + //parallax map is stored in the alpha channel of the normal map + newTexCoord = steepParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight); + #else + //parallax map is a texture + newTexCoord = steepParallaxOffset(m_ParallaxMap, vViewDir, texCoord, m_ParallaxHeight); + #endif + #else + #ifdef NORMALMAP_PARALLAX + //parallax map is stored in the alpha channel of the normal map + newTexCoord = classicParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight); + #else + //parallax map is a texture + newTexCoord = classicParallaxOffset(m_ParallaxMap, vViewDir, texCoord, m_ParallaxHeight); + #endif + #endif + #else + newTexCoord = texCoord; + #endif + + #ifdef DIFFUSEMAP + vec4 diffuseColor = texture2D(m_DiffuseMap, newTexCoord); + #else + vec4 diffuseColor = vec4(1.0); + #endif + + float alpha = DiffuseSum.a * diffuseColor.a; + + #ifdef ALPHAMAP + alpha = alpha * texture2D(m_AlphaMap, newTexCoord).r; + #endif + + #ifdef DISCARD_ALPHA + if(alpha < m_AlphaDiscardThreshold){ + discard; + } + #endif + + // *********************** + // Read from textures + // *********************** + #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING) + vec4 normalHeight = texture2D(m_NormalMap, newTexCoord); + //Note the -2.0 and -1.0. We invert the green channel of the normal map, + //as it's complient with normal maps generated with blender. + //see http://hub.jmonkeyengine.org/forum/topic/parallax-mapping-fundamental-bug/#post-256898 + //for more explanation. + vec3 normal = normalize((normalHeight.xyz * vec3(2.0,-2.0,2.0) - vec3(1.0,-1.0,1.0))); + #elif !defined(VERTEX_LIGHTING) + vec3 normal = normalize(vNormal); + #endif + + #ifdef SPECULARMAP + vec4 specularColor = texture2D(m_SpecularMap, newTexCoord); + #else + vec4 specularColor = vec4(1.0); + #endif + + #ifdef LIGHTMAP + vec3 lightMapColor; + #ifdef SEPARATE_TEXCOORD + lightMapColor = texture2D(m_LightMap, texCoord2).rgb; + #else + lightMapColor = texture2D(m_LightMap, texCoord).rgb; + #endif + specularColor.rgb *= lightMapColor; + diffuseColor.rgb *= lightMapColor; + #endif + + #ifdef VERTEX_LIGHTING + gl_FragColor.rgb = AmbientSum * diffuseColor.rgb + +diffuseAccum.rgb *diffuseColor.rgb + +specularAccum.rgb * specularColor.rgb; + gl_FragColor.a=1.0; + #else + + int i = 0; + gl_FragColor.rgb = AmbientSum * diffuseColor.rgb; + + #ifdef USE_REFLECTION + vec4 refColor = Optics_GetEnvColor(m_EnvMap, refVec.xyz); + #endif + + #ifdef NORMALMAP + mat3 tbnMat = mat3(normalize(vTangent.xyz) , normalize(vBinormal.xyz) , normalize(vNormal.xyz)); + #endif + + for( int i = 0;i < NB_LIGHTS; i+=3){ + vec4 lightColor = g_LightData[i]; + vec4 lightData1 = g_LightData[i+1]; + vec4 lightDir; + vec3 lightVec; + lightComputeDir(vPos, lightColor.w, lightData1, lightDir,lightVec); + + float spotFallOff = 1.0; + #if __VERSION__ >= 110 + // allow use of control flow + if(lightColor.w > 1.0){ + #endif + spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec); + #if __VERSION__ >= 110 + } + #endif + + #ifdef NORMALMAP + //Normal map -> lighting is computed in tangent space + lightDir.xyz = normalize(lightDir.xyz * tbnMat); + vec3 viewDir = normalize(-vPos.xyz * tbnMat); + #else + //no Normal map -> lighting is computed in view space + lightDir.xyz = normalize(lightDir.xyz); + vec3 viewDir = normalize(-vPos.xyz); + #endif + + vec2 light = computeLighting(normal, viewDir, lightDir.xyz, lightDir.w * spotFallOff , m_Shininess); + + #ifdef COLORRAMP + diffuseColor.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb; + specularColor.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb; + #endif + + // Workaround, since it is not possible to modify varying variables + vec4 SpecularSum2 = vec4(SpecularSum, 1.0); + #ifdef USE_REFLECTION + // Interpolate light specularity toward reflection color + // Multiply result by specular map + specularColor = mix(SpecularSum2 * light.y, refColor, refVec.w) * specularColor; + + SpecularSum2 = vec4(1.0); + light.y = 1.0; + #endif + + gl_FragColor.rgb += DiffuseSum.rgb * lightColor.rgb * diffuseColor.rgb * vec3(light.x) + + SpecularSum2.rgb * specularColor.rgb * vec3(light.y); + } + + #endif + gl_FragColor.a = alpha; +} diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert new file mode 100644 index 000000000..81ea869b6 --- /dev/null +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert @@ -0,0 +1,172 @@ +#import "Common/ShaderLib/Instancing.glsllib" +#import "Common/ShaderLib/Skinning.glsllib" +#import "Common/ShaderLib/Lighting.glsllib" +#ifdef VERTEX_LIGHTING + #import "Common/ShaderLib/PhongLighting.glsllib" +#endif + + +uniform vec4 m_Ambient; +uniform vec4 m_Diffuse; +uniform vec4 m_Specular; +uniform float m_Shininess; + +#if defined(VERTEX_LIGHTING) + uniform vec4 g_LightData[NB_LIGHTS]; +#endif +uniform vec4 g_AmbientLightColor; +varying vec2 texCoord; + +#ifdef SEPARATE_TEXCOORD + varying vec2 texCoord2; + attribute vec2 inTexCoord2; +#endif + +varying vec3 AmbientSum; +varying vec4 DiffuseSum; +varying vec3 SpecularSum; + +attribute vec3 inPosition; +attribute vec2 inTexCoord; +attribute vec3 inNormal; + +#ifdef VERTEX_COLOR + attribute vec4 inColor; +#endif + +#ifndef VERTEX_LIGHTING + varying vec3 vNormal; + varying vec3 vPos; + #ifdef NORMALMAP + attribute vec4 inTangent; + varying vec3 vTangent; + varying vec3 vBinormal; + #endif +#else + varying vec3 specularAccum; + varying vec4 diffuseAccum; +#endif + +#ifdef USE_REFLECTION + uniform vec3 g_CameraPosition; + uniform vec3 m_FresnelParams; + varying vec4 refVec; + + /** + * Input: + * attribute inPosition + * attribute inNormal + * uniform g_WorldMatrix + * uniform g_CameraPosition + * + * Output: + * varying refVec + */ + void computeRef(in vec4 modelSpacePos){ + // vec3 worldPos = (g_WorldMatrix * modelSpacePos).xyz; + vec3 worldPos = TransformWorld(modelSpacePos).xyz; + + vec3 I = normalize( g_CameraPosition - worldPos ).xyz; + // vec3 N = normalize( (g_WorldMatrix * vec4(inNormal, 0.0)).xyz ); + vec3 N = normalize( TransformWorld(vec4(inNormal, 0.0)).xyz ); + + refVec.xyz = reflect(I, N); + refVec.w = m_FresnelParams.x + m_FresnelParams.y * pow(1.0 + dot(I, N), m_FresnelParams.z); + } +#endif + +void main(){ + vec4 modelSpacePos = vec4(inPosition, 1.0); + vec3 modelSpaceNorm = inNormal; + + #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING) + vec3 modelSpaceTan = inTangent.xyz; + #endif + + #ifdef NUM_BONES + #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING) + Skinning_Compute(modelSpacePos, modelSpaceNorm, modelSpaceTan); + #else + Skinning_Compute(modelSpacePos, modelSpaceNorm); + #endif + #endif + + gl_Position = TransformWorldViewProjection(modelSpacePos); + texCoord = inTexCoord; + #ifdef SEPARATE_TEXCOORD + texCoord2 = inTexCoord2; + #endif + + vec3 wvPosition = TransformWorldView(modelSpacePos).xyz; + vec3 wvNormal = normalize(TransformNormal(modelSpaceNorm)); + vec3 viewDir = normalize(-wvPosition); + + + #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING) + vTangent = TransformNormal(modelSpaceTan); + vBinormal = cross(wvNormal, vTangent)* inTangent.w; + vNormal = wvNormal; + vPos = wvPosition; + #elif !defined(VERTEX_LIGHTING) + vNormal = wvNormal; + vPos = wvPosition; + #endif + + #ifdef MATERIAL_COLORS + AmbientSum = m_Ambient.rgb * g_AmbientLightColor.rgb; + SpecularSum = m_Specular.rgb; + DiffuseSum = m_Diffuse; + #else + AmbientSum = g_AmbientLightColor.rgb; + SpecularSum = vec3(0.0); + DiffuseSum = vec4(1.0); + #endif + #ifdef VERTEX_COLOR + AmbientSum *= inColor.rgb; + DiffuseSum *= inColor; + #endif + #ifdef VERTEX_LIGHTING + int i = 0; + diffuseAccum = vec4(0.0); + specularAccum = vec3(0.0); + vec4 diffuseColor; + vec3 specularColor; + for (int i =0;i < NB_LIGHTS; i+=3){ + vec4 lightColor = g_LightData[i]; + vec4 lightData1 = g_LightData[i+1]; + DiffuseSum = vec4(1.0); + #ifdef MATERIAL_COLORS + diffuseColor = m_Diffuse * vec4(lightColor.rgb, 1.0); + specularColor = m_Specular.rgb * lightColor.rgb; + #else + diffuseColor = vec4(lightColor.rgb, 1.0); + specularColor = vec3(0.0); + #endif + + vec4 lightDir; + vec3 lightVec; + lightComputeDir(wvPosition, lightColor.w, lightData1, lightDir, lightVec); + // lightDir = normalize(lightDir); + // lightVec = normalize(lightVec); + + float spotFallOff = 1.0; + #if __VERSION__ >= 110 + // allow use of control flow + if(lightColor.w > 1.0){ + #endif + vec4 lightDirection = g_LightData[i+2]; + spotFallOff = computeSpotFalloff(lightDirection, lightVec); + #if __VERSION__ >= 110 + } + #endif + vec2 v = computeLighting(wvNormal, viewDir, lightDir.xyz, lightDir.w * spotFallOff, m_Shininess); + diffuseAccum +=v.x * diffuseColor; + specularAccum += v.y * specularColor; + } + #endif + + + #ifdef USE_REFLECTION + computeRef(modelSpacePos); + #endif +} \ No newline at end of file diff --git a/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib index 4d1b40436..3b8863b6c 100644 --- a/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib +++ b/jme3-core/src/main/resources/Common/ShaderLib/Lighting.glsllib @@ -1,48 +1,30 @@ -#ifndef NUM_LIGHTS - #define NUM_LIGHTS 4 -#endif +/*Common function for light calculations*/ -uniform mat4 g_ViewMatrix; -uniform vec4 g_LightPosition[NUM_LIGHTS]; -uniform vec4 g_g_LightColor[NUM_LIGHTS]; -uniform float m_Shininess; -float Lighting_Diffuse(vec3 norm, vec3 lightdir){ - return max(0.0, dot(norm, lightdir)); -} - -float Lighting_Specular(vec3 norm, vec3 viewdir, vec3 lightdir, float shiny){ - vec3 refdir = reflect(-lightdir, norm); - return pow(max(dot(refdir, viewdir), 0.0), shiny); -} - -void Lighting_Direction(vec3 worldPos, vec4 color, vec4 position, out vec4 lightDir){ - float posLight = step(0.5, color.w); +/* +* Computes light direction +* lightType should be 0.0,1.0,2.0, repectively for Directional, point and spot lights. +* Outputs the light direction and the light half vector. +*/ +void lightComputeDir(in vec3 worldPos, in float ligthType, in vec4 position, out vec4 lightDir, out vec3 lightVec){ + float posLight = step(0.5, ligthType); vec3 tempVec = position.xyz * sign(posLight - 0.5) - (worldPos * posLight); + lightVec = tempVec; float dist = length(tempVec); - lightDir.w = clamp(1.0 - position.w * dist * posLight, 0.0, 1.0); - lightDir.xyz = tempVec / dist; + lightDir.xyz = tempVec / vec3(dist); } -void Lighting_ComputePS(vec3 tanNormal, mat3 tbnMat, - int lightCount, out vec3 outDiffuse, out vec3 outSpecular){ - // find tangent view dir & vert pos - vec3 tanViewDir = viewDir * tbnMat; - - for (int i = 0; i < lightCount; i++){ - // find light dir in tangent space, works for point & directional lights - vec4 wvLightPos = (g_ViewMatrix * vec4(g_LightPosition[i].xyz, g_LightColor[i].w)); - wvLightPos.w = g_LightPosition[i].w; - - vec4 tanLightDir; - Lighting_Direction(wvPosition, g_LightColor[i], wvLightPos, tanLightDir); - tanLightDir.xyz = tanLightDir.xyz * tbnMat; - - vec3 lightScale = g_LightColor[i].rgb * tanLightDir.w; - float specular = Lighting_Specular(tanNormal, tanViewDir, tanLightDir.xyz, m_Shininess); - float diffuse = Lighting_Diffuse(tanNormal, tanLightDir.xyz); - outSpecular += specular * lightScale * step(0.01, diffuse) * g_LightColor[i].rgb; - outDiffuse += diffuse * lightScale * g_LightColor[i].rgb; - } +/* +* Computes the spot falloff for a spotlight +*/ +float computeSpotFalloff(in vec4 lightDirection, in vec3 lightVector){ + vec3 L=normalize(lightVector); + vec3 spotdir = normalize(lightDirection.xyz); + float curAngleCos = dot(-L, spotdir); + float innerAngleCos = floor(lightDirection.w) * 0.001; + float outerAngleCos = fract(lightDirection.w); + float innerMinusOuter = innerAngleCos - outerAngleCos; + return clamp((curAngleCos - outerAngleCos) / innerMinusOuter, step(lightDirection.w, 0.001), 1.0); } + diff --git a/jme3-core/src/main/resources/Common/ShaderLib/PhongLighting.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/PhongLighting.glsllib new file mode 100644 index 000000000..8ebeb9924 --- /dev/null +++ b/jme3-core/src/main/resources/Common/ShaderLib/PhongLighting.glsllib @@ -0,0 +1,29 @@ +/*Standard Phong ligting*/ + +/* +* Computes diffuse factor +*/ +float lightComputeDiffuse(in vec3 norm, in vec3 lightdir){ + return max(0.0, dot(norm, lightdir)); +} + +/* +* Computes specular factor +*/ +float lightComputeSpecular(in vec3 norm, in vec3 viewdir, in vec3 lightdir, in float shiny){ + vec3 R = reflect(-lightdir, norm); + return pow(max(dot(R, viewdir), 0.0), shiny); +} + +/* +* Computes diffuse and specular factors and pack them in a vec2 (x=diffuse, y=specular) +*/ +vec2 computeLighting(in vec3 norm, in vec3 viewDir, in vec3 lightDir, in float attenuation, in float shininess){ + float diffuseFactor = lightComputeDiffuse(norm, lightDir); + float specularFactor = lightComputeSpecular(norm, viewDir, lightDir, shininess); + if (shininess <= 1.0) { + specularFactor = 0.0; // should be one instruction on most cards .. + } + specularFactor *= diffuseFactor; + return vec2(diffuseFactor, specularFactor) * vec2(attenuation); +} \ No newline at end of file diff --git a/jme3-examples/src/main/java/jme3test/light/TestManyLightsSingle.java b/jme3-examples/src/main/java/jme3test/light/TestManyLightsSingle.java new file mode 100644 index 000000000..acc0037b8 --- /dev/null +++ b/jme3-examples/src/main/java/jme3test/light/TestManyLightsSingle.java @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package jme3test.light; + +import com.jme3.app.BasicProfilerState; +import com.jme3.app.SimpleApplication; +import com.jme3.font.BitmapText; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.light.AmbientLight; +import com.jme3.light.DirectionalLight; +import com.jme3.light.Light; +import com.jme3.light.LightList; +import com.jme3.light.PointLight; +import com.jme3.light.SpotLight; +import com.jme3.material.Material; +import com.jme3.material.TechniqueDef; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector3f; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; +import com.jme3.scene.LightNode; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.AbstractControl; +import com.jme3.scene.shape.Box; + +public class TestManyLightsSingle extends SimpleApplication { + + public static void main(String[] args) { + TestManyLightsSingle app = new TestManyLightsSingle(); + app.start(); + } + TechniqueDef.LightMode lm = TechniqueDef.LightMode.MultiPass; + int lightNum = 6 ; + + @Override + public void simpleInitApp() { + renderManager.setPreferredLightMode(lm); + renderManager.setSinglePassLightBatchSize(lightNum); + + + flyCam.setMoveSpeed(10); + + Node scene = (Node) assetManager.loadModel("Scenes/ManyLights/Main.scene"); + rootNode.attachChild(scene); + Node n = (Node) rootNode.getChild(0); + LightList lightList = n.getWorldLightList(); + Geometry g = (Geometry) n.getChild("Grid-geom-1"); + + g.getMaterial().setColor("Ambient", new ColorRGBA(0.2f, 0.2f, 0.2f, 1f)); + + /* A colored lit cube. Needs light source! */ + Box boxMesh = new Box(1f, 1f, 1f); + Geometry boxGeo = new Geometry("Colored Box", boxMesh); + Material boxMat = g.getMaterial().clone(); + boxMat.setBoolean("UseMaterialColors", true); + boxMat.setColor("Ambient", new ColorRGBA(0.2f, 0.2f, 0.2f, 1f)); + boxMat.setColor("Diffuse", ColorRGBA.Blue); + boxGeo.setMaterial(boxMat); + + int nb = 0; + for (Light light : lightList) { + nb++; + PointLight p = (PointLight) light; + if (nb >60) { + n.removeLight(light); + } else { + + LightNode ln = new LightNode("l", light); + n.attachChild(ln); + ln.setLocalTranslation(p.getPosition()); + int rand = FastMath.nextRandomInt(0, 3); + switch (rand) { + case 0: + light.setColor(ColorRGBA.Red); + // ln.addControl(new MoveControl(5f)); + break; + case 1: + light.setColor(ColorRGBA.Yellow); + // ln.addControl(new MoveControl(5f)); + break; + case 2: + light.setColor(ColorRGBA.Green); + //ln.addControl(new MoveControl(-5f)); + break; + case 3: + light.setColor(ColorRGBA.Orange); + //ln.addControl(new MoveControl(-5f)); + break; + } + } + Geometry b = boxGeo.clone(); + n.attachChild(b); + b.setLocalTranslation(p.getPosition().x, 2, p.getPosition().z); + + } + + +// cam.setLocation(new Vector3f(3.1893547f, 17.977385f, 30.8378f)); +// cam.setRotation(new Quaternion(0.14317635f, 0.82302624f, -0.23777823f, 0.49557027f)); + + cam.setLocation(new Vector3f(-1.8901939f, 29.34097f, 73.07533f)); + cam.setRotation(new Quaternion(0.0021000702f, 0.971012f, -0.23886925f, 0.008527749f)); + + + BasicProfilerState profiler = new BasicProfilerState(true); + profiler.setGraphScale(1000f); + + // getStateManager().attach(profiler); +// guiNode.setCullHint(CullHint.Always); + + + + + flyCam.setDragToRotate(true); + flyCam.setMoveSpeed(50); + + + inputManager.addListener(new ActionListener() { + public void onAction(String name, boolean isPressed, float tpf) { + if (name.equals("toggle") && isPressed) { + if (lm == TechniqueDef.LightMode.SinglePass) { + lm = TechniqueDef.LightMode.MultiPass; + } else { + lm = TechniqueDef.LightMode.SinglePass; + } + renderManager.setPreferredLightMode(lm); + } + if (name.equals("lightsUp") && isPressed) { + lightNum++; + renderManager.setSinglePassLightBatchSize(lightNum); + helloText.setText("nb lights per batch : " + lightNum); + } + if (name.equals("lightsDown") && isPressed) { + lightNum--; + renderManager.setSinglePassLightBatchSize(lightNum); + helloText.setText("nb lights per batch : " + lightNum); + } + } + }, "toggle", "lightsUp", "lightsDown"); + + inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE)); + inputManager.addMapping("lightsUp", new KeyTrigger(KeyInput.KEY_UP)); + inputManager.addMapping("lightsDown", new KeyTrigger(KeyInput.KEY_DOWN)); + + + SpotLight spot = new SpotLight(); + spot.setDirection(new Vector3f(-1f, -1f, -1f).normalizeLocal()); + spot.setColor(ColorRGBA.Blue.mult(5)); + spot.setSpotOuterAngle(FastMath.DEG_TO_RAD * 20); + spot.setSpotInnerAngle(FastMath.DEG_TO_RAD * 5); + spot.setPosition(new Vector3f(10, 10, 20)); + rootNode.addLight(spot); + + DirectionalLight dl = new DirectionalLight(); + dl.setDirection(new Vector3f(-1, -1, 1)); + rootNode.addLight(dl); + + AmbientLight al = new AmbientLight(); + al.setColor(new ColorRGBA(0.2f, 0.2f, 0.2f, 1f)); + rootNode.addLight(al); + + + /** + * Write text on the screen (HUD) + */ + guiNode.detachAllChildren(); + guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + helloText = new BitmapText(guiFont, false); + helloText.setSize(guiFont.getCharSet().getRenderedSize()); + helloText.setText("nb lights per batch : " + lightNum); + helloText.setLocalTranslation(300, helloText.getLineHeight(), 0); + guiNode.attachChild(helloText); + + + } + BitmapText helloText; + long time; + long nbFrames; + long startTime = 0; + + @Override + public void simpleUpdate(float tpf) { +// if (nbFrames == 4000) { +// startTime = System.nanoTime(); +// } +// if (nbFrames > 4000) { +// time = System.nanoTime(); +// float average = ((float) time - (float) startTime) / ((float) nbFrames - 4000f); +// helloText.setText("Average = " + average); +// } +// nbFrames++; + } + + class MoveControl extends AbstractControl { + + float direction; + Vector3f origPos = new Vector3f(); + + public MoveControl(float direction) { + this.direction = direction; + } + + @Override + public void setSpatial(Spatial spatial) { + super.setSpatial(spatial); //To change body of generated methods, choose Tools | Templates. + origPos.set(spatial.getLocalTranslation()); + } + float time = 0; + + @Override + protected void controlUpdate(float tpf) { + time += tpf; + spatial.setLocalTranslation(origPos.x + FastMath.cos(time) * direction, origPos.y, origPos.z + FastMath.sin(time) * direction); + } + + @Override + protected void controlRender(RenderManager rm, ViewPort vp) { + } + } +} \ No newline at end of file diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/SPTerrainLighting.frag b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/SPTerrainLighting.frag new file mode 100644 index 000000000..9556f256d --- /dev/null +++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/SPTerrainLighting.frag @@ -0,0 +1,615 @@ +#import "Common/ShaderLib/PhongLighting.glsllib" +#import "Common/ShaderLib/Lighting.glsllib" + +uniform float m_Shininess; + +varying vec4 AmbientSum; +varying vec4 DiffuseSum; +varying vec4 SpecularSum; + +uniform mat4 g_ViewMatrix; +uniform vec4 g_LightData[NB_LIGHTS]; +varying vec3 vTangent; +varying vec3 vBinormal; +varying vec3 vPos; +varying vec3 vNormal; +varying vec2 texCoord; + + +#ifdef DIFFUSEMAP + uniform sampler2D m_DiffuseMap; +#endif +#ifdef DIFFUSEMAP_1 + uniform sampler2D m_DiffuseMap_1; +#endif +#ifdef DIFFUSEMAP_2 + uniform sampler2D m_DiffuseMap_2; +#endif +#ifdef DIFFUSEMAP_3 + uniform sampler2D m_DiffuseMap_3; +#endif +#ifdef DIFFUSEMAP_4 + uniform sampler2D m_DiffuseMap_4; +#endif +#ifdef DIFFUSEMAP_5 + uniform sampler2D m_DiffuseMap_5; +#endif +#ifdef DIFFUSEMAP_6 + uniform sampler2D m_DiffuseMap_6; +#endif +#ifdef DIFFUSEMAP_7 + uniform sampler2D m_DiffuseMap_7; +#endif +#ifdef DIFFUSEMAP_8 + uniform sampler2D m_DiffuseMap_8; +#endif +#ifdef DIFFUSEMAP_9 + uniform sampler2D m_DiffuseMap_9; +#endif +#ifdef DIFFUSEMAP_10 + uniform sampler2D m_DiffuseMap_10; +#endif +#ifdef DIFFUSEMAP_11 + uniform sampler2D m_DiffuseMap_11; +#endif + + +#ifdef DIFFUSEMAP_0_SCALE + uniform float m_DiffuseMap_0_scale; +#endif +#ifdef DIFFUSEMAP_1_SCALE + uniform float m_DiffuseMap_1_scale; +#endif +#ifdef DIFFUSEMAP_2_SCALE + uniform float m_DiffuseMap_2_scale; +#endif +#ifdef DIFFUSEMAP_3_SCALE + uniform float m_DiffuseMap_3_scale; +#endif +#ifdef DIFFUSEMAP_4_SCALE + uniform float m_DiffuseMap_4_scale; +#endif +#ifdef DIFFUSEMAP_5_SCALE + uniform float m_DiffuseMap_5_scale; +#endif +#ifdef DIFFUSEMAP_6_SCALE + uniform float m_DiffuseMap_6_scale; +#endif +#ifdef DIFFUSEMAP_7_SCALE + uniform float m_DiffuseMap_7_scale; +#endif +#ifdef DIFFUSEMAP_8_SCALE + uniform float m_DiffuseMap_8_scale; +#endif +#ifdef DIFFUSEMAP_9_SCALE + uniform float m_DiffuseMap_9_scale; +#endif +#ifdef DIFFUSEMAP_10_SCALE + uniform float m_DiffuseMap_10_scale; +#endif +#ifdef DIFFUSEMAP_11_SCALE + uniform float m_DiffuseMap_11_scale; +#endif + + +#ifdef ALPHAMAP + uniform sampler2D m_AlphaMap; +#endif +#ifdef ALPHAMAP_1 + uniform sampler2D m_AlphaMap_1; +#endif +#ifdef ALPHAMAP_2 + uniform sampler2D m_AlphaMap_2; +#endif + +#ifdef NORMALMAP + uniform sampler2D m_NormalMap; +#endif +#ifdef NORMALMAP_1 + uniform sampler2D m_NormalMap_1; +#endif +#ifdef NORMALMAP_2 + uniform sampler2D m_NormalMap_2; +#endif +#ifdef NORMALMAP_3 + uniform sampler2D m_NormalMap_3; +#endif +#ifdef NORMALMAP_4 + uniform sampler2D m_NormalMap_4; +#endif +#ifdef NORMALMAP_5 + uniform sampler2D m_NormalMap_5; +#endif +#ifdef NORMALMAP_6 + uniform sampler2D m_NormalMap_6; +#endif +#ifdef NORMALMAP_7 + uniform sampler2D m_NormalMap_7; +#endif +#ifdef NORMALMAP_8 + uniform sampler2D m_NormalMap_8; +#endif +#ifdef NORMALMAP_9 + uniform sampler2D m_NormalMap_9; +#endif +#ifdef NORMALMAP_10 + uniform sampler2D m_NormalMap_10; +#endif +#ifdef NORMALMAP_11 + uniform sampler2D m_NormalMap_11; +#endif + + +#ifdef TRI_PLANAR_MAPPING + varying vec4 wVertex; + varying vec3 wNormal; +#endif + + +#ifdef ALPHAMAP + + vec4 calculateDiffuseBlend(in vec2 texCoord) { + vec4 alphaBlend = texture2D( m_AlphaMap, texCoord.xy ); + + #ifdef ALPHAMAP_1 + vec4 alphaBlend1 = texture2D( m_AlphaMap_1, texCoord.xy ); + #endif + #ifdef ALPHAMAP_2 + vec4 alphaBlend2 = texture2D( m_AlphaMap_2, texCoord.xy ); + #endif + + vec4 diffuseColor = texture2D(m_DiffuseMap, texCoord * m_DiffuseMap_0_scale); + diffuseColor *= alphaBlend.r; + #ifdef DIFFUSEMAP_1 + vec4 diffuseColor1 = texture2D(m_DiffuseMap_1, texCoord * m_DiffuseMap_1_scale); + diffuseColor = mix( diffuseColor, diffuseColor1, alphaBlend.g ); + #endif + #ifdef DIFFUSEMAP_2 + vec4 diffuseColor2 = texture2D(m_DiffuseMap_2, texCoord * m_DiffuseMap_2_scale); + diffuseColor = mix( diffuseColor, diffuseColor2, alphaBlend.b ); + #endif + #ifdef DIFFUSEMAP_3 + vec4 diffuseColor3 = texture2D(m_DiffuseMap_3, texCoord * m_DiffuseMap_3_scale); + diffuseColor = mix( diffuseColor, diffuseColor3, alphaBlend.a ); + #endif + + #ifdef ALPHAMAP_1 + #ifdef DIFFUSEMAP_4 + vec4 diffuseColor4 = texture2D(m_DiffuseMap_4, texCoord * m_DiffuseMap_4_scale); + diffuseColor = mix( diffuseColor, diffuseColor4, alphaBlend1.r ); + #endif + #ifdef DIFFUSEMAP_5 + vec4 diffuseColor5 = texture2D(m_DiffuseMap_5, texCoord * m_DiffuseMap_5_scale); + diffuseColor = mix( diffuseColor, diffuseColor5, alphaBlend1.g ); + #endif + #ifdef DIFFUSEMAP_6 + vec4 diffuseColor6 = texture2D(m_DiffuseMap_6, texCoord * m_DiffuseMap_6_scale); + diffuseColor = mix( diffuseColor, diffuseColor6, alphaBlend1.b ); + #endif + #ifdef DIFFUSEMAP_7 + vec4 diffuseColor7 = texture2D(m_DiffuseMap_7, texCoord * m_DiffuseMap_7_scale); + diffuseColor = mix( diffuseColor, diffuseColor7, alphaBlend1.a ); + #endif + #endif + + #ifdef ALPHAMAP_2 + #ifdef DIFFUSEMAP_8 + vec4 diffuseColor8 = texture2D(m_DiffuseMap_8, texCoord * m_DiffuseMap_8_scale); + diffuseColor = mix( diffuseColor, diffuseColor8, alphaBlend2.r ); + #endif + #ifdef DIFFUSEMAP_9 + vec4 diffuseColor9 = texture2D(m_DiffuseMap_9, texCoord * m_DiffuseMap_9_scale); + diffuseColor = mix( diffuseColor, diffuseColor9, alphaBlend2.g ); + #endif + #ifdef DIFFUSEMAP_10 + vec4 diffuseColor10 = texture2D(m_DiffuseMap_10, texCoord * m_DiffuseMap_10_scale); + diffuseColor = mix( diffuseColor, diffuseColor10, alphaBlend2.b ); + #endif + #ifdef DIFFUSEMAP_11 + vec4 diffuseColor11 = texture2D(m_DiffuseMap_11, texCoord * m_DiffuseMap_11_scale); + diffuseColor = mix( diffuseColor, diffuseColor11, alphaBlend2.a ); + #endif + #endif + + return diffuseColor; + } + + vec3 calculateNormal(in vec2 texCoord) { + vec3 normal = vec3(0,0,1); + vec3 n = vec3(0,0,0); + + vec4 alphaBlend = texture2D( m_AlphaMap, texCoord.xy ); + + #ifdef ALPHAMAP_1 + vec4 alphaBlend1 = texture2D( m_AlphaMap_1, texCoord.xy ); + #endif + #ifdef ALPHAMAP_2 + vec4 alphaBlend2 = texture2D( m_AlphaMap_2, texCoord.xy ); + #endif + + #ifdef NORMALMAP + n = texture2D(m_NormalMap, texCoord * m_DiffuseMap_0_scale).xyz; + normal += n * alphaBlend.r; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.r; + #endif + + #ifdef NORMALMAP_1 + n = texture2D(m_NormalMap_1, texCoord * m_DiffuseMap_1_scale).xyz; + normal += n * alphaBlend.g; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.g; + #endif + + #ifdef NORMALMAP_2 + n = texture2D(m_NormalMap_2, texCoord * m_DiffuseMap_2_scale).xyz; + normal += n * alphaBlend.b; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.b; + #endif + + #ifdef NORMALMAP_3 + n = texture2D(m_NormalMap_3, texCoord * m_DiffuseMap_3_scale).xyz; + normal += n * alphaBlend.a; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.a; + #endif + + #ifdef ALPHAMAP_1 + #ifdef NORMALMAP_4 + n = texture2D(m_NormalMap_4, texCoord * m_DiffuseMap_4_scale).xyz; + normal += n * alphaBlend1.r; + #endif + + #ifdef NORMALMAP_5 + n = texture2D(m_NormalMap_5, texCoord * m_DiffuseMap_5_scale).xyz; + normal += n * alphaBlend1.g; + #endif + + #ifdef NORMALMAP_6 + n = texture2D(m_NormalMap_6, texCoord * m_DiffuseMap_6_scale).xyz; + normal += n * alphaBlend1.b; + #endif + + #ifdef NORMALMAP_7 + n = texture2D(m_NormalMap_7, texCoord * m_DiffuseMap_7_scale).xyz; + normal += n * alphaBlend1.a; + #endif + #endif + + #ifdef ALPHAMAP_2 + #ifdef NORMALMAP_8 + n = texture2D(m_NormalMap_8, texCoord * m_DiffuseMap_8_scale).xyz; + normal += n * alphaBlend2.r; + #endif + + #ifdef NORMALMAP_9 + n = texture2D(m_NormalMap_9, texCoord * m_DiffuseMap_9_scale); + normal += n * alphaBlend2.g; + #endif + + #ifdef NORMALMAP_10 + n = texture2D(m_NormalMap_10, texCoord * m_DiffuseMap_10_scale); + normal += n * alphaBlend2.b; + #endif + + #ifdef NORMALMAP_11 + n = texture2D(m_NormalMap_11, texCoord * m_DiffuseMap_11_scale); + normal += n * alphaBlend2.a; + #endif + #endif + + normal = (normal.xyz * vec3(2.0) - vec3(1.0)); + return normalize(normal); + } + + #ifdef TRI_PLANAR_MAPPING + + vec4 getTriPlanarBlend(in vec4 coords, in vec3 blending, in sampler2D map, in float scale) { + vec4 col1 = texture2D( map, coords.yz * scale); + vec4 col2 = texture2D( map, coords.xz * scale); + vec4 col3 = texture2D( map, coords.xy * scale); + // blend the results of the 3 planar projections. + vec4 tex = col1 * blending.x + col2 * blending.y + col3 * blending.z; + return tex; + } + + vec4 calculateTriPlanarDiffuseBlend(in vec3 wNorm, in vec4 wVert, in vec2 texCoord) { + // tri-planar texture bending factor for this fragment's normal + vec3 blending = abs( wNorm ); + blending = (blending -0.2) * 0.7; + blending = normalize(max(blending, 0.00001)); // Force weights to sum to 1.0 (very important!) + float b = (blending.x + blending.y + blending.z); + blending /= vec3(b, b, b); + + // texture coords + vec4 coords = wVert; + + // blend the results of the 3 planar projections. + vec4 tex0 = getTriPlanarBlend(coords, blending, m_DiffuseMap, m_DiffuseMap_0_scale); + + #ifdef DIFFUSEMAP_1 + // blend the results of the 3 planar projections. + vec4 tex1 = getTriPlanarBlend(coords, blending, m_DiffuseMap_1, m_DiffuseMap_1_scale); + #endif + #ifdef DIFFUSEMAP_2 + // blend the results of the 3 planar projections. + vec4 tex2 = getTriPlanarBlend(coords, blending, m_DiffuseMap_2, m_DiffuseMap_2_scale); + #endif + #ifdef DIFFUSEMAP_3 + // blend the results of the 3 planar projections. + vec4 tex3 = getTriPlanarBlend(coords, blending, m_DiffuseMap_3, m_DiffuseMap_3_scale); + #endif + #ifdef DIFFUSEMAP_4 + // blend the results of the 3 planar projections. + vec4 tex4 = getTriPlanarBlend(coords, blending, m_DiffuseMap_4, m_DiffuseMap_4_scale); + #endif + #ifdef DIFFUSEMAP_5 + // blend the results of the 3 planar projections. + vec4 tex5 = getTriPlanarBlend(coords, blending, m_DiffuseMap_5, m_DiffuseMap_5_scale); + #endif + #ifdef DIFFUSEMAP_6 + // blend the results of the 3 planar projections. + vec4 tex6 = getTriPlanarBlend(coords, blending, m_DiffuseMap_6, m_DiffuseMap_6_scale); + #endif + #ifdef DIFFUSEMAP_7 + // blend the results of the 3 planar projections. + vec4 tex7 = getTriPlanarBlend(coords, blending, m_DiffuseMap_7, m_DiffuseMap_7_scale); + #endif + #ifdef DIFFUSEMAP_8 + // blend the results of the 3 planar projections. + vec4 tex8 = getTriPlanarBlend(coords, blending, m_DiffuseMap_8, m_DiffuseMap_8_scale); + #endif + #ifdef DIFFUSEMAP_9 + // blend the results of the 3 planar projections. + vec4 tex9 = getTriPlanarBlend(coords, blending, m_DiffuseMap_9, m_DiffuseMap_9_scale); + #endif + #ifdef DIFFUSEMAP_10 + // blend the results of the 3 planar projections. + vec4 tex10 = getTriPlanarBlend(coords, blending, m_DiffuseMap_10, m_DiffuseMap_10_scale); + #endif + #ifdef DIFFUSEMAP_11 + // blend the results of the 3 planar projections. + vec4 tex11 = getTriPlanarBlend(coords, blending, m_DiffuseMap_11, m_DiffuseMap_11_scale); + #endif + + vec4 alphaBlend = texture2D( m_AlphaMap, texCoord.xy ); + + #ifdef ALPHAMAP_1 + vec4 alphaBlend1 = texture2D( m_AlphaMap_1, texCoord.xy ); + #endif + #ifdef ALPHAMAP_2 + vec4 alphaBlend2 = texture2D( m_AlphaMap_2, texCoord.xy ); + #endif + + vec4 diffuseColor = tex0 * alphaBlend.r; + #ifdef DIFFUSEMAP_1 + diffuseColor = mix( diffuseColor, tex1, alphaBlend.g ); + #endif + #ifdef DIFFUSEMAP_2 + diffuseColor = mix( diffuseColor, tex2, alphaBlend.b ); + #endif + #ifdef DIFFUSEMAP_3 + diffuseColor = mix( diffuseColor, tex3, alphaBlend.a ); + #endif + #ifdef ALPHAMAP_1 + #ifdef DIFFUSEMAP_4 + diffuseColor = mix( diffuseColor, tex4, alphaBlend1.r ); + #endif + #ifdef DIFFUSEMAP_5 + diffuseColor = mix( diffuseColor, tex5, alphaBlend1.g ); + #endif + #ifdef DIFFUSEMAP_6 + diffuseColor = mix( diffuseColor, tex6, alphaBlend1.b ); + #endif + #ifdef DIFFUSEMAP_7 + diffuseColor = mix( diffuseColor, tex7, alphaBlend1.a ); + #endif + #endif + #ifdef ALPHAMAP_2 + #ifdef DIFFUSEMAP_8 + diffuseColor = mix( diffuseColor, tex8, alphaBlend2.r ); + #endif + #ifdef DIFFUSEMAP_9 + diffuseColor = mix( diffuseColor, tex9, alphaBlend2.g ); + #endif + #ifdef DIFFUSEMAP_10 + diffuseColor = mix( diffuseColor, tex10, alphaBlend2.b ); + #endif + #ifdef DIFFUSEMAP_11 + diffuseColor = mix( diffuseColor, tex11, alphaBlend2.a ); + #endif + #endif + + return diffuseColor; + } + + vec3 calculateNormalTriPlanar(in vec3 wNorm, in vec4 wVert,in vec2 texCoord) { + // tri-planar texture bending factor for this fragment's world-space normal + vec3 blending = abs( wNorm ); + blending = (blending -0.2) * 0.7; + blending = normalize(max(blending, 0.00001)); // Force weights to sum to 1.0 (very important!) + float b = (blending.x + blending.y + blending.z); + blending /= vec3(b, b, b); + + // texture coords + vec4 coords = wVert; + vec4 alphaBlend = texture2D( m_AlphaMap, texCoord.xy ); + + #ifdef ALPHAMAP_1 + vec4 alphaBlend1 = texture2D( m_AlphaMap_1, texCoord.xy ); + #endif + #ifdef ALPHAMAP_2 + vec4 alphaBlend2 = texture2D( m_AlphaMap_2, texCoord.xy ); + #endif + + vec3 normal = vec3(0,0,1); + vec3 n = vec3(0,0,0); + + #ifdef NORMALMAP + n = getTriPlanarBlend(coords, blending, m_NormalMap, m_DiffuseMap_0_scale).xyz; + normal += n * alphaBlend.r; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.r; + #endif + + #ifdef NORMALMAP_1 + n = getTriPlanarBlend(coords, blending, m_NormalMap_1, m_DiffuseMap_1_scale).xyz; + normal += n * alphaBlend.g; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.g; + #endif + + #ifdef NORMALMAP_2 + n = getTriPlanarBlend(coords, blending, m_NormalMap_2, m_DiffuseMap_2_scale).xyz; + normal += n * alphaBlend.b; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.b; + #endif + + #ifdef NORMALMAP_3 + n = getTriPlanarBlend(coords, blending, m_NormalMap_3, m_DiffuseMap_3_scale).xyz; + normal += n * alphaBlend.a; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.a; + #endif + + #ifdef ALPHAMAP_1 + #ifdef NORMALMAP_4 + n = getTriPlanarBlend(coords, blending, m_NormalMap_4, m_DiffuseMap_4_scale).xyz; + normal += n * alphaBlend1.r; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.r; + #endif + + #ifdef NORMALMAP_5 + n = getTriPlanarBlend(coords, blending, m_NormalMap_5, m_DiffuseMap_5_scale).xyz; + normal += n * alphaBlend1.g; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.g; + #endif + + #ifdef NORMALMAP_6 + n = getTriPlanarBlend(coords, blending, m_NormalMap_6, m_DiffuseMap_6_scale).xyz; + normal += n * alphaBlend1.b; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.b; + #endif + + #ifdef NORMALMAP_7 + n = getTriPlanarBlend(coords, blending, m_NormalMap_7, m_DiffuseMap_7_scale).xyz; + normal += n * alphaBlend1.a; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.a; + #endif + #endif + + #ifdef ALPHAMAP_2 + #ifdef NORMALMAP_8 + n = getTriPlanarBlend(coords, blending, m_NormalMap_8, m_DiffuseMap_8_scale).xyz; + normal += n * alphaBlend2.r; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.r; + #endif + + #ifdef NORMALMAP_9 + n = getTriPlanarBlend(coords, blending, m_NormalMap_9, m_DiffuseMap_9_scale).xyz; + normal += n * alphaBlend2.g; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.g; + #endif + + #ifdef NORMALMAP_10 + n = getTriPlanarBlend(coords, blending, m_NormalMap_10, m_DiffuseMap_10_scale).xyz; + normal += n * alphaBlend2.b; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.b; + #endif + + #ifdef NORMALMAP_11 + n = getTriPlanarBlend(coords, blending, m_NormalMap_11, m_DiffuseMap_11_scale).xyz; + normal += n * alphaBlend2.a; + #else + normal += vec3(0.5,0.5,1) * alphaBlend.a; + #endif + #endif + + normal = (normal.xyz * vec3(2.0) - vec3(1.0)); + return normalize(normal); + } + #endif + +#endif + +void main(){ + + //---------------------- + // diffuse calculations + //---------------------- + #ifdef DIFFUSEMAP + #ifdef ALPHAMAP + #ifdef TRI_PLANAR_MAPPING + vec4 diffuseColor = calculateTriPlanarDiffuseBlend(wNormal, wVertex, texCoord); + #else + vec4 diffuseColor = calculateDiffuseBlend(texCoord); + #endif + #else + vec4 diffuseColor = texture2D(m_DiffuseMap, texCoord); + #endif + #else + vec4 diffuseColor = vec4(1.0); + #endif + + + //--------------------- + // normal calculations + //--------------------- + #if defined(NORMALMAP) || defined(NORMALMAP_1) || defined(NORMALMAP_2) || defined(NORMALMAP_3) || defined(NORMALMAP_4) || defined(NORMALMAP_5) || defined(NORMALMAP_6) || defined(NORMALMAP_7) || defined(NORMALMAP_8) || defined(NORMALMAP_9) || defined(NORMALMAP_10) || defined(NORMALMAP_11) + #ifdef TRI_PLANAR_MAPPING + vec3 normal = calculateNormalTriPlanar(wNormal, wVertex, texCoord); + #else + vec3 normal = calculateNormal(texCoord); + #endif + mat3 tbnMat = mat3(normalize(vTangent.xyz) , normalize(vBinormal.xyz) , normalize(vNormal.xyz)); + #else + vec3 normal = vNormal; + #endif + + + //----------------------- + // lighting calculations + //----------------------- + gl_FragColor = AmbientSum * diffuseColor; + for( int i = 0;i < NB_LIGHTS; i+=3){ + vec4 lightColor = g_LightData[i]; + vec4 lightData1 = g_LightData[i+1]; + vec4 lightDir; + vec3 lightVec; + lightComputeDir(vPos, lightColor.w, lightData1, lightDir, lightVec); + + float spotFallOff = 1.0; + #if __VERSION__ >= 110 + // allow use of control flow + if(lightColor.w > 1.0){ + #endif + spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec); + #if __VERSION__ >= 110 + } + #endif + + #ifdef NORMALMAP + //Normal map -> lighting is computed in tangent space + lightDir.xyz = normalize(lightDir.xyz * tbnMat); + vec3 viewDir = normalize(-vPos.xyz * tbnMat); + #else + //no Normal map -> lighting is computed in view space + lightDir.xyz = normalize(lightDir.xyz); + vec3 viewDir = normalize(-vPos.xyz); + #endif + + vec2 light = computeLighting(normal, viewDir, lightDir.xyz, lightDir.w * spotFallOff, m_Shininess); + gl_FragColor.rgb += DiffuseSum.rgb * lightColor.rgb * diffuseColor.rgb * vec3(light.x) + + SpecularSum.rgb * vec3(light.y); + } + +} \ No newline at end of file diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/SPTerrainLighting.vert b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/SPTerrainLighting.vert new file mode 100644 index 000000000..78036c93c --- /dev/null +++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/SPTerrainLighting.vert @@ -0,0 +1,66 @@ +uniform mat4 g_WorldViewProjectionMatrix; +uniform mat4 g_WorldViewMatrix; +uniform mat3 g_NormalMatrix; +uniform mat4 g_ViewMatrix; + +uniform vec4 g_AmbientLightColor; + +attribute vec3 inPosition; +attribute vec3 inNormal; +attribute vec2 inTexCoord; +attribute vec4 inTangent; + +varying vec3 vNormal; +varying vec2 texCoord; +varying vec3 vPos; +varying vec3 vTangent; +varying vec3 vBinormal; + +varying vec4 AmbientSum; +varying vec4 DiffuseSum; +varying vec4 SpecularSum; + +#ifdef TRI_PLANAR_MAPPING + varying vec4 wVertex; + varying vec3 wNormal; +#endif + + + +void main(){ + vec4 pos = vec4(inPosition, 1.0); + gl_Position = g_WorldViewProjectionMatrix * pos; + #ifdef TERRAIN_GRID + texCoord = inTexCoord * 2.0; + #else + texCoord = inTexCoord; + #endif + + vec3 wvPosition = (g_WorldViewMatrix * pos).xyz; + vec3 wvNormal = normalize(g_NormalMatrix * inNormal); + + //-------------------------- + // specific to normal maps: + //-------------------------- + #if defined(NORMALMAP) || defined(NORMALMAP_1) || defined(NORMALMAP_2) || defined(NORMALMAP_3) || defined(NORMALMAP_4) || defined(NORMALMAP_5) || defined(NORMALMAP_6) || defined(NORMALMAP_7) || defined(NORMALMAP_8) || defined(NORMALMAP_9) || defined(NORMALMAP_10) || defined(NORMALMAP_11) + vTangent = g_NormalMatrix * inTangent.xyz; + vBinormal = cross(wvNormal, vTangent)* inTangent.w; + #endif + + //------------------------- + // general to all lighting + //------------------------- + vNormal = wvNormal; + vPos = wvPosition; + + AmbientSum = g_AmbientLightColor; + DiffuseSum = vec4(1.0); + SpecularSum = vec4(0.0); + + +#ifdef TRI_PLANAR_MAPPING + wVertex = vec4(inPosition,0.0); + wNormal = inNormal; +#endif + +} \ No newline at end of file diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.frag b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.frag index 68bd2d236..8ab9b993b 100644 --- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.frag +++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.frag @@ -1,3 +1,5 @@ +#import "Common/ShaderLib/PhongLighting.glsllib" +#import "Common/ShaderLib/Lighting.glsllib" uniform float m_Shininess; uniform vec4 g_LightDirection; @@ -145,54 +147,6 @@ varying vec3 lightVec; varying vec3 wNormal; #endif - - -float tangDot(in vec3 v1, in vec3 v2){ - float d = dot(v1,v2); - #ifdef V_TANGENT - d = 1.0 - d*d; - return step(0.0, d) * sqrt(d); - #else - return d; - #endif -} - - -float lightComputeDiffuse(in vec3 norm, in vec3 lightdir, in vec3 viewdir){ - return max(0.0, dot(norm, lightdir)); -} - -float lightComputeSpecular(in vec3 norm, in vec3 viewdir, in vec3 lightdir, in float shiny){ - #ifdef WARDISO - // Isotropic Ward - vec3 halfVec = normalize(viewdir + lightdir); - float NdotH = max(0.001, tangDot(norm, halfVec)); - float NdotV = max(0.001, tangDot(norm, viewdir)); - float NdotL = max(0.001, tangDot(norm, lightdir)); - float a = tan(acos(NdotH)); - float p = max(shiny/128.0, 0.001); - return NdotL * (1.0 / (4.0*3.14159265*p*p)) * (exp(-(a*a)/(p*p)) / (sqrt(NdotV * NdotL))); - #else - // Standard Phong - vec3 R = reflect(-lightdir, norm); - return pow(max(tangDot(R, viewdir), 0.0), shiny); - #endif -} - -vec2 computeLighting(in vec3 wvPos, in vec3 wvNorm, in vec3 wvViewDir, in vec3 wvLightDir){ - float diffuseFactor = lightComputeDiffuse(wvNorm, wvLightDir, wvViewDir); - float specularFactor = lightComputeSpecular(wvNorm, wvViewDir, wvLightDir, m_Shininess); - - if (m_Shininess <= 1.0) { - specularFactor = 0.0; // should be one instruction on most cards .. - } - - float att = vLightDir.w; - - return vec2(diffuseFactor, specularFactor) * vec2(att); -} - - #ifdef ALPHAMAP vec4 calculateDiffuseBlend(in vec2 texCoord) { @@ -355,7 +309,7 @@ vec2 computeLighting(in vec3 wvPos, in vec3 wvNorm, in vec3 wvViewDir, in vec3 w vec4 getTriPlanarBlend(in vec4 coords, in vec3 blending, in sampler2D map, in float scale) { vec4 col1 = texture2D( map, coords.yz * scale); vec4 col2 = texture2D( map, coords.xz * scale); - vec4 col3 = texture2D( map, coords.xy * scale); + vec4 col3 = texture2D( map, coords.xy * scale); // blend the results of the 3 planar projections. vec4 tex = col1 * blending.x + col2 * blending.y + col3 * blending.z; return tex; @@ -627,7 +581,7 @@ void main(){ spotFallOff = clamp(spotFallOff, 0.0, 1.0); } } - + //--------------------- // normal calculations //--------------------- @@ -648,7 +602,7 @@ void main(){ vec4 lightDir = vLightDir; lightDir.xyz = normalize(lightDir.xyz); - vec2 light = computeLighting(vPosition, normal, vViewDir.xyz, lightDir.xyz)*spotFallOff; + vec2 light = computeLighting(normal, vViewDir.xyz, lightDir.xyz,lightDir.w*spotFallOff,m_Shininess); vec4 specularColor = vec4(1.0); diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.j3md b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.j3md index 04470ca26..48c404da4 100644 --- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.j3md +++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.j3md @@ -163,6 +163,70 @@ MaterialDef Terrain Lighting { } } + + Technique { + + LightMode SinglePass + + VertexShader GLSL100: Common/MatDefs/Terrain/SPTerrainLighting.vert + FragmentShader GLSL100: Common/MatDefs/Terrain/SPTerrainLighting.frag + + WorldParameters { + WorldViewProjectionMatrix + NormalMatrix + WorldViewMatrix + ViewMatrix + } + + Defines { + TRI_PLANAR_MAPPING : useTriPlanarMapping + TERRAIN_GRID : isTerrainGrid + WARDISO : WardIso + + DIFFUSEMAP : DiffuseMap + DIFFUSEMAP_1 : DiffuseMap_1 + DIFFUSEMAP_2 : DiffuseMap_2 + DIFFUSEMAP_3 : DiffuseMap_3 + DIFFUSEMAP_4 : DiffuseMap_4 + DIFFUSEMAP_5 : DiffuseMap_5 + DIFFUSEMAP_6 : DiffuseMap_6 + DIFFUSEMAP_7 : DiffuseMap_7 + DIFFUSEMAP_8 : DiffuseMap_8 + DIFFUSEMAP_9 : DiffuseMap_9 + DIFFUSEMAP_10 : DiffuseMap_10 + DIFFUSEMAP_11 : DiffuseMap_11 + NORMALMAP : NormalMap + NORMALMAP_1 : NormalMap_1 + NORMALMAP_2 : NormalMap_2 + NORMALMAP_3 : NormalMap_3 + NORMALMAP_4 : NormalMap_4 + NORMALMAP_5 : NormalMap_5 + NORMALMAP_6 : NormalMap_6 + NORMALMAP_7 : NormalMap_7 + NORMALMAP_8 : NormalMap_8 + NORMALMAP_9 : NormalMap_9 + NORMALMAP_10 : NormalMap_10 + NORMALMAP_11 : NormalMap_11 + SPECULARMAP : SpecularMap + ALPHAMAP : AlphaMap + ALPHAMAP_1 : AlphaMap_1 + ALPHAMAP_2 : AlphaMap_2 + DIFFUSEMAP_0_SCALE : DiffuseMap_0_scale + DIFFUSEMAP_1_SCALE : DiffuseMap_1_scale + DIFFUSEMAP_2_SCALE : DiffuseMap_2_scale + DIFFUSEMAP_3_SCALE : DiffuseMap_3_scale + DIFFUSEMAP_4_SCALE : DiffuseMap_4_scale + DIFFUSEMAP_5_SCALE : DiffuseMap_5_scale + DIFFUSEMAP_6_SCALE : DiffuseMap_6_scale + DIFFUSEMAP_7_SCALE : DiffuseMap_7_scale + DIFFUSEMAP_8_SCALE : DiffuseMap_8_scale + DIFFUSEMAP_9_SCALE : DiffuseMap_9_scale + DIFFUSEMAP_10_SCALE : DiffuseMap_10_scale + DIFFUSEMAP_11_SCALE : DiffuseMap_11_scale + } + } + + Technique PreShadow { VertexShader GLSL100 : Common/MatDefs/Shadow/PreShadow.vert diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.vert b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.vert index a3a1cc24e..e03f03f7f 100644 --- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.vert +++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.vert @@ -1,3 +1,5 @@ +#import "Common/ShaderLib/Lighting.glsllib" + uniform mat4 g_WorldViewProjectionMatrix; uniform mat4 g_WorldViewMatrix; uniform mat3 g_NormalMatrix; @@ -34,16 +36,6 @@ varying vec4 SpecularSum; varying vec3 wNormal; #endif -// JME3 lights in world space -void lightComputeDir(in vec3 worldPos, in vec4 color, in vec4 position, out vec4 lightDir){ - float posLight = step(0.5, color.w); - vec3 tempVec = position.xyz * sign(posLight - 0.5) - (worldPos * posLight); - lightVec.xyz = tempVec; - float dist = length(tempVec); - lightDir.w = clamp(1.0 - position.w * dist * posLight, 0.0, 1.0); - lightDir.xyz = tempVec / vec3(dist); -} - void main(){ vec4 pos = vec4(inPosition, 1.0); @@ -66,35 +58,30 @@ void main(){ // specific to normal maps: //-------------------------- #if defined(NORMALMAP) || defined(NORMALMAP_1) || defined(NORMALMAP_2) || defined(NORMALMAP_3) || defined(NORMALMAP_4) || defined(NORMALMAP_5) || defined(NORMALMAP_6) || defined(NORMALMAP_7) || defined(NORMALMAP_8) || defined(NORMALMAP_9) || defined(NORMALMAP_10) || defined(NORMALMAP_11) - vec3 wvTangent = normalize(g_NormalMatrix * inTangent.xyz); - vec3 wvBinormal = cross(wvNormal, wvTangent); + vec3 wvTangent = normalize(g_NormalMatrix * inTangent.xyz); + vec3 wvBinormal = cross(wvNormal, wvTangent); - mat3 tbnMat = mat3(wvTangent, wvBinormal * -inTangent.w,wvNormal); + mat3 tbnMat = mat3(wvTangent, wvBinormal * inTangent.w,wvNormal); - vPosition = wvPosition * tbnMat; - vViewDir = viewDir * tbnMat; - lightComputeDir(wvPosition, lightColor, wvLightPos, vLightDir); - vLightDir.xyz = (vLightDir.xyz * tbnMat).xyz; - #else + vPosition = wvPosition * tbnMat; + vViewDir = viewDir * tbnMat; - //------------------------- - // general to all lighting - //------------------------- - vNormal = wvNormal; + lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec); + vLightDir.xyz = (vLightDir.xyz * tbnMat).xyz; + #else + //------------------------- + // general to all lighting + //------------------------- + vNormal = wvNormal; - vPosition = wvPosition; - vViewDir = viewDir; + vPosition = wvPosition; + vViewDir = viewDir; - lightComputeDir(wvPosition, lightColor, wvLightPos, vLightDir); + lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec); #endif - //computing spot direction in view space and unpacking spotlight cos - // spotVec=(g_ViewMatrix *vec4(g_LightDirection.xyz,0.0) ); - // spotVec.w=floor(g_LightDirection.w)*0.001; - // lightVec.w = fract(g_LightDirection.w); - - AmbientSum = vec4(0.2, 0.2, 0.2, 1.0) * g_AmbientLightColor; // Default: ambient color is dark gray + AmbientSum = g_AmbientLightColor; // Default: ambient color is dark gray DiffuseSum = lightColor; SpecularSum = lightColor;