Quellcode durchsuchen

Techniques are now weighted and sorted depending on their LightMode and GLSL version

Nehon vor 8 Jahren
Ursprung
Commit
cb04548fd5

+ 4 - 8
jme3-core/src/main/java/com/jme3/material/Material.java

@@ -704,15 +704,14 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
      * @throws UnsupportedOperationException If no candidate technique supports
      * the system capabilities.
      */
-    public void selectTechnique(String name, RenderManager renderManager) {
+    public void selectTechnique(String name, final RenderManager renderManager) {
         // check if already created
         Technique tech = techniques.get(name);
         // When choosing technique, we choose one that
         // supports all the caps.
         if (tech == null) {
             EnumSet<Caps> rendererCaps = renderManager.getRenderer().getCaps();
-            List<TechniqueDef> techDefs = def.getTechniqueDefs(name);
-
+            List<TechniqueDef> techDefs = def.getSortedTechniqueDefs(name, renderManager);
             if (techDefs == null || techDefs.isEmpty()) {
                 throw new IllegalArgumentException(
                         String.format("The requested technique %s is not available on material %s", name, def.getName()));
@@ -724,10 +723,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
                     // use the first one that supports all the caps
                     tech = new Technique(this, techDef);
                     techniques.put(name, tech);
-                    if (tech.getDef().getLightMode() == renderManager.getPreferredLightMode()
-                            || tech.getDef().getLightMode() == LightMode.Disable) {
-                        break;
-                    }
+                    break;
                 }
                 lastTech = techDef;
             }
@@ -779,7 +775,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
     }
 
     private int updateShaderMaterialParameters(Renderer renderer, Shader shader,
-                 SafeArrayList<MatParamOverride> worldOverrides, SafeArrayList<MatParamOverride> forcedOverrides) {
+                                               SafeArrayList<MatParamOverride> worldOverrides, SafeArrayList<MatParamOverride> forcedOverrides) {
 
         int unit = 0;
         if (worldOverrides != null) {

+ 26 - 2
jme3-core/src/main/java/com/jme3/material/MaterialDef.java

@@ -32,11 +32,10 @@
 package com.jme3.material;
 
 import com.jme3.asset.AssetManager;
-import com.jme3.export.*;
+import com.jme3.renderer.RenderManager;
 import com.jme3.shader.VarType;
 import com.jme3.texture.image.ColorSpace;
 
-import java.io.IOException;
 import java.util.*;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -56,6 +55,7 @@ public class MaterialDef{
 
     private Map<String, List<TechniqueDef>> techniques;
     private Map<String, MatParam> matParams;
+    private TechDefComparator comparator = new TechDefComparator();
 
     /**
      * Serialization only. Do not use.
@@ -188,6 +188,17 @@ public class MaterialDef{
         return techniques.get(name);
     }
 
+    public List<TechniqueDef> getSortedTechniqueDefs(String name, RenderManager rm) {
+        List<TechniqueDef> techDefs = getTechniqueDefs(name);
+        if (techDefs == null) {
+            return null;
+        }
+        //Sorting the techdef depending on their weight (depending on their glsl version) and on the preferred light mode)
+        comparator.rm = rm;
+        Collections.sort(techDefs, comparator);
+        return techDefs;
+    }
+
     /**
      *
      * @return the list of all the technique definitions names.
@@ -196,4 +207,17 @@ public class MaterialDef{
         return techniques.keySet();
     }
 
+    public static class TechDefComparator implements Comparator<TechniqueDef> {
+
+        RenderManager rm;
+
+        @Override
+        public int compare(TechniqueDef o1, TechniqueDef o2) {
+            float o1Weight = o1.getWeight() + (o1.getLightMode() == rm.getPreferredLightMode() ? 10f : 0);
+            float o2Weight = o2.getWeight() + (o2.getLightMode() == rm.getPreferredLightMode() ? 10f : 0);
+            return (int) Math.signum(o2Weight - o1Weight);
+        }
+    }
+
+
 }

+ 20 - 3
jme3-core/src/main/java/com/jme3/material/TechniqueDef.java

@@ -31,9 +31,9 @@
  */
 package com.jme3.material;
 
-import com.jme3.material.logic.TechniqueDefLogic;
 import com.jme3.asset.AssetManager;
 import com.jme3.export.*;
+import com.jme3.material.logic.TechniqueDefLogic;
 import com.jme3.renderer.Caps;
 import com.jme3.shader.*;
 import com.jme3.shader.Shader.ShaderType;
@@ -161,6 +161,9 @@ public class TechniqueDef implements Savable {
     //The space in which the light should be transposed before sending to the shader.
     private LightSpace lightSpace;
 
+    //used to find the best fit technique
+    private float weight = 0;
+
     /**
      * Creates a new technique definition.
      * <p>
@@ -341,6 +344,8 @@ public class TechniqueDef implements Savable {
         requiredCaps.add(vertCap);
         Caps fragCap = Caps.valueOf(fragLanguage);
         requiredCaps.add(fragCap);
+
+        weight = Math.max(vertCap.ordinal(), fragCap.ordinal());
     }
 
     /**
@@ -534,6 +539,7 @@ public class TechniqueDef implements Savable {
     public void setShaderFile(EnumMap<Shader.ShaderType, String> shaderNames, EnumMap<Shader.ShaderType, String> shaderLanguages) {
         requiredCaps.clear();
 
+        int maxCap = 0;
         for (Shader.ShaderType shaderType : shaderNames.keySet()) {
             String language = shaderLanguages.get(shaderType);
             String shaderFile = shaderNames.get(shaderType);
@@ -541,8 +547,9 @@ public class TechniqueDef implements Savable {
             this.shaderLanguages.put(shaderType, language);
             this.shaderNames.put(shaderType, shaderFile);
 
-            Caps vertCap = Caps.valueOf(language);
-            requiredCaps.add(vertCap);
+            Caps cap = Caps.valueOf(language);
+            requiredCaps.add(cap);
+            maxCap = Math.max(maxCap, cap.ordinal());
 
             if (shaderType.equals(Shader.ShaderType.Geometry)) {
                 requiredCaps.add(Caps.GeometryShader);
@@ -550,6 +557,7 @@ public class TechniqueDef implements Savable {
                 requiredCaps.add(Caps.TesselationShader);
             }
         }
+        weight = maxCap;
     }
 
     /**
@@ -600,6 +608,15 @@ public class TechniqueDef implements Savable {
         return shaderNames.get(shaderType);
     }
 
+    /**
+     * returns the weight of the technique def
+     *
+     * @return
+     */
+    public float getWeight() {
+        return weight;
+    }
+
     /**
      * Adds a new world parameter by the given name.
      *

+ 167 - 0
jme3-core/src/test/java/com/jme3/material/TestTechniqueDefOrdering.java

@@ -0,0 +1,167 @@
+package com.jme3.material;
+
+import com.jme3.renderer.RenderManager;
+import com.jme3.shader.Shader;
+import com.jme3.system.NullRenderer;
+import org.junit.Test;
+
+import java.util.*;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Created by Nehon on 14/01/2017.
+ */
+public class TestTechniqueDefOrdering {
+
+    @Test
+    public void order() {
+
+        RenderManager rm = new RenderManager(new NullRenderer());
+        rm.setPreferredLightMode(TechniqueDef.LightMode.MultiPass);
+        MaterialDef.TechDefComparator comp = new MaterialDef.TechDefComparator();
+        comp.rm = rm;
+
+
+        //random case
+        List<TechniqueDef> defs = new ArrayList<>();
+        TechniqueDef def = new TechniqueDef("tech", 1);
+        def.setShaderFile("", "", "GLSL100", "GLSL100");
+        def.setLightMode(TechniqueDef.LightMode.SinglePass);
+        defs.add(def);
+        def = new TechniqueDef("tech2", 1);
+        def.setShaderFile("", "", "GLSL150", "GLSL150");
+        def.setLightMode(TechniqueDef.LightMode.MultiPass);
+        defs.add(def);
+        def = new TechniqueDef("tech3", 1);
+        def.setShaderFile("", "", "GLSL110", "GLSL110");
+        defs.add(def);
+        def = new TechniqueDef("tech4", 1);
+        def.setShaderFile("", "", "GLSL120", "GLSL120");
+        defs.add(def);
+        def = new TechniqueDef("tech5", 1);
+        def.setShaderFile("", "", "GLSL130", "GLSL130");
+        defs.add(def);
+
+        Collections.sort(defs, comp);
+
+        assertEquals(defs.get(0).getName(), "tech2");
+        assertEquals(defs.get(1).getName(), "tech5");
+        assertEquals(defs.get(2).getName(), "tech4");
+        assertEquals(defs.get(3).getName(), "tech3");
+        assertEquals(defs.get(4).getName(), "tech");
+
+
+        //Test the unshaded material case: 2 disabled : 150 and 100
+        defs = new ArrayList<>();
+        def = new TechniqueDef("unshaded", 1);
+        def.setShaderFile("", "", "GLSL100", "GLSL100");
+        defs.add(def);
+        def = new TechniqueDef("unshaded2", 1);
+        def.setShaderFile("", "", "GLSL150", "GLSL150");
+        defs.add(def);
+        Collections.sort(defs, comp);
+
+        assertEquals(defs.get(0).getName(), "unshaded2");
+        assertEquals(defs.get(1).getName(), "unshaded");
+
+        //Test the lighting material case: 2 singlepass : 150 and 100, 2 multipass : 150 and 100
+        defs = new ArrayList<>();
+        def = new TechniqueDef("lighting1", 1);
+        def.setShaderFile("", "", "GLSL100", "GLSL100");
+        def.setLightMode(TechniqueDef.LightMode.MultiPass);
+        defs.add(def);
+        def = new TechniqueDef("lighting2", 1);
+        def.setShaderFile("", "", "GLSL150", "GLSL150");
+        def.setLightMode(TechniqueDef.LightMode.MultiPass);
+        defs.add(def);
+        def = new TechniqueDef("lighting3", 1);
+        def.setShaderFile("", "", "GLSL100", "GLSL100");
+        def.setLightMode(TechniqueDef.LightMode.SinglePass);
+        defs.add(def);
+        def = new TechniqueDef("lighting4", 1);
+        def.setShaderFile("", "", "GLSL150", "GLSL150");
+        def.setLightMode(TechniqueDef.LightMode.SinglePass);
+        defs.add(def);
+        Collections.sort(defs, comp);
+
+        assertEquals(defs.get(0).getName(), "lighting2");
+        assertEquals(defs.get(1).getName(), "lighting1");
+        assertEquals(defs.get(2).getName(), "lighting4");
+        assertEquals(defs.get(3).getName(), "lighting3");
+
+        //switching preferred lighting mode
+        rm.setPreferredLightMode(TechniqueDef.LightMode.SinglePass);
+        Collections.sort(defs, comp);
+
+        assertEquals(defs.get(0).getName(), "lighting4");
+        assertEquals(defs.get(1).getName(), "lighting3");
+        assertEquals(defs.get(2).getName(), "lighting2");
+        assertEquals(defs.get(3).getName(), "lighting1");
+
+
+        //test setting source through the enumMaps method with random cases
+        rm.setPreferredLightMode(TechniqueDef.LightMode.MultiPass);
+        defs = new ArrayList<>();
+        def = new TechniqueDef("lighting1", 1);
+        EnumMap<Shader.ShaderType, String> em = new EnumMap<>(Shader.ShaderType.class);
+        em.put(Shader.ShaderType.Vertex, "");
+        em.put(Shader.ShaderType.Fragment, "");
+        em.put(Shader.ShaderType.Geometry, "");
+        EnumMap<Shader.ShaderType, String> l = new EnumMap<>(Shader.ShaderType.class);
+        l.put(Shader.ShaderType.Vertex, "GLSL100");
+        l.put(Shader.ShaderType.Fragment, "GLSL100");
+        l.put(Shader.ShaderType.Geometry, "GLSL100");
+        def.setShaderFile(em, l);
+        def.setLightMode(TechniqueDef.LightMode.SinglePass);
+        defs.add(def);
+
+        def = new TechniqueDef("lighting2", 1);
+        em = new EnumMap<>(Shader.ShaderType.class);
+        em.put(Shader.ShaderType.Vertex, "");
+        em.put(Shader.ShaderType.Fragment, "");
+        em.put(Shader.ShaderType.Geometry, "");
+        l = new EnumMap<>(Shader.ShaderType.class);
+        l.put(Shader.ShaderType.Vertex, "GLSL100");
+        l.put(Shader.ShaderType.Fragment, "GLSL100");
+        l.put(Shader.ShaderType.Geometry, "GLSL100");
+        def.setShaderFile(em, l);
+        def.setLightMode(TechniqueDef.LightMode.MultiPass);
+        defs.add(def);
+
+        def = new TechniqueDef("lighting3", 1);
+        em = new EnumMap<>(Shader.ShaderType.class);
+        em.put(Shader.ShaderType.Vertex, "");
+        em.put(Shader.ShaderType.Fragment, "");
+        em.put(Shader.ShaderType.Geometry, "");
+        l = new EnumMap<>(Shader.ShaderType.class);
+        l.put(Shader.ShaderType.Vertex, "GLSL150");
+        l.put(Shader.ShaderType.Fragment, "GLSL150");
+        l.put(Shader.ShaderType.Geometry, "GLSL150");
+        def.setShaderFile(em, l);
+        def.setLightMode(TechniqueDef.LightMode.MultiPass);
+        defs.add(def);
+
+        def = new TechniqueDef("lighting4", 1);
+        em = new EnumMap<>(Shader.ShaderType.class);
+        em.put(Shader.ShaderType.Vertex, "");
+        em.put(Shader.ShaderType.Fragment, "");
+        em.put(Shader.ShaderType.Geometry, "");
+        l = new EnumMap<>(Shader.ShaderType.class);
+        l.put(Shader.ShaderType.Vertex, "GLSL130");
+        l.put(Shader.ShaderType.Fragment, "GLSL130");
+        l.put(Shader.ShaderType.Geometry, "GLSL110");
+        def.setShaderFile(em, l);
+        def.setLightMode(TechniqueDef.LightMode.MultiPass);
+        defs.add(def);
+
+        Collections.sort(defs, comp);
+
+        assertEquals(defs.get(0).getName(), "lighting3");
+        assertEquals(defs.get(1).getName(), "lighting4");
+        assertEquals(defs.get(2).getName(), "lighting2");
+        assertEquals(defs.get(3).getName(), "lighting1");
+
+
+    }
+}