Переглянути джерело

RM: add ability to force mat param

Kirill Vainer 9 роки тому
батько
коміт
83259061d3

+ 34 - 23
jme3-core/src/main/java/com/jme3/material/Material.java

@@ -774,32 +774,43 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
         sortingId = -1;
     }
 
-    private void updateShaderMaterialParameters(Renderer renderer, Shader shader, List<MatParamOverride> overrides) {
-        int unit = 0;
+    private int applyOverrides(Renderer renderer, Shader shader, List<MatParamOverride> overrides, int unit) {
+        for (MatParamOverride override : overrides) {
+            VarType type = override.getVarType();
 
-        if (overrides != null) {
-            for (MatParamOverride override : overrides) {
-                VarType type = override.getVarType();
+            MatParam paramDef = def.getMaterialParam(override.getName());
 
-                MatParam paramDef = def.getMaterialParam(override.getName());
-                if (paramDef == null || paramDef.getVarType() != type || !override.isEnabled()) {
-                    continue;
-                }
+            if (paramDef == null || paramDef.getVarType() != type || !override.isEnabled()) {
+                continue;
+            }
 
-                Uniform uniform = shader.getUniform(override.getPrefixedName());
-                if (override.getValue() != null) {
-                    if (type.isTextureType()) {
-                        renderer.setTexture(unit, (Texture) override.getValue());
-                        uniform.setValue(VarType.Int, unit);
-                        unit++;
-                    } else {
-                        uniform.setValue(type, override.getValue());
-                    }
+            Uniform uniform = shader.getUniform(override.getPrefixedName());
+
+            if (override.getValue() != null) {
+                if (type.isTextureType()) {
+                    renderer.setTexture(unit, (Texture) override.getValue());
+                    uniform.setValue(VarType.Int, unit);
+                    unit++;
                 } else {
-                    uniform.clearValue();
+                    uniform.setValue(type, override.getValue());
                 }
+            } else {
+                uniform.clearValue();
             }
         }
+        return unit;
+    }
+
+    private void updateShaderMaterialParameters(Renderer renderer, Shader shader,
+            List<MatParamOverride> worldOverrides, List<MatParamOverride> forcedOverrides) {
+
+        int unit = 0;
+        if (worldOverrides != null) {
+            unit = applyOverrides(renderer, shader, worldOverrides, unit);
+        }
+        if (forcedOverrides != null) {
+            unit = applyOverrides(renderer, shader, forcedOverrides, unit);
+        }
 
         for (int i = 0; i < paramValues.size(); i++) {
             MatParam param = paramValues.getValue(i);
@@ -854,8 +865,8 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
             return;
         }
 
-        Shader shader = technique.makeCurrent(renderManager, null, null, rendererCaps);
-        updateShaderMaterialParameters(renderer, shader, null);
+        Shader shader = technique.makeCurrent(renderManager, null, null, null, rendererCaps);
+        updateShaderMaterialParameters(renderer, shader, null, null);
         renderManager.getRenderer().setShader(shader);
     }
 
@@ -962,7 +973,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
         List<MatParamOverride> overrides = geometry.getWorldMatParamOverrides();
 
         // Select shader to use
-        Shader shader = technique.makeCurrent(renderManager, overrides, lights, rendererCaps);
+        Shader shader = technique.makeCurrent(renderManager, overrides, renderManager.getForcedMatParams(), lights, rendererCaps);
         
         // Begin tracking which uniforms were changed by material.
         clearUniformsSetByCurrent(shader);
@@ -971,7 +982,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
         renderManager.updateUniformBindings(shader);
         
         // Set material parameters
-        updateShaderMaterialParameters(renderer, shader, geometry.getWorldMatParamOverrides());
+        updateShaderMaterialParameters(renderer, shader, overrides, renderManager.getForcedMatParams());
         
         // Clear any uniforms not changed by material.
         resetUniformsNotSetByCurrent(shader);

+ 21 - 13
jme3-core/src/main/java/com/jme3/material/Technique.java

@@ -110,6 +110,20 @@ public final class Technique {
         }
     }
 
+    private void applyOverrides(DefineList defineList, List<MatParamOverride> overrides) {
+        for (MatParamOverride override : overrides) {
+            if (!override.isEnabled()) {
+                continue;
+            }
+            Integer defineId = def.getShaderParamDefineId(override.name);
+            if (defineId != null) {
+                if (def.getDefineIdType(defineId) == override.type) {
+                    defineList.set(defineId, override.type, override.value);
+                }
+            }
+        }
+    }
+
     /**
      * Called by the material to determine which shader to use for rendering.
      * 
@@ -120,7 +134,8 @@ public final class Technique {
      * @param rendererCaps The renderer capabilities which the shader should support.
      * @return A compatible shader.
      */
-    Shader makeCurrent(RenderManager renderManager, List<MatParamOverride> overrides,
+    Shader makeCurrent(RenderManager renderManager, List<MatParamOverride> worldOverrides,
+            List<MatParamOverride> forcedOverrides,
             LightList lights, EnumSet<Caps> rendererCaps) {
         TechniqueDefLogic logic = def.getLogic();
         AssetManager assetManager = owner.getMaterialDef().getAssetManager();
@@ -128,18 +143,11 @@ public final class Technique {
         dynamicDefines.clear();
         dynamicDefines.setAll(paramDefines);
 
-        if (overrides != null) {
-            for (MatParamOverride override : overrides) {
-                if (!override.isEnabled()) {
-                    continue;
-                }
-                Integer defineId = def.getShaderParamDefineId(override.name);
-                if (defineId != null) {
-                    if (def.getDefineIdType(defineId) == override.type) {
-                        dynamicDefines.set(defineId, override.type, override.value);
-                    }
-                }
-            }
+        if (worldOverrides != null) {
+            applyOverrides(dynamicDefines, worldOverrides);
+        }
+        if (forcedOverrides != null) {
+            applyOverrides(dynamicDefines, forcedOverrides);
         }
 
         return logic.makeCurrent(assetManager, renderManager, rendererCaps, lights, dynamicDefines);

+ 41 - 0
jme3-core/src/main/java/com/jme3/renderer/RenderManager.java

@@ -34,6 +34,7 @@ package com.jme3.renderer;
 import com.jme3.light.DefaultLightFilter;
 import com.jme3.light.LightFilter;
 import com.jme3.light.LightList;
+import com.jme3.material.MatParamOverride;
 import com.jme3.material.Material;
 import com.jme3.material.MaterialDef;
 import com.jme3.material.RenderState;
@@ -82,6 +83,7 @@ public class RenderManager {
     private Material forcedMaterial = null;
     private String forcedTechnique = null;
     private RenderState forcedRenderState = null;
+    private final List<MatParamOverride> forcedOverrides = new ArrayList<>();
     private int viewX, viewY, viewWidth, viewHeight;
     private Matrix4f orthoMatrix = new Matrix4f();
     private LightList filteredLightList = new LightList(null);
@@ -92,6 +94,7 @@ public class RenderManager {
     private TechniqueDef.LightMode preferredLightMode = TechniqueDef.LightMode.MultiPass;
     private int singlePassLightBatchSize = 1;
 
+
     /**
      * Create a high-level rendering interface over the
      * low-level rendering interface.
@@ -426,6 +429,44 @@ public class RenderManager {
         this.forcedTechnique = forcedTechnique;
     }
 
+    /**
+     * Adds a forced material parameter to use when rendering geometries.
+     * <p>
+     * The provided parameter takes precedence over parameters set on the
+     * material or any overrides that exist in the scene graph that have the
+     * same name.
+     *
+     * @param override The override to add
+     * @see MatParamOverride
+     * @see #removeForcedMatParam(com.jme3.material.MatParamOverride)
+     */
+    public void addForcedMatParam(MatParamOverride override) {
+        forcedOverrides.add(override);
+    }
+
+    /**
+     * Remove a forced material parameter previously added.
+     *
+     * @param override The override to remove.
+     * @see #addForcedMatParam(com.jme3.material.MatParamOverride)
+     */
+    public void removeForcedMatParam(MatParamOverride override) {
+        forcedOverrides.remove(override);
+    }
+
+    /**
+     * Get the forced material parameters applied to rendered geometries.
+     * <p>
+     * Forced parameters can be added via
+     * {@link #addForcedMatParam(com.jme3.material.MatParamOverride)} or removed
+     * via {@link #removeForcedMatParam(com.jme3.material.MatParamOverride)}.
+     *
+     * @return The forced material parameters.
+     */
+    public List<MatParamOverride> getForcedMatParams() {
+        return forcedOverrides;
+    }
+
     /**
      * Enable or disable alpha-to-coverage. 
      * <p>

+ 29 - 0
jme3-core/src/test/java/com/jme3/material/MaterialMatParamOverrideTest.java

@@ -53,6 +53,7 @@ import com.jme3.system.TestUtil;
 import com.jme3.texture.Image.Format;
 import com.jme3.texture.Texture;
 import com.jme3.texture.Texture2D;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
 import org.junit.Before;
@@ -126,6 +127,22 @@ public class MaterialMatParamOverrideTest {
         outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 2.79f));
     }
 
+    @Test
+    public void testForcedOverride() {
+        material("Common/MatDefs/Light/Lighting.j3md");
+        inputMp(mpoFloat("AlphaDiscardThreshold", 3.12f));
+        inputMpo(mpoFloat("AlphaDiscardThreshold", 2.79f));
+        inputFpo(mpoFloat("AlphaDiscardThreshold", 1.23f));
+        outDefines(def("DISCARD_ALPHA", VarType.Float, 1.23f));
+        outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 1.23f));
+
+        reset();
+        root.clearMatParamOverrides();
+        root.updateGeometricState();
+        outDefines(def("DISCARD_ALPHA", VarType.Float, 2.79f));
+        outUniforms(uniform("AlphaDiscardThreshold", VarType.Float, 2.79f));
+    }
+
     @Test
     public void testChildOverridesParent() {
         material("Common/MatDefs/Light/Lighting.j3md");
@@ -439,10 +456,22 @@ public class MaterialMatParamOverrideTest {
         root.updateGeometricState();
     }
 
+    private void inputFpo(MatParamOverride... overrides) {
+        if (evaluated) {
+            throw new IllegalStateException();
+        }
+        for (MatParamOverride override : overrides) {
+            renderManager.addForcedMatParam(override);
+        }
+    }
+
     private void reset() {
         evaluated = false;
         usedShader = null;
         Arrays.fill(usedTextures, null);
+        for (MatParamOverride override : new ArrayList<>(renderManager.getForcedMatParams())) {
+            renderManager.removeForcedMatParam(override);
+        }
     }
 
     private Define def(String name, VarType type, Object value) {