Przeglądaj źródła

Implement static pass in the lighting material

Kirill Vainer 8 lat temu
rodzic
commit
77e552f551

+ 25 - 1
jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md

@@ -27,6 +27,9 @@ MaterialDef Phong Lighting {
         // Specular power/shininess
         Float Shininess : 1
 
+        // Ambient map
+        Texture2D AmbientMap
+
         // Diffuse map
         Texture2D DiffuseMap
 
@@ -79,7 +82,7 @@ MaterialDef Phong Lighting {
         Boolean EnvMapAsSphereMap
 
         //shadows
-         Int FilterMode
+        Int FilterMode
         Boolean HardwareShadows
 
         Texture2D ShadowMap0
@@ -117,6 +120,27 @@ MaterialDef Phong Lighting {
         Boolean BackfaceShadows : false
     }
 
+    Technique {
+        LightMode StaticPass
+ 
+        VertexShader   GLSL100 GLSL150 : Common/MatDefs/Light/StaticLighting.vert
+        FragmentShader GLSL100 GLSL150 : Common/MatDefs/Light/StaticLighting.frag
+ 
+        WorldParameters {
+            WorldViewProjectionMatrix
+            NormalMatrix
+            WorldViewMatrix
+            ViewMatrix
+            CameraPosition
+            WorldMatrix
+            ViewProjectionMatrix
+        }
+ 
+        Defines {
+            AMBIENTMAP : AmbientMap
+        }
+    }
+
     Technique {
         LightMode SinglePass
 

+ 203 - 0
jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.frag

@@ -0,0 +1,203 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+#import "Common/ShaderLib/BlinnPhongLighting.glsllib"
+#import "Common/ShaderLib/Lighting.glsllib"
+#import "Common/ShaderLib/InPassShadows.glsl"
+
+#ifndef NUM_DIR_LIGHTS
+#define NUM_DIR_LIGHTS 0
+#endif
+
+#ifndef NUM_POINT_LIGHTS
+#define NUM_POINT_LIGHTS 0
+#endif
+
+#ifndef NUM_SPOT_LIGHTS
+#define NUM_SPOT_LIGHTS 0
+#endif
+
+#define DIR_SHADOW_LIGHT_START    (0)
+#define DIR_SHADOW_LIGHT_END      (NUM_SHADOW_DIR_LIGHTS * 2)
+
+#define DIR_LIGHT_START           (DIR_SHADOW_LIGHT_END)
+#define DIR_LIGHT_END             (NUM_DIR_LIGHTS * 2)
+
+#define POINT_LIGHT_START         (DIR_LIGHT_END)
+#define POINT_LIGHT_END           (POINT_LIGHT_START + NUM_POINT_LIGHTS * 2)
+
+#define SPOT_SHADOW_LIGHT_START   (POINT_LIGHT_END)
+#define SPOT_SHADOW_LIGHT_END     (SPOT_SHADOW_LIGHT_START + NUM_SHADOW_SPOT_LIGHTS * 3)
+
+#define SPOT_LIGHT_START          (SPOT_SHADOW_LIGHT_END)
+#define SPOT_LIGHT_END            (SPOT_LIGHT_START + NUM_SPOT_LIGHTS * 3)
+
+#define LIGHT_DATA_SIZE           (SPOT_LIGHT_END)
+
+uniform sampler2D m_AmbientMap;
+uniform float m_AlphaDiscardThreshold;
+uniform float m_Shininess;
+uniform vec4 g_AmbientLightColor;
+
+#if LIGHT_DATA_SIZE > 0
+uniform vec4 g_LightData[LIGHT_DATA_SIZE];
+#else
+const vec4 g_LightData[1] = vec4[]( vec4(1.0) );
+#endif
+
+varying vec3 vPos;
+varying vec3 vNormal;
+varying vec2 vTexCoord;
+
+struct surface_t {
+    vec3 position;
+    vec3 normal;
+    vec3 viewDir;
+    vec3 ambient;
+    vec4 diffuse;
+    vec4 specular;
+    float shininess;
+};
+
+vec2 Lighting_ProcessLighting(vec3 norm, vec3 viewDir, vec3 lightDir, float attenuation, float shininess) {
+    float diffuseFactor = max(0.0, dot(norm, lightDir));
+    vec3 H = normalize(viewDir + lightDir);
+    float HdotN = max(0.0, dot(H, norm));
+    float specularFactor = pow(HdotN, shininess);
+    return vec2(diffuseFactor, diffuseFactor * specularFactor) * vec2(attenuation);
+}
+
+vec2 Lighting_ProcessDirectional(int lightIndex, surface_t surface) {
+    vec3 lightDirection = g_LightData[lightIndex + 1].xyz;
+    vec2 light = Lighting_ProcessLighting(surface.normal, surface.viewDir, -lightDirection, 1.0, surface.shininess);
+    return light;
+}
+
+float Lighting_ProcessAttenuation(float invRadius, float dist) {
+    #ifdef SRGB
+        float atten = (1.0 - invRadius * dist) / (1.0 + invRadius * dist * dist);
+        return clamp(atten, 0.0, 1.0);
+    #else
+        return max(0.0, 1.0 - invRadius * dist);
+    #endif
+}
+
+vec2 Lighting_ProcessPoint(int lightIndex, surface_t surface) {
+    vec4 lightPosition  = g_LightData[lightIndex + 1];
+    vec3 lightDirection = lightPosition.xyz - surface.position;
+    float dist = length(lightDirection);
+    lightDirection /= vec3(dist);
+    float atten = Lighting_ProcessAttenuation(lightPosition.w, dist);
+    return Lighting_ProcessLighting(surface.normal, surface.viewDir, lightDirection, atten, surface.shininess);
+}
+
+vec2 Lighting_ProcessSpot(int lightIndex, surface_t surface) {
+    vec4 lightPosition  = g_LightData[lightIndex + 1];
+    vec4 lightDirection = g_LightData[lightIndex + 2];
+    vec3 lightVector    = lightPosition.xyz - surface.position;
+    float dist          = length(lightVector);
+    lightVector        /= vec3(dist);
+    float atten         = Lighting_ProcessAttenuation(lightPosition.w, dist);
+    atten              *= computeSpotFalloff(lightDirection, lightVector);
+    return Lighting_ProcessLighting(surface.normal, surface.viewDir, lightVector, atten, surface.shininess);
+}
+
+void Lighting_ProcessAll(surface_t surface, out vec3 ambient, out vec3 diffuse, out vec3 specular) {
+
+    ambient  = g_AmbientLightColor.rgb;
+    diffuse  = vec3(0.0);
+    specular = vec3(0.0);
+
+    Shadow_ProcessPssmSlice();
+
+#if LIGHT_DATA_SIZE > 0
+    int projIndex = 0;
+
+    for (int i = DIR_SHADOW_LIGHT_START; i < DIR_SHADOW_LIGHT_END; i += 2) {
+        vec4 lightColor = g_LightData[i];
+        vec2 lightDiffSpec = Lighting_ProcessDirectional(i, surface);
+        float shadow = Shadow_ProcessDirectional(projIndex, lightColor.w);
+        lightDiffSpec *= vec2(shadow);
+        diffuse  += lightColor.rgb * lightDiffSpec.x;
+        specular += lightColor.rgb * lightDiffSpec.y;
+        projIndex += NUM_PSSM_SPLITS;
+    }
+
+    for (int i = DIR_LIGHT_START; i < DIR_LIGHT_END; i += 2) {
+        vec3 lightColor = g_LightData[i].rgb;
+        vec2 lightDiffSpec = Lighting_ProcessDirectional(i, surface);
+        diffuse  += lightColor.rgb * lightDiffSpec.x;
+        specular += lightColor.rgb * lightDiffSpec.y;
+    }
+
+    for (int i = POINT_LIGHT_START; i < POINT_LIGHT_END; i += 2) {
+        vec3 lightColor = g_LightData[i].rgb;
+        vec2 lightDiffSpec = Lighting_ProcessPoint(i, surface);
+        diffuse  += lightColor.rgb * lightDiffSpec.x;
+        specular += lightColor.rgb * lightDiffSpec.y;
+    }
+
+    for (int i = SPOT_SHADOW_LIGHT_START; i < SPOT_SHADOW_LIGHT_END; i += 3) {
+        vec4 lightColor = g_LightData[i];
+        vec2 lightDiffSpec = Lighting_ProcessSpot(i, surface);
+        float shadow = Shadow_ProcessSpot(projIndex, lightColor.w);
+        lightDiffSpec *= vec2(shadow);
+        diffuse  += lightColor.rgb * lightDiffSpec.x;
+        specular += lightColor.rgb * lightDiffSpec.y;
+        projIndex++;
+    }
+
+    for (int i = SPOT_LIGHT_START; i < SPOT_LIGHT_END; i += 3) {
+        vec3 lightColor = g_LightData[i].rgb;
+        vec2 lightDiffSpec = Lighting_ProcessSpot(i, surface);
+        diffuse  += lightColor * lightDiffSpec.x;
+        specular += lightColor * lightDiffSpec.y;
+    }
+
+#endif
+}
+
+surface_t getSurface() {
+    surface_t s;
+    s.position = vPos;
+    s.normal = normalize(vNormal);
+    if (!gl_FrontFacing) {
+        s.normal = -s.normal;
+    }
+    s.viewDir = normalize(-vPos);
+#ifdef AMBIENTMAP
+    s.ambient = texture2D(m_AmbientMap, vTexCoord).rgb;
+#else
+    s.ambient = vec3(1.0);
+#endif
+    s.diffuse = vec4(1.0);
+    s.specular = vec4(1.0);
+    s.shininess = m_Shininess;
+    return s;
+}
+
+void main() {
+    vec3 ambient, diffuse, specular;
+
+    surface_t surface = getSurface();
+    Lighting_ProcessAll(surface, ambient, diffuse, specular);
+
+    vec4 color = vec4(1.0);
+    color.rgb = surface.ambient.rgb  * ambient +
+                surface.diffuse.rgb  * diffuse +
+                surface.specular.rgb * specular;
+
+    #ifdef DISCARD_ALPHA
+        if (color.a < m_AlphaDiscardThreshold) {
+            discard;
+        }
+    #endif
+
+    gl_FragColor = color;
+
+/*
+    vec4 projCoord = vProjCoord[0];
+    projCoord.xyz /= projCoord.w;
+    float shad = shadow2D(g_ShadowMapArray, vec4(projCoord.xy, 0.0, projCoord.z)).r;
+    vec3 amb = texture2D(m_AmbientMap, vTexCoord).rgb;
+    gl_FragColor = vec4(amb * vec3(shad), 1.0);
+*/
+}

+ 32 - 0
jme3-core/src/main/resources/Common/MatDefs/Light/StaticLighting.vert

@@ -0,0 +1,32 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+#import "Common/ShaderLib/Skinning.glsllib"
+#import "Common/ShaderLib/Instancing.glsllib"
+#import "Common/ShaderLib/InPassShadows.glsl"
+
+attribute vec3 inPosition;
+attribute vec3 inNormal;
+attribute vec2 inTexCoord;
+attribute vec4 inColor;
+
+varying vec3 vPos;
+varying vec3 vNormal;
+varying vec2 vTexCoord;
+
+void main() {
+    vTexCoord = inTexCoord;
+
+    vec4 modelSpacePos = vec4(inPosition, 1.0);
+    vec3 modelSpaceNorm = inNormal;
+
+    #ifdef NUM_BONES
+        Skinning_Compute(modelSpacePos, modelSpaceNorm);
+    #endif
+
+    vPos = TransformWorldView(modelSpacePos).xyz;
+    vNormal = TransformNormal(modelSpaceNorm);
+
+    vec3 shadowPos = TransformWorld(modelSpacePos).xyz;
+    Shadow_ProcessProjCoord(shadowPos);
+
+    gl_Position = TransformWorldViewProjection(modelSpacePos);
+}

+ 133 - 0
jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsl

@@ -0,0 +1,133 @@
+#ifndef NUM_SHADOW_DIR_LIGHTS
+#define NUM_SHADOW_DIR_LIGHTS 0
+#endif
+#ifndef NUM_SHADOW_POINT_LIGHTS
+#define NUM_SHADOW_POINT_LIGHTS 0
+#endif
+#ifndef NUM_SHADOW_SPOT_LIGHTS
+#define NUM_SHADOW_SPOT_LIGHTS 0
+#endif
+#ifndef NUM_PSSM_SPLITS
+#define NUM_PSSM_SPLITS 0
+#endif
+
+#define SHADOW_DATA_SIZE (NUM_SHADOW_DIR_LIGHTS * NUM_PSSM_SPLITS + NUM_SHADOW_POINT_LIGHTS * 6 + NUM_SHADOW_SPOT_LIGHTS)
+
+#if SHADOW_DATA_SIZE > 0
+
+    varying vec4 vProjCoord[SHADOW_DATA_SIZE];
+
+    #ifdef VERTEX_SHADER
+        uniform mat4 g_ShadowMatrices[SHADOW_DATA_SIZE];
+
+        void Shadow_ProcessProjCoord(vec3 worldPos) {
+            for (int i = 0; i < SHADOW_DATA_SIZE; i++) {
+                vProjCoord[i] = g_ShadowMatrices[i] * vec4(worldPos, 1.0);
+            }
+        }
+    #else
+        uniform sampler2DArrayShadow g_ShadowMapArray;
+        uniform vec4 g_PssmSplits;
+
+        int pssmSliceOffset;
+
+        void Shadow_ProcessPssmSlice() {
+            #ifdef NUM_PSSM_SPLITS
+                float z = gl_FragCoord.z;
+                if (z < g_PssmSplits[0]) {
+                    pssmSliceOffset = 0;
+                } else if (z < g_PssmSplits[1]) {
+                    pssmSliceOffset = 1;
+                } else if (z < g_PssmSplits[2]) {
+                    pssmSliceOffset = 2;
+                } else {
+                    pssmSliceOffset = 3;
+                }
+            #else
+                pssmSliceOffset = 0;
+            #endif
+        }
+
+        float Shadow_ProcessDirectional(int startProjIndex, float startArrayLayer) {
+            float arraySlice = startArrayLayer + float(pssmSliceOffset);
+            vec3 projCoord = vProjCoord[startProjIndex + pssmSliceOffset].xyz;
+            return texture(g_ShadowMapArray, vec4(projCoord.xy, arraySlice, projCoord.z));
+        }
+
+        float Shadow_ProcessSpot(int startProjIndex, float startArrayLayer) {
+            vec4 projCoord = vProjCoord[startProjIndex];
+            projCoord.xyz /= projCoord.w;
+            return texture(g_ShadowMapArray, vec4(projCoord.xy, startArrayLayer, projCoord.z));
+        }
+    #endif
+
+#elif NUM_PSSM_SPLITS > 0
+
+    // A lightweight version of in-pass lighting that only handles directional lights
+    // Control flow and loop iteration count are static
+
+    varying vec4 vProjCoord[NUM_PSSM_SPLITS];
+
+    #ifdef VERTEX_SHADER
+        uniform mat4 g_DirectionalShadowMatrix[NUM_PSSM_SPLITS];
+        void Shadow_ProcessProjCoord(vec3 worldPos) {
+            for (int i = 0; i < NUM_PSSM_SPLITS; i++) {
+                vProjCoord[i] = g_DirectionalShadowMatrix[i] * vec4(worldPos, 1.0);
+            }
+        }
+    #else
+        uniform sampler2DShadow g_DirectionalShadowMap[NUM_PSSM_SPLITS];
+        uniform vec4 g_PssmSplits;
+
+        const vec2 invTexSize = vec2(1.0 / 1024.0);
+
+        float Shadow_SampleOffset(sampler2DShadow shadowMap, vec4 projCoord, vec2 offset) {
+            return shadow2D(shadowMap, vec3(projCoord.xy + offset * invTexSize, projCoord.z)).r;
+        }
+
+        float Shadow_Sample(sampler2DShadow shadowMap, vec4 projCoord) {
+            return shadow2D(shadowMap, projCoord.xyz).r;
+        }
+
+        #define GET_SHADOW(i) if (z < g_PssmSplits[i]) return Shadow_Sample(g_DirectionalShadowMap[i], vProjCoord[i]);
+
+        void Shadow_ProcessPssmSlice() {
+        }
+
+        float Shadow_ProcessDirectional() {
+            float z = gl_FragCoord.z;
+
+            GET_SHADOW(0);
+            #if NUM_PSSM_SPLITS > 1
+                GET_SHADOW(1)
+                #if NUM_PSSM_SPLITS > 2
+                    GET_SHADOW(2)
+                    #if NUM_PSSM_SPLITS > 3
+                        GET_SHADOW(3)
+                    #endif
+                #endif
+            #endif
+
+            return 1.0;
+        }
+    #endif
+#else
+    #define NUM_SHADOW_DIR_LIGHTS 0
+    #define NUM_SHADOW_POINT_LIGHTS 0
+    #define NUM_SHADOW_SPOT_LIGHTS 0
+    #define NUM_PSSM_SPLITS 0
+
+    void Shadow_ProcessProjCoord(vec3 worldPos) {
+    }
+
+    void Shadow_ProcessPssmSlice() {
+    }
+
+    float Shadow_ProcessDirectional(int startLightIndex, float startArrayLayer) {
+        return 1.0;
+    }
+
+    float Shadow_ProcessSpot(int startLightIndex, float startArrayLayer) {
+        return 1.0;
+    }
+#endif

+ 1 - 1
jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java

@@ -646,7 +646,7 @@ public class J3MLoader implements AssetLoader {
                 technique.setLogic(new SinglePassLightingLogic(technique));
                 break;
             case StaticPass:
-                technique.setLogic(new StaticPassLightingLogic(technique));
+                technique.setLogic(new ShadowStaticPassLightingLogic(technique));
                 break;
             case SinglePassAndImageBased:
                 technique.setLogic(new SinglePassAndImageBasedLightingLogic(technique));

+ 4 - 3
jme3-core/src/plugins/java/com/jme3/shader/plugins/GLSLLoader.java

@@ -49,7 +49,7 @@ import java.util.*;
 public class GLSLLoader implements AssetLoader {
 
     private AssetManager assetManager;
-    private Map<String, ShaderDependencyNode> dependCache = new HashMap<String, ShaderDependencyNode>();
+    private final Map<String, ShaderDependencyNode> dependCache = new HashMap<>();
 
     /**
      * Used to load {@link ShaderDependencyNode}s.
@@ -168,7 +168,7 @@ public class GLSLLoader implements AssetLoader {
             return node.getSource();
         } else {
             StringBuilder sb = new StringBuilder(node.getSource());
-            List<String> resolvedShaderNodes = new ArrayList<String>();
+            List<String> resolvedShaderNodes = new ArrayList<>();
 
             for (ShaderDependencyNode dependencyNode : node.getDependencies()) {
                 resolvedShaderNodes.add(resolveDependencies(dependencyNode, alreadyInjectedSet, extensions));
@@ -187,7 +187,8 @@ public class GLSLLoader implements AssetLoader {
         // to retrieve the fragment shader, use the content manager
         this.assetManager = info.getManager();
         Reader reader = new InputStreamReader(info.openStream());
-        if (info.getKey().getExtension().equals("glsllib")) {
+        String extension = info.getKey().getExtension();
+        if (extension.equals("glsllib") || extension.equals("glsl")) {
             // NOTE: Loopback, GLSLLIB is loaded by this loader
             // and needs data as InputStream
             return reader;