Kaynağa Gözat

Single pass lighting implementation.
Along with some light shaders refactoring and clean up

Nehon 11 yıl önce
ebeveyn
işleme
c55717141e

+ 96 - 55
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) <br/> </p>
      */
-    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;

+ 9 - 2
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<Caps> rendererCaps) {
+    public void makeCurrent(AssetManager assetManager, boolean techniqueSwitched, EnumSet<Caps> 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) {

+ 30 - 0
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.
      * <p>

+ 26 - 106
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;

+ 45 - 36
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 {
         }
     }
 
-}
+}

+ 26 - 87
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 
 }

+ 218 - 0
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;
+}

+ 172 - 0
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 
+}

+ 22 - 40
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);
 }
+

+ 29 - 0
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);
+}

+ 255 - 0
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) {
+        }
+    }
+}

+ 615 - 0
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);
+    }
+
+}

+ 66 - 0
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
+
+}

+ 5 - 51
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);
 

+ 64 - 0
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

+ 18 - 31
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;