From 3b6f7b8aca58006745f038ce58f7419d9e11540f Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Mon, 9 Oct 2023 11:14:45 +0800
Subject: [PATCH 001/111] jme3-core: 1. Added basic framework of framegraph to
manage and organize new rendering passes; 2. Split existing rendering into
several core RenderPasses; 3. Added multiple rendering paths (forward,
deferred, tile based deferred); 4. Activated Framegraph system by
useFramegraph, activated rendering paths by setRenderPath;
---
.../java/com/jme3/material/TechniqueDef.java | 89 +-
.../DeferredSinglePassLightingLogic.java | 449 ++++++++++
.../SkyLightAndReflectionProbeRender.java | 72 ++
...eBasedDeferredSinglePassLightingLogic.java | 807 ++++++++++++++++++
.../src/main/java/com/jme3/math/FastMath.java | 12 +
.../java/com/jme3/renderer/RenderManager.java | 392 ++++++---
.../main/java/com/jme3/renderer/ViewPort.java | 14 +
.../jme3/renderer/framegraph/FGBindable.java | 20 +
.../renderer/framegraph/FGBindingPass.java | 42 +
.../renderer/framegraph/FGCallbackPass.java | 34 +
.../renderer/framegraph/FGComputePass.java | 17 +
.../framegraph/FGContainerBindableSink.java | 75 ++
.../FGFramebufferCopyBindableSink.java | 69 ++
.../framegraph/FGFramebufferSource.java | 35 +
.../jme3/renderer/framegraph/FGGlobal.java | 32 +
.../com/jme3/renderer/framegraph/FGPass.java | 113 +++
.../renderer/framegraph/FGRenderContext.java | 37 +
.../framegraph/FGRenderQueuePass.java | 64 ++
.../framegraph/FGRenderTargetSource.java | 45 +
.../com/jme3/renderer/framegraph/FGSink.java | 49 ++
.../jme3/renderer/framegraph/FGSource.java | 22 +
.../framegraph/FGTextureBindableSink.java | 58 ++
.../framegraph/FGVarBindableSink.java | 18 +
.../jme3/renderer/framegraph/FGVarSource.java | 34 +
.../jme3/renderer/framegraph/FrameGraph.java | 175 ++++
.../com/jme3/renderer/queue/RenderQueue.java | 90 +-
.../renderPass/DeferredLightDataSink.java | 17 +
.../renderPass/DeferredLightDataSource.java | 36 +
.../renderPass/DeferredShadingPass.java | 98 +++
.../jme3/renderer/renderPass/ForwardPass.java | 44 +
.../jme3/renderer/renderPass/GBufferPass.java | 184 ++++
.../com/jme3/renderer/renderPass/GuiPass.java | 33 +
.../renderer/renderPass/IRenderGeometry.java | 17 +
.../jme3/renderer/renderPass/OpaquePass.java | 25 +
.../renderPass/PostProcessorPass.java | 31 +
.../renderPass/ResolveSceneColorPass.java | 63 ++
.../jme3/renderer/renderPass/ScreenPass.java | 35 +
.../com/jme3/renderer/renderPass/SkyPass.java | 21 +
.../renderPass/TileDeferredShadingPass.java | 44 +
.../renderer/renderPass/TranslucentPass.java | 18 +
.../renderer/renderPass/TransparentPass.java | 21 +
.../src/main/java/com/jme3/scene/Spatial.java | 17 +-
.../Common/MatDefs/Light/Lighting.j3md | 50 ++
.../MatDefs/Light/LightingGBufferPack.frag | 212 +++++
.../MatDefs/Light/LightingGBufferPack.vert | 149 ++++
.../Common/MatDefs/Light/PBRLighting.j3md | 50 ++
.../MatDefs/Light/PBRLightingGBufferPack.frag | 258 ++++++
.../MatDefs/Light/PBRLightingGBufferPack.vert | 74 ++
.../ShadingCommon/DeferredShading.frag | 231 +++++
.../ShadingCommon/DeferredShading.j3md | 42 +
.../ShadingCommon/DeferredShading.vert | 23 +
.../TileBasedDeferredShading.frag | 356 ++++++++
.../TileBasedDeferredShading.j3md | 46 +
.../Common/ShaderLib/Deferred.glsllib | 65 ++
.../Common/ShaderLib/GLSLCompat.glsllib | 36 +-
.../Common/ShaderLib/Instancing.glsllib | 7 +
.../Common/ShaderLib/Octahedral.glsllib | 43 +
.../Common/ShaderLib/ShadingModel.glsllib | 18 +
.../ShaderLib/SkyLightReflectionProbe.glsllib | 70 ++
.../com/jme3/material/plugins/J3MLoader.java | 53 +-
60 files changed, 5166 insertions(+), 185 deletions(-)
create mode 100644 jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java
create mode 100644 jme3-core/src/main/java/com/jme3/material/logic/SkyLightAndReflectionProbeRender.java
create mode 100644 jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGCallbackPass.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGComputePass.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferSource.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGGlobal.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderTargetSource.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSink.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSource.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarBindableSink.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSink.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSource.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredShadingPass.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/renderPass/ForwardPass.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/renderPass/GuiPass.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/renderPass/IRenderGeometry.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/renderPass/OpaquePass.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/renderPass/PostProcessorPass.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/renderPass/ResolveSceneColorPass.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/renderPass/ScreenPass.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/renderPass/SkyPass.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/renderPass/TileDeferredShadingPass.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/renderPass/TranslucentPass.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/renderPass/TransparentPass.java
create mode 100644 jme3-core/src/main/resources/Common/MatDefs/Light/LightingGBufferPack.frag
create mode 100644 jme3-core/src/main/resources/Common/MatDefs/Light/LightingGBufferPack.vert
create mode 100644 jme3-core/src/main/resources/Common/MatDefs/Light/PBRLightingGBufferPack.frag
create mode 100644 jme3-core/src/main/resources/Common/MatDefs/Light/PBRLightingGBufferPack.vert
create mode 100644 jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag
create mode 100644 jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md
create mode 100644 jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.vert
create mode 100644 jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
create mode 100644 jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md
create mode 100644 jme3-core/src/main/resources/Common/ShaderLib/Deferred.glsllib
create mode 100644 jme3-core/src/main/resources/Common/ShaderLib/Octahedral.glsllib
create mode 100644 jme3-core/src/main/resources/Common/ShaderLib/ShadingModel.glsllib
create mode 100644 jme3-core/src/main/resources/Common/ShaderLib/SkyLightReflectionProbe.glsllib
diff --git a/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java b/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java
index daa08d3266..a6c33dc66b 100644
--- a/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java
+++ b/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java
@@ -62,6 +62,47 @@ public class TechniqueDef implements Savable, Cloneable {
*/
public static final String DEFAULT_TECHNIQUE_NAME = "Default";
+ /**
+ * RenderPipeline.
+ */
+ public enum Pipeline{
+ /**
+ * Default, most basic rendering
+ */
+ Forward("Forward"),
+
+ /**
+ * Forward based on Cluster
+ */
+ ForwardPlus("ForwardPlus"),
+
+ /**
+ * Standard Deferred Rendering
+ */
+ Deferred("Deferred"),
+
+ /**
+ * Tiled Based Deferred Rendering
+ */
+ TiledBasedDeferred("TiledBasedDeferred"),
+
+ /**
+ * Clustered Based Deferred Rendering
+ */
+ ClusteredBasedDeferred("ClusteredBasedDeferred"),
+ ;
+
+ private String text;
+ Pipeline(String t){
+ text = t;
+ }
+
+ @Override
+ public String toString() {
+ return text;
+ }
+ }
+
/**
* Describes light rendering mode.
*/
@@ -100,6 +141,22 @@ public enum LightMode {
*/
SinglePassAndImageBased,
+ /**
+ * Enable light rendering by using deferred single pass.
+ *
+ * An array of light positions and light colors is passed to the shader
+ * containing the world light list for the geometry being rendered.
+ */
+ DeferredSinglePass,
+
+ /**
+ * Enable light rendering by using tile-based deferred single pass.
+ *
+ * An array of light positions and light colors is passed to the shader
+ * containing the world light list for the geometry being rendered.
+ */
+ TileBasedDeferredSinglePass,
+
/**
* @deprecated OpenGL1 is not supported anymore
*/
@@ -156,6 +213,7 @@ public enum LightSpace {
private LightMode lightMode = LightMode.Disable;
private ShadowMode shadowMode = ShadowMode.Disable;
+ private Pipeline pipeline = Pipeline.Forward;
private TechniqueDefLogic logic;
private ArrayList worldBinds;
@@ -239,6 +297,19 @@ public void setLightMode(LightMode lightMode) {
}
}
+ public Pipeline getPipeline() {
+ return pipeline;
+ }
+
+ /**
+ * Set the pipeline
+ * @param pipeline the render pipeline
+ * @see Pipeline
+ */
+ public void setPipeline(Pipeline pipeline){
+ this.pipeline = pipeline;
+ }
+
public void setLogic(TechniqueDefLogic logic) {
this.logic = logic;
}
@@ -524,13 +595,13 @@ private Shader loadShader(AssetManager assetManager, EnumSet rendererCaps,
}
public Shader getShader(AssetManager assetManager, EnumSet rendererCaps, DefineList defines) {
- Shader shader = definesToShaderMap.get(defines);
- if (shader == null) {
- shader = loadShader(assetManager, rendererCaps, defines);
- definesToShaderMap.put(defines.deepClone(), shader);
- }
- return shader;
- }
+ Shader shader = definesToShaderMap.get(defines);
+ if (shader == null) {
+ shader = loadShader(assetManager, rendererCaps, defines);
+ definesToShaderMap.put(defines.deepClone(), shader);
+ }
+ return shader;
+ }
/**
* Sets the shaders that this technique definition will use.
@@ -539,7 +610,7 @@ public Shader getShader(AssetManager assetManager, EnumSet rendererCaps, D
* @param shaderLanguages EnumMap containing all shader languages for this stage
*/
public void setShaderFile(EnumMap shaderNames,
- EnumMap shaderLanguages) {
+ EnumMap shaderLanguages) {
requiredCaps.clear();
weight = 0;
@@ -825,7 +896,7 @@ public TechniqueDef clone() throws CloneNotSupportedException {
try {
clone.logic = logic.getClass().getConstructor(TechniqueDef.class).newInstance(clone);
} catch (InstantiationException | IllegalAccessException
- | NoSuchMethodException | InvocationTargetException e) {
+ | NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
}
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java
new file mode 100644
index 0000000000..fbd592834e
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2009-2021 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 com.jme3.material.logic;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.light.*;
+import com.jme3.material.RenderState;
+import com.jme3.material.RenderState.BlendMode;
+import com.jme3.material.TechniqueDef;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.math.Vector4f;
+import com.jme3.renderer.Caps;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.scene.Geometry;
+import com.jme3.shader.DefineList;
+import com.jme3.shader.Shader;
+import com.jme3.shader.Uniform;
+import com.jme3.shader.VarType;
+import com.jme3.texture.Image;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture2D;
+import com.jme3.texture.image.ColorSpace;
+import com.jme3.texture.image.ImageRaster;
+import com.jme3.util.BufferUtils;
+import com.jme3.util.TempVars;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+
+public final class DeferredSinglePassLightingLogic extends DefaultTechniqueDefLogic {
+ private final static String _S_LIGHT_CULL_DRAW_STAGE = "Light_Cull_Draw_Stage";
+ private static final String DEFINE_DEFERRED_SINGLE_PASS_LIGHTING = "DEFERRED_SINGLE_PASS_LIGHTING";
+ private static final String DEFINE_NB_LIGHTS = "NB_LIGHTS";
+ private static final String DEFINE_USE_TEXTURE_PACK_MODE = "USE_TEXTURE_PACK_MODE";
+ private static final String DEFINE_PACK_NB_LIGHTS = "PACK_NB_LIGHTS";
+ private static final String DEFINE_NB_SKY_LIGHT_AND_REFLECTION_PROBES = "NB_SKY_LIGHT_AND_REFLECTION_PROBES";
+ private static final RenderState ADDITIVE_LIGHT = new RenderState();
+ private boolean bUseTexturePackMode = true;
+ // 避免过多的光源
+ private static final int MAX_LIGHT_NUM = 9046;
+ // 使用texture来一次性存储大量光源数据,避免多次绘制
+ private Texture2D lightData1;
+ private Texture2D lightData2;
+ private Texture2D lightData3;
+ private ImageRaster lightDataUpdateIO1;
+ private ImageRaster lightDataUpdateIO2;
+ private ImageRaster lightDataUpdateIO3;
+ private int lightNum;
+
+ private final ColorRGBA ambientLightColor = new ColorRGBA(0, 0, 0, 1);
+ final private List skyLightAndReflectionProbes = new ArrayList<>(3);
+
+ static {
+ ADDITIVE_LIGHT.setBlendMode(BlendMode.AlphaAdditive);
+ ADDITIVE_LIGHT.setDepthWrite(false);
+ }
+
+ private final int singlePassLightingDefineId;
+ private int nbLightsDefineId;
+ private int packNbLightsDefineId;
+ private int packTextureModeDefineId;
+ private final int nbSkyLightAndReflectionProbesDefineId;
+
+ public DeferredSinglePassLightingLogic(TechniqueDef techniqueDef) {
+ super(techniqueDef);
+ singlePassLightingDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_DEFERRED_SINGLE_PASS_LIGHTING, VarType.Boolean);
+ if(bUseTexturePackMode){
+ packNbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_PACK_NB_LIGHTS, VarType.Int);
+ packTextureModeDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_USE_TEXTURE_PACK_MODE, VarType.Boolean);
+ prepaLightData(1024);
+ }
+ else{
+ nbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_LIGHTS, VarType.Int);
+ }
+ nbSkyLightAndReflectionProbesDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_SKY_LIGHT_AND_REFLECTION_PROBES, VarType.Int);
+ }
+
+ private void prepaLightData(int lightNum){
+ this.lightNum = lightNum;
+ // 1d texture
+ lightData1 = new Texture2D(lightNum, 1, Image.Format.RGBA32F);
+ lightData1.setMinFilter(Texture.MinFilter.NearestNoMipMaps);
+ lightData1.setMagFilter(Texture.MagFilter.Nearest);
+ lightData1.setWrap(Texture.WrapMode.EdgeClamp);
+ ByteBuffer data = BufferUtils.createByteBuffer( (int)Math.ceil(Image.Format.RGBA32F.getBitsPerPixel() / 8.0) * lightNum);
+ Image convertedImage = new Image(Image.Format.RGBA32F, lightNum, 1, data, null, ColorSpace.Linear);
+ lightData1.setImage(convertedImage);
+ lightData1.getImage().setMipmapsGenerated(false);
+ lightDataUpdateIO1 = ImageRaster.create(lightData1.getImage());
+
+ lightData2 = new Texture2D(lightNum, 1, Image.Format.RGBA32F);
+ lightData2.setMinFilter(Texture.MinFilter.NearestNoMipMaps);
+ lightData2.setMagFilter(Texture.MagFilter.Nearest);
+ lightData2.setWrap(Texture.WrapMode.EdgeClamp);
+ ByteBuffer data2 = BufferUtils.createByteBuffer( (int)Math.ceil(Image.Format.RGBA32F.getBitsPerPixel() / 8.0) * lightNum);
+ Image convertedImage2 = new Image(Image.Format.RGBA32F, lightNum, 1, data2, null, ColorSpace.Linear);
+ lightData2.setImage(convertedImage2);
+ lightData2.getImage().setMipmapsGenerated(false);
+ lightDataUpdateIO2 = ImageRaster.create(lightData2.getImage());
+
+ lightData3 = new Texture2D(lightNum, 1, Image.Format.RGBA32F);
+ lightData3.setMinFilter(Texture.MinFilter.NearestNoMipMaps);
+ lightData3.setMagFilter(Texture.MagFilter.Nearest);
+ lightData3.setWrap(Texture.WrapMode.EdgeClamp);
+ ByteBuffer data3 = BufferUtils.createByteBuffer( (int)Math.ceil(Image.Format.RGBA32F.getBitsPerPixel() / 8.0) * lightNum);
+ Image convertedImage3 = new Image(Image.Format.RGBA32F, lightNum, 1, data3, null, ColorSpace.Linear);
+ lightData3.setImage(convertedImage3);
+ lightData3.getImage().setMipmapsGenerated(false);
+ lightDataUpdateIO3 = ImageRaster.create(lightData3.getImage());
+ }
+
+ @Override
+ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager,
+ EnumSet rendererCaps, LightList lights, DefineList defines) {
+ if(bUseTexturePackMode){
+ defines.set(packNbLightsDefineId, this.lightNum);
+ defines.set(packTextureModeDefineId, true);
+ }
+ else{
+ defines.set(nbLightsDefineId, renderManager.getSinglePassLightBatchSize() * 3);
+ }
+ defines.set(singlePassLightingDefineId, true);
+ //TODO here we have a problem, this is called once before render, so the define will be set for all passes (in case we have more than NB_LIGHTS lights)
+ //Though the second pass should not render IBL as it is taken care of on first pass like ambient light in phong lighting.
+ //We cannot change the define between passes and the old technique, and for some reason the code fails on mac (renders nothing).
+ if(lights != null) {
+ SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, false);
+ defines.set(nbSkyLightAndReflectionProbesDefineId, skyLightAndReflectionProbes.size());
+ }
+ return super.makeCurrent(assetManager, renderManager, rendererCaps, lights, defines);
+ }
+
+ protected int updateLightListPackToTexture(Shader shader, Geometry g, LightList lightList, int numLights, RenderManager rm, int startIndex, boolean isLightCullStageDraw, int lastTexUnit) {
+ if (numLights == 0) { // this shader does not do lighting, ignore.
+ return 0;
+ }
+
+ Uniform ambientColor = shader.getUniform("g_AmbientLightColor");
+
+// skyLightAndReflectionProbes.clear();
+ if (startIndex != 0 || isLightCullStageDraw) {
+ // apply additive blending for 2nd and future passes
+ rm.getRenderer().applyRenderState(ADDITIVE_LIGHT);
+ ambientColor.setValue(VarType.Vector4, ColorRGBA.Black);
+ } else {
+// extractSkyLightAndReflectionProbes(lightList,true);
+ ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, true, ambientLightColor));
+ }
+
+ // render skyLights and reflectionProbes
+ if(!skyLightAndReflectionProbes.isEmpty()){
+ // Matrix4f
+ Uniform skyLightData = shader.getUniform("g_SkyLightData");
+ Uniform skyLightData2 = shader.getUniform("g_SkyLightData2");
+ Uniform skyLightData3 = shader.getUniform("g_SkyLightData3");
+
+ Uniform shCoeffs = shader.getUniform("g_ShCoeffs");
+ Uniform reflectionProbePemMap = shader.getUniform("g_ReflectionEnvMap");
+ Uniform shCoeffs2 = shader.getUniform("g_ShCoeffs2");
+ Uniform reflectionProbePemMap2 = shader.getUniform("g_ReflectionEnvMap2");
+ Uniform shCoeffs3 = shader.getUniform("g_ShCoeffs3");
+ Uniform reflectionProbePemMap3 = shader.getUniform("g_ReflectionEnvMap3");
+
+ LightProbe skyLight = skyLightAndReflectionProbes.get(0);
+ lastTexUnit = SkyLightAndReflectionProbeRender.setSkyLightAndReflectionProbeData(rm, lastTexUnit, skyLightData, shCoeffs, reflectionProbePemMap, skyLight);
+ if (skyLightAndReflectionProbes.size() > 1) {
+ skyLight = skyLightAndReflectionProbes.get(1);
+ lastTexUnit = SkyLightAndReflectionProbeRender.setSkyLightAndReflectionProbeData(rm, lastTexUnit, skyLightData2, shCoeffs2, reflectionProbePemMap2, skyLight);
+ }
+ if (skyLightAndReflectionProbes.size() > 2) {
+ skyLight = skyLightAndReflectionProbes.get(2);
+ SkyLightAndReflectionProbeRender.setSkyLightAndReflectionProbeData(rm, lastTexUnit, skyLightData3, shCoeffs3, reflectionProbePemMap3, skyLight);
+ }
+ } else {
+ Uniform skyLightData = shader.getUniform("g_SkyLightData");
+ //Disable IBL for this pass
+ skyLightData.setValue(VarType.Matrix4, LightProbe.FALLBACK_MATRIX);
+ }
+
+ TempVars vars = TempVars.get();
+ int curIndex;
+ int endIndex = numLights + startIndex;
+ ColorRGBA temp = vars.color;
+ for (curIndex = startIndex; curIndex < endIndex && curIndex < lightList.size(); curIndex++) {
+
+ Light l = lightList.get(curIndex);
+ if (l.getType() == Light.Type.Ambient || l.getType() == Light.Type.Probe) {
+ endIndex++;
+ continue;
+ }
+ ColorRGBA color = l.getColor();
+ //Color
+ temp.r = color.getRed();
+ temp.g = color.getGreen();
+ temp.b = color.getBlue();
+ temp.a = l.getType().getId();
+ lightDataUpdateIO1.setPixel(curIndex, 0, temp);
+
+ switch (l.getType()) {
+ case Directional:
+ DirectionalLight dl = (DirectionalLight) l;
+ Vector3f dir = dl.getDirection();
+ temp.r = dir.getX();
+ temp.g = dir.getY();
+ temp.b = dir.getZ();
+ temp.a = -1;
+ lightDataUpdateIO2.setPixel(curIndex, 0, temp);
+ break;
+ case Point:
+ PointLight pl = (PointLight) l;
+ Vector3f pos = pl.getPosition();
+ float invRadius = pl.getInvRadius();
+ temp.r = pos.getX();
+ temp.g = pos.getY();
+ temp.b = pos.getZ();
+ temp.a = invRadius;
+ lightDataUpdateIO2.setPixel(curIndex, 0, temp);
+ break;
+ case Spot:
+ SpotLight sl = (SpotLight) l;
+ Vector3f pos2 = sl.getPosition();
+ Vector3f dir2 = sl.getDirection();
+ float invRange = sl.getInvSpotRange();
+ float spotAngleCos = sl.getPackedAngleCos();
+ temp.r = pos2.getX();
+ temp.g = pos2.getY();
+ temp.b = pos2.getZ();
+ temp.a = invRange;
+ lightDataUpdateIO2.setPixel(curIndex, 0, temp);
+
+ //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.
+ temp.r = dir2.getX();
+ temp.g = dir2.getY();
+ temp.b = dir2.getZ();
+ temp.a = spotAngleCos;
+ lightDataUpdateIO3.setPixel(curIndex, 0, temp);
+ break;
+ default:
+ throw new UnsupportedOperationException("Unknown type of light: " + l.getType());
+ }
+ }
+ vars.release();
+ lightData1.getImage().setUpdateNeeded();
+ lightData2.getImage().setUpdateNeeded();
+ lightData3.getImage().setUpdateNeeded();
+// Uniform g_LightPackData1 = shader.getUniform("g_LightPackData1");
+// g_LightPackData1.setValue(VarType.Texture2D, lightData1);
+// Uniform g_LightPackData2 = shader.getUniform("g_LightPackData2");
+// g_LightPackData2.setValue(VarType.Texture2D, lightData2);
+// Uniform g_LightPackData3 = shader.getUniform("g_LightPackData3");
+// g_LightPackData3.setValue(VarType.Texture2D, lightData3);
+ g.getMaterial().setTexture("LightPackData1", lightData1);
+ g.getMaterial().setTexture("LightPackData2", lightData2);
+ g.getMaterial().setTexture("LightPackData3", lightData3);
+ return curIndex;
+ }
+
+ /**
+ * Uploads the lights in the light list as two uniform arrays.
+ *
+ * uniform vec4 g_LightColor[numLights];
//
+ * g_LightColor.rgb is the diffuse/specular color of the light.
//
+ * g_Lightcolor.a is the type of light, 0 = Directional, 1 = Point,
//
+ * 2 = Spot.
+ * uniform vec4 g_LightPosition[numLights];
//
+ * g_LightPosition.xyz is the position of the light (for point lights)
+ * // or the direction of the light (for directional lights).
//
+ * g_LightPosition.w is the inverse radius (1/r) of the light (for
+ * attenuation)
+ *
+ * @param shader the Shader being used
+ * @param g the Geometry being rendered
+ * @param lightList the list of lights
+ * @param numLights the number of lights to upload
+ * @param rm to manage rendering
+ * @param startIndex the starting index in the LightList
+ * @param isLightCullStageDraw isLightCullStageDraw
+ * @return the next starting index in the LightList
+ */
+ protected int updateLightListUniforms(Shader shader, Geometry g, LightList lightList, int numLights, RenderManager rm, int startIndex, boolean isLightCullStageDraw) {
+ if (numLights == 0) { // this shader does not do lighting, ignore.
+ return 0;
+ }
+
+ Uniform lightData = shader.getUniform("g_LightData");
+ lightData.setVector4Length(numLights * 3);//8 lights * max 3
+ Uniform ambientColor = shader.getUniform("g_AmbientLightColor");
+
+ if (startIndex != 0 || isLightCullStageDraw) {
+ // apply additive blending for 2nd and future passes
+ rm.getRenderer().applyRenderState(ADDITIVE_LIGHT);
+ ambientColor.setValue(VarType.Vector4, ColorRGBA.Black);
+ } else {
+ ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, true, ambientLightColor));
+ }
+
+ 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 || l.getType() == Light.Type.Probe) {
+ endIndex++;
+ continue;
+ }
+ ColorRGBA color = l.getColor();
+ //Color
+ lightData.setVector4InArray(color.getRed(),
+ color.getGreen(),
+ color.getBlue(),
+ l.getType().getId(),
+ lightDataIndex);
+ lightDataIndex++;
+
+ switch (l.getType()) {
+ case Directional:
+ DirectionalLight dl = (DirectionalLight) l;
+ Vector3f dir = dl.getDirection();
+ lightData.setVector4InArray(dir.getX(), dir.getY(), dir.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();
+ lightData.setVector4InArray(pos.getX(), pos.getY(), pos.getZ(), invRadius, lightDataIndex);
+ lightDataIndex++;
+ //PADDING
+ lightData.setVector4InArray(0, 0, 0, 0, lightDataIndex);
+ lightDataIndex++;
+ break;
+ case Spot:
+ SpotLight sl = (SpotLight) l;
+ Vector3f pos2 = sl.getPosition();
+ Vector3f dir2 = sl.getDirection();
+ float invRange = sl.getInvSpotRange();
+ float spotAngleCos = sl.getPackedAngleCos();
+ lightData.setVector4InArray(pos2.getX(), pos2.getY(), pos2.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.
+ lightData.setVector4InArray(dir2.getX(), dir2.getY(), dir2.getZ(), spotAngleCos, lightDataIndex);
+ lightDataIndex++;
+ break;
+ default:
+ throw new UnsupportedOperationException("Unknown type of light: " + l.getType());
+ }
+ }
+ vars.release();
+ // pad unused buffer space
+ while(lightDataIndex < numLights * 3) {
+ lightData.setVector4InArray(0f, 0f, 0f, 0f, lightDataIndex);
+ lightDataIndex++;
+ }
+ return curIndex;
+ }
+
+ @Override
+ public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) {
+ int nbRenderedLights = 0;
+ Renderer renderer = renderManager.getRenderer();
+ boolean isLightCullStageDraw = false;
+ if(geometry.getUserData(_S_LIGHT_CULL_DRAW_STAGE) != null){
+ isLightCullStageDraw = geometry.getUserData(_S_LIGHT_CULL_DRAW_STAGE);
+ }
+ // todo:这里的一种优化方式是:
+ // todo:使用uniform数组存储的方案:
+ // todo:首先将lights分成DirectionalLights,PointLights,SpotLights三种列表
+ // todo:然后首先绘制DirectionalLights和SpotLights,这两个都是用Rect绘制,一次提交SingleBatch指定的数量灯光
+ // todo:然后使用Sphere(开启FrontFace剔除,避免相机进入球内光源着色消失)绘制点光源,根据SingleBatch一次绘制一组Sphere实例化
+
+ // todo:另一种做法是,将lights分为全屏和非全屏,DirectionalLight和SpotLight按全屏处理,然后便利所有PointLight中属于无效半径的也归为全屏
+ // todo:然后把剩下的PointLights作为非全屏光源,然后纹理中一次性存储所有光源信息,内存存放按全屏在前非全屏在后
+ // todo:然后发起一个RectPass,在一个DC内绘制完所有全屏光,更新light_offset,然后使用SingleBatch预创建的SphereInstance绘制剩下的非全屏光
+ // todo:这里将采用第二种方法
+
+ // todo:关于light probes(暂时实现基于preCompute light probe),根据当前视锥体可见范围获取到light probe grid,按light probe grid执行multi pass
+ // todo:关于reflection probes,使用textureArray(八面体投影,带mipmap),收集相机可见范围内的reflection probes,并限制当前视锥体内只能有多少个reflection probes
+ if(bUseTexturePackMode){
+ Uniform lightCount = shader.getUniform("g_LightCount");
+ SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, true);
+ int count = lights.size();
+ lightCount.setValue(VarType.Int, count);
+ while (nbRenderedLights < count) {
+ // todo:采用第二种方法优化deferred,则这里使用当前类的geometrys(rect,sphere)进行绘制,而不使用这个传递进来的geometry(或者在外部传递两个geometry,一个rect一个sphereinstance)
+ nbRenderedLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, nbRenderedLights, isLightCullStageDraw, lastTexUnit);
+ renderer.setShader(shader);
+ renderMeshFromGeometry(renderer, geometry);
+ }
+ }
+ else{
+ int batchSize = renderManager.getSinglePassLightBatchSize();
+ if (lights.size() == 0) {
+ updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, 0, isLightCullStageDraw);
+ renderer.setShader(shader);
+ renderMeshFromGeometry(renderer, geometry);
+ } else {
+ while (nbRenderedLights < lights.size()) {
+ nbRenderedLights = updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, nbRenderedLights, isLightCullStageDraw);
+ renderer.setShader(shader);
+ renderMeshFromGeometry(renderer, geometry);
+ }
+ }
+ }
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/SkyLightAndReflectionProbeRender.java b/jme3-core/src/main/java/com/jme3/material/logic/SkyLightAndReflectionProbeRender.java
new file mode 100644
index 0000000000..f402c32a85
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/material/logic/SkyLightAndReflectionProbeRender.java
@@ -0,0 +1,72 @@
+package com.jme3.material.logic;
+
+import com.jme3.light.AmbientLight;
+import com.jme3.light.Light;
+import com.jme3.light.LightList;
+import com.jme3.light.LightProbe;
+import com.jme3.math.ColorRGBA;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.renderer.TextureUnitException;
+import com.jme3.shader.Uniform;
+import com.jme3.shader.VarType;
+import com.jme3.texture.TextureCubeMap;
+
+import java.util.List;
+
+/**
+ * Rendering logic for handling SkyLight and ReflectionProbe.
+ * @author JohnKkk
+ */
+public class SkyLightAndReflectionProbeRender {
+
+ public static int setSkyLightAndReflectionProbeData(RenderManager rm, int lastTexUnit, Uniform lightProbeData, Uniform shCoeffs, Uniform lightProbePemMap, LightProbe lightProbe) {
+
+ lightProbeData.setValue(VarType.Matrix4, lightProbe.getUniformMatrix());
+ //setVector4InArray(lightProbe.getPosition().x, lightProbe.getPosition().y, lightProbe.getPosition().z, 1f / area.getRadius() + lightProbe.getNbMipMaps(), 0);
+ shCoeffs.setValue(VarType.Vector3Array, lightProbe.getShCoeffs());
+ /*
+ * Assign the prefiltered env map to the next available texture unit.
+ */
+ int pemUnit = lastTexUnit++;
+ Renderer renderer = rm.getRenderer();
+ TextureCubeMap pemTexture = lightProbe.getPrefilteredEnvMap();
+ try {
+ renderer.setTexture(pemUnit, pemTexture);
+ } catch (TextureUnitException exception) {
+ String message = "Can't assign texture unit for SkyLightAndReflectionProbe."
+ + " lastTexUnit=" + lastTexUnit;
+ throw new IllegalArgumentException(message);
+ }
+ lightProbePemMap.setValue(VarType.Int, pemUnit);
+ return lastTexUnit;
+ }
+
+ public static void extractSkyLightAndReflectionProbes(LightList lightList, ColorRGBA ambientLightColor, List skyLightAndReflectionProbes, boolean removeLights) {
+ ambientLightColor.set(0, 0, 0, 1);
+ skyLightAndReflectionProbes.clear();
+ 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);
+ j--;
+ }
+ }
+ if (l instanceof LightProbe) {
+ skyLightAndReflectionProbes.add((LightProbe) l);
+ if(removeLights){
+ lightList.remove(l);
+ j--;
+ }
+ }
+ }
+ // todo:For reflection probes, only top three in view frustum are processed per frame (but scene can contain large amount of reflection probes)
+ if(skyLightAndReflectionProbes.size() > 3){
+
+ }
+ ambientLightColor.a = 1.0f;
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
new file mode 100644
index 0000000000..7be6e4f810
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
@@ -0,0 +1,807 @@
+package com.jme3.material.logic;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.light.*;
+import com.jme3.material.RenderState;
+import com.jme3.material.TechniqueDef;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Matrix4f;
+import com.jme3.math.Vector3f;
+import com.jme3.math.Vector4f;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.Caps;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.scene.Geometry;
+import com.jme3.shader.DefineList;
+import com.jme3.shader.Shader;
+import com.jme3.shader.Uniform;
+import com.jme3.shader.VarType;
+import com.jme3.texture.Image;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture2D;
+import com.jme3.texture.image.ColorSpace;
+import com.jme3.texture.image.ImageRaster;
+import com.jme3.util.BufferUtils;
+import com.jme3.util.TempVars;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+
+/**
+ * @author JohnKkk
+ */
+public class TileBasedDeferredSinglePassLightingLogic extends DefaultTechniqueDefLogic{
+ private final static String _S_LIGHT_CULL_DRAW_STAGE = "Light_Cull_Draw_Stage";
+ private static final String DEFINE_TILE_BASED_DEFERRED_SINGLE_PASS_LIGHTING = "TILE_BASED_DEFERRED_SINGLE_PASS_LIGHTING";
+ private static final String DEFINE_NB_LIGHTS = "NB_LIGHTS";
+ private static final String DEFINE_USE_TEXTURE_PACK_MODE = "USE_TEXTURE_PACK_MODE";
+ private static final String DEFINE_PACK_NB_LIGHTS = "PACK_NB_LIGHTS";
+ private static final String DEFINE_NB_SKY_LIGHT_AND_REFLECTION_PROBES = "NB_SKY_LIGHT_AND_REFLECTION_PROBES";
+ // Light source retrieval encoded in ppx of Tile
+ private static final String TILE_LIGHT_DECODE = "TileLightDecode";
+ // Light source id encoded in ppx of Tile
+ private static final String TILE_LIGHT_INDEX = "TileLightIndex";
+ // Sampling offset size in Tile
+ private static final String TILE_LIGHT_OFFSET_SIZE = "g_TileLightOffsetSize";
+ private static final RenderState ADDITIVE_LIGHT = new RenderState();
+ private boolean bUseTexturePackMode = true;
+ // 避免过多的光源
+ private static final int MAX_LIGHT_NUM = 9046;
+ // 使用texture来一次性存储大量光源数据,避免多次绘制
+ private Texture2D lightData1;
+ private Texture2D lightData2;
+ private Texture2D lightData3;
+ private ImageRaster lightDataUpdateIO1;
+ private ImageRaster lightDataUpdateIO2;
+ private ImageRaster lightDataUpdateIO3;
+ private int lightNum;
+
+ private final ColorRGBA ambientLightColor = new ColorRGBA(0, 0, 0, 1);
+ final private List skyLightAndReflectionProbes = new ArrayList<>(3);
+
+ static {
+ ADDITIVE_LIGHT.setBlendMode(RenderState.BlendMode.AlphaAdditive);
+ ADDITIVE_LIGHT.setDepthWrite(false);
+ }
+
+ private final int singlePassLightingDefineId;
+ private int nbLightsDefineId;
+ private int packNbLightsDefineId;
+ private int packTextureModeDefineId;
+ private final int nbSkyLightAndReflectionProbesDefineId;
+
+
+
+ // temp var
+ private Matrix4f _vp;
+ private float _camLeftCoeff = -1;
+ private float _camTopCoeff = -1;
+ private float _viewPortWidth = -1;
+ private float _viewPortHeight = -1;
+ private float[] _matArray1 = new float[16];
+ private float[] _matArray2 = new float[16];
+ private Vector3f _tempVec3 = new Vector3f();
+ private Vector3f _tempVec3_2 = new Vector3f();
+ private Vector4f _tempVec4 = new Vector4f();
+ private Vector4f _tempvec4_2 = new Vector4f();
+ private Vector4f _tempVec4_3 = new Vector4f();
+ private Vector4f _camUp = new Vector4f();
+ private Vector4f _camLeft = new Vector4f();
+ private Vector4f _lightLeft = new Vector4f();
+ private Vector4f _lightUp = new Vector4f();
+ private Vector4f _lightCenter = new Vector4f();
+ private LightFrustum _lightFrustum = new LightFrustum(0, 0, 0, 0);
+
+ // tile info
+ private TileInfo tileInfo;
+ private int _tileWidth = -1;
+ private int _tileHeight = -1;
+ private int _curTileNum = 0;
+
+ // tile light ids
+ private ArrayList> tiles;
+ // lightsIndex per tile
+ private ArrayList lightsIndex;
+ // lightsDecode per tile
+ private ArrayList lightsDecode;
+ private Texture2D lightsIndexData;
+ private Texture2D lightsDecodeData;
+ private ImageRaster lightsIndexDataUpdateIO;
+ private ImageRaster lightsDecodeDataUpdateIO;
+ private int lightIndexWidth;
+
+ /**
+ * TileInfo
+ */
+ public static class TileInfo{
+ int tileSize = 0;
+ int tileWidth = 0;
+ int tileHeight = 0;
+ int tileNum = 0;
+
+ public TileInfo(int tileSize, int tileWidth, int tileHeight, int tileNum) {
+ this.tileSize = tileSize;
+ this.tileWidth = tileWidth;
+ this.tileHeight = tileHeight;
+ this.tileNum = tileNum;
+ }
+
+ public void updateTileSize(int tileSize){
+ this.tileSize = tileSize;
+ }
+ }
+
+ /**
+ * LightFrustum
+ */
+ private static class LightFrustum{
+ float left;
+ float right;
+ float top;
+ float bottom;
+
+ public LightFrustum(float left, float right, float top, float bottom) {
+ this.left = left;
+ this.right = right;
+ this.top = top;
+ this.bottom = bottom;
+ }
+ }
+
+ private void cleanupLightsIndexTexture(){
+ if(lightsIndexData != null){
+ lightsIndexData.getImage().dispose();
+ lightsIndexData = null;
+ }
+ }
+
+ private void cleanupLightsDecodeTexture(){
+ if(lightsDecodeData != null){
+ lightsDecodeData.getImage().dispose();
+ lightsDecodeData = null;
+ }
+ }
+
+ private void cleanupTileTexture(){
+ cleanupLightsIndexTexture();
+ cleanupLightsDecodeTexture();
+ }
+
+ /**
+ * reset.
+ * @param tileNum
+ */
+ private void reset(int tileWidth, int tileHeight, int tileNum){
+ if(tileWidth != _tileWidth || tileHeight != _tileHeight){
+ cleanupTileTexture();
+ _tileWidth = tileWidth;
+ _tileHeight = tileHeight;
+
+ lightIndexWidth = (int)(Math.floor(Math.sqrt(1024)));
+ lightsIndexData = new Texture2D(lightIndexWidth, lightIndexWidth, Image.Format.RGBA32F);
+ lightsIndexData.setMinFilter(Texture.MinFilter.NearestNoMipMaps);
+ lightsIndexData.setMagFilter(Texture.MagFilter.Nearest);
+ lightsIndexData.setWrap(Texture.WrapMode.EdgeClamp);
+ ByteBuffer dataT = BufferUtils.createByteBuffer( (int)Math.ceil(Image.Format.RGBA32F.getBitsPerPixel() / 8.0) * lightIndexWidth * lightIndexWidth);
+ Image convertedImageT = new Image(Image.Format.RGBA32F, lightIndexWidth, lightIndexWidth, dataT, null, ColorSpace.Linear);
+ lightsIndexData.setImage(convertedImageT);
+ lightsIndexData.getImage().setMipmapsGenerated(false);
+ lightsIndexDataUpdateIO = ImageRaster.create(lightsIndexData.getImage());
+
+
+ lightsDecodeData = new Texture2D(_tileWidth, _tileHeight, Image.Format.RGBA32F);
+ lightsDecodeData.setMinFilter(Texture.MinFilter.NearestNoMipMaps);
+ lightsDecodeData.setMagFilter(Texture.MagFilter.Nearest);
+ lightsDecodeData.setWrap(Texture.WrapMode.EdgeClamp);
+ ByteBuffer dataU = BufferUtils.createByteBuffer( (int)Math.ceil(Image.Format.RGBA32F.getBitsPerPixel() / 8.0) * _tileWidth * _tileHeight);
+ Image convertedImageU = new Image(Image.Format.RGBA32F, _tileWidth, _tileHeight, dataU, null, ColorSpace.Linear);
+ lightsDecodeData.setImage(convertedImageU);
+ lightsDecodeData.getImage().setMipmapsGenerated(false);
+ lightsDecodeDataUpdateIO = ImageRaster.create(lightsDecodeData.getImage());
+ }
+ if(_curTileNum != tileNum){
+ tiles = new ArrayList>();
+ for(int i = 0;i < tileNum;i++){
+ tiles.add(new ArrayList<>());
+ }
+ }
+ else{
+ for(int i = 0;i < tileNum;i++){
+ tiles.get(i).clear();
+ }
+ }
+ if(lightsDecode == null){
+ lightsDecode = new ArrayList<>();
+ }
+ lightsDecode.clear();
+ if(lightsIndex == null){
+ lightsIndex = new ArrayList<>();
+ }
+ lightsIndex.clear();
+ }
+ private void tilesFullUpdate(int tileWidth, int tileHeight, int tileNum, ArrayList> tiles, int lightId){
+ // calc tiles
+ int tileId = 0;
+ for(int l = 0;l < tileWidth;l++){
+ for(int b = 0;b < tileHeight;b++){
+ tileId = l + b * tileWidth;
+ if(tileId >= 0 && tileId < tileNum){
+ tiles.get(tileId).add(lightId);
+ }
+ }
+ }
+ }
+
+ private void tilesUpdate(int tileSize, int tileWidth, int tileHeight, int tileNum, ArrayList> tiles, LightFrustum lightFrustum, int lightId){
+ // tile built on
+ //⬆
+ //|
+ //|
+ //----------➡
+ // so,Using pixel screen precision, stepping top-right
+ int tileLeft = (int) Math.max(Math.floor(lightFrustum.left / tileSize), 0);
+ int tileRight = (int) Math.min(Math.ceil(lightFrustum.right / tileSize), tileWidth);
+ int tileBottom = (int) Math.max(Math.floor(lightFrustum.bottom / tileSize), 0);
+ int tileTop = (int) Math.min(Math.ceil(lightFrustum.top / tileSize), tileHeight);
+
+ // calc tiles
+ int tileId = 0;
+ for(int l = tileLeft;l < tileRight;l++){
+ for(int b = tileBottom;b < tileTop;b++){
+ tileId = l + b * tileWidth;
+ if(tileId >= 0 && tileId < tileNum){
+ tiles.get(tileId).add(lightId);
+ }
+ }
+ }
+ }
+ private final LightFrustum lightClip(Camera camera, Light light){
+ if(light instanceof PointLight){
+ PointLight pl = (PointLight)light;
+ float r = pl.getRadius();
+ if(r <= 0)return null;
+ camera.getUp().add(pl.getPosition(), _tempVec3);
+ _tempVec3.multLocal(r);
+ camera.getScreenCoordinates(_tempVec3, _tempVec3_2);
+ float t = _tempVec3_2.y;
+
+ camera.getUp().mult(-1, _tempVec3);
+ _tempVec3.add(pl.getPosition(), _tempVec3_2);
+ _tempVec3_2.multLocal(r);
+ camera.getScreenCoordinates(_tempVec3_2, _tempVec3);
+ float b = _tempVec3.y;
+
+ camera.getLeft().add(pl.getPosition(), _tempVec3_2);
+ _tempVec3_2.multLocal(r);
+ camera.getScreenCoordinates(_tempVec3_2, _tempVec3);
+ float l = _tempVec3.x;
+
+ camera.getLeft().mult(-1, _tempVec3);
+ _tempVec3.add(pl.getPosition(), _tempVec3_2);
+ camera.getScreenCoordinates(_tempVec3_2, _tempVec3);
+ r = _tempVec3.x;
+ _lightFrustum.left = l;
+ _lightFrustum.right = r;
+ _lightFrustum.bottom = b;
+ _lightFrustum.top = t;
+ return _lightFrustum;
+ }
+ return null;
+ }
+
+ private final LightFrustum lightClip(Light light){
+ // todo:Currently, only point light sources are processed
+ if(light instanceof PointLight){
+ PointLight pl = (PointLight)light;
+ float r = pl.getRadius();
+ if(r <= 0)return null;
+ float lr = r * _camLeftCoeff;
+ float tr = r * _camTopCoeff;
+ _tempVec4.set(pl.getPosition().x, pl.getPosition().y, pl.getPosition().z, 1.0f);
+ Vector4f center = _tempVec4;
+ _tempvec4_2.w = 1.0f;
+ _tempVec4_3.w = 1.0f;
+
+ _camLeft.mult(lr, _tempvec4_2);
+ _tempvec4_2.addLocal(center);
+ Vector4f lightFrustumLeft = _tempvec4_2;
+ lightFrustumLeft.w = 1.0f;
+
+ _camUp.mult(tr, _tempVec4_3);
+ _tempVec4_3.addLocal(center);
+ Vector4f lightFrustumUp = _tempVec4_3;
+ lightFrustumUp.w = 1.0f;
+
+ _vp.mult(lightFrustumLeft, _lightLeft);
+ _vp.mult(lightFrustumUp, _lightUp);
+ _vp.mult(center, _lightCenter);
+
+ _lightLeft.x /= _lightLeft.w;
+ _lightLeft.y /= _lightLeft.w;
+
+ _lightUp.x /= _lightUp.w;
+ _lightUp.y /= _lightUp.w;
+
+ _lightCenter.x /= _lightCenter.w;
+ _lightCenter.y /= _lightCenter.w;
+
+ _lightLeft.x = _viewPortWidth * (1.0f + _lightLeft.x);
+ _lightUp.x = _viewPortWidth * (1.0f + _lightUp.x);
+ _lightCenter.x = _viewPortWidth * (1.0f + _lightCenter.x);
+
+ _lightLeft.y = _viewPortHeight * (1.0f - _lightLeft.y);
+ _lightUp.y = _viewPortHeight * (1.0f - _lightUp.y);
+ _lightCenter.y = _viewPortHeight * (1.0f - _lightCenter.y);
+
+ // light frustum rect
+ float lw = Math.abs(_lightLeft.x - _lightCenter.x);
+ float lh = Math.abs(_lightCenter.y - _lightUp.y);
+ float left = -1.0f, btm = -1.0f;
+ if(_lightCenter.z < -_lightCenter.w){
+ left = -_lightCenter.x - lw;
+ btm = -_lightCenter.y + lh;
+ }
+ else{
+ left = _lightCenter.x - lw;
+ btm = _lightCenter.y + lh;
+ }
+ float bottom = _viewPortHeight * 2.0f - btm;
+ _lightFrustum.left = left;
+ _lightFrustum.right = lw * 2.0f + left;
+ _lightFrustum.top = lh * 2.0f + bottom;
+ _lightFrustum.bottom = bottom;
+ return _lightFrustum;
+ }
+ return null;
+ }
+
+ private void tileLightDecode(int tileNum, ArrayList> tiles, int tileWidth, int tileHeight, Shader shader, Geometry g, LightList lights){
+ int len = lights.size();
+
+ ArrayList tile = null;
+ for(int i = 0, offset = 0;i < tileNum;i++){
+ tile = tiles.get(i);
+ len = tile.size();
+ for(int l = 0;l < len;l++){
+ lightsIndex.add(tile.get(l));
+ lightsIndex.add(0);
+ lightsIndex.add(0);
+ }
+ // u offset
+ lightsDecode.add(offset);
+ // tile light num
+ lightsDecode.add(len);
+ // Add in next step
+ lightsDecode.add(-1);
+ offset += len;
+ }
+ // Calculate light sampling size
+ int lightIndexWidth = (int) Math.ceil(Math.sqrt(lightsIndex.size() / 3));
+// int _lightIndexWidth = (int) Math.ceil(lightIndexWidth / 3);
+ // updateData
+ Uniform tileLightOffsetSizeUniform = shader.getUniform(TILE_LIGHT_OFFSET_SIZE);
+ tileLightOffsetSizeUniform.setValue(VarType.Int, lightIndexWidth);
+
+ // padding
+ for(int i = lightsIndex.size(), size = lightIndexWidth * lightIndexWidth * 3;i < size;i++){
+ lightsIndex.add(-1);
+ }
+
+ // Normalize the light uv of each tile to the light size range
+ for(int i = 0, size = lightsDecode.size();i < size;i+=3){
+ // The b component stores the v offset
+ lightsDecode.set(i + 2, lightsDecode.get(i) / lightIndexWidth);
+ lightsDecode.set(i, lightsDecode.get(i) % lightIndexWidth);
+ }
+ // updateData
+ TempVars vars = TempVars.get();
+ ColorRGBA temp = vars.color;
+ temp.b = temp.g = 0.0f;
+ temp.a = 1.0f;
+ for(int i = 0, size = lightIndexWidth;i < size;i++){
+ for(int j = 0, size2 = lightIndexWidth;j < size2;j++){
+ temp.r = lightsIndex.get((j + i * lightIndexWidth) * 3);
+ temp.g = 0.0f;
+ lightsIndexDataUpdateIO.setPixel(j, i, temp);
+ }
+ }
+ for(int i = 0;i < tileHeight;i++){
+ for(int j = 0;j < tileWidth;j++){
+ temp.r = lightsDecode.get((j + i * tileWidth) * 3);
+ temp.g = lightsDecode.get((j + i * tileWidth) * 3 + 1);
+ temp.b = lightsDecode.get((j + i * tileWidth) * 3 + 2);
+ lightsDecodeDataUpdateIO.setPixel(j, i, temp);
+ }
+ }
+ vars.release();
+ lightsIndexData.getImage().setUpdateNeeded();
+ lightsDecodeData.getImage().setUpdateNeeded();
+ g.getMaterial().setTexture(TILE_LIGHT_INDEX, lightsIndexData);
+ g.getMaterial().setTexture(TILE_LIGHT_DECODE, lightsDecodeData);
+ }
+
+
+ public TileBasedDeferredSinglePassLightingLogic(TechniqueDef techniqueDef) {
+ super(techniqueDef);
+ singlePassLightingDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_TILE_BASED_DEFERRED_SINGLE_PASS_LIGHTING, VarType.Boolean);
+ if(bUseTexturePackMode){
+ packNbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_PACK_NB_LIGHTS, VarType.Int);
+ packTextureModeDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_USE_TEXTURE_PACK_MODE, VarType.Boolean);
+ prepaLightData(1024);
+ }
+ else{
+ nbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_LIGHTS, VarType.Int);
+ }
+ nbSkyLightAndReflectionProbesDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_SKY_LIGHT_AND_REFLECTION_PROBES, VarType.Int);
+ }
+
+ private void prepaLightData(int lightNum){
+ this.lightNum = lightNum;
+ // 1d texture
+ lightData1 = new Texture2D(lightNum, 1, Image.Format.RGBA32F);
+ lightData1.setMinFilter(Texture.MinFilter.NearestNoMipMaps);
+ lightData1.setMagFilter(Texture.MagFilter.Nearest);
+ lightData1.setWrap(Texture.WrapMode.EdgeClamp);
+ ByteBuffer data = BufferUtils.createByteBuffer( (int)Math.ceil(Image.Format.RGBA32F.getBitsPerPixel() / 8.0) * lightNum);
+ Image convertedImage = new Image(Image.Format.RGBA32F, lightNum, 1, data, null, ColorSpace.Linear);
+ lightData1.setImage(convertedImage);
+ lightData1.getImage().setMipmapsGenerated(false);
+ lightDataUpdateIO1 = ImageRaster.create(lightData1.getImage());
+
+ lightData2 = new Texture2D(lightNum, 1, Image.Format.RGBA32F);
+ lightData2.setMinFilter(Texture.MinFilter.NearestNoMipMaps);
+ lightData2.setMagFilter(Texture.MagFilter.Nearest);
+ lightData2.setWrap(Texture.WrapMode.EdgeClamp);
+ ByteBuffer data2 = BufferUtils.createByteBuffer( (int)Math.ceil(Image.Format.RGBA32F.getBitsPerPixel() / 8.0) * lightNum);
+ Image convertedImage2 = new Image(Image.Format.RGBA32F, lightNum, 1, data2, null, ColorSpace.Linear);
+ lightData2.setImage(convertedImage2);
+ lightData2.getImage().setMipmapsGenerated(false);
+ lightDataUpdateIO2 = ImageRaster.create(lightData2.getImage());
+
+ lightData3 = new Texture2D(lightNum, 1, Image.Format.RGBA32F);
+ lightData3.setMinFilter(Texture.MinFilter.NearestNoMipMaps);
+ lightData3.setMagFilter(Texture.MagFilter.Nearest);
+ lightData3.setWrap(Texture.WrapMode.EdgeClamp);
+ ByteBuffer data3 = BufferUtils.createByteBuffer( (int)Math.ceil(Image.Format.RGBA32F.getBitsPerPixel() / 8.0) * lightNum);
+ Image convertedImage3 = new Image(Image.Format.RGBA32F, lightNum, 1, data3, null, ColorSpace.Linear);
+ lightData3.setImage(convertedImage3);
+ lightData3.getImage().setMipmapsGenerated(false);
+ lightDataUpdateIO3 = ImageRaster.create(lightData3.getImage());
+ }
+
+ @Override
+ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager,
+ EnumSet rendererCaps, LightList lights, DefineList defines) {
+ if(bUseTexturePackMode){
+ defines.set(packNbLightsDefineId, this.lightNum);
+ defines.set(packTextureModeDefineId, true);
+ }
+ else{
+ defines.set(nbLightsDefineId, renderManager.getSinglePassLightBatchSize() * 3);
+ }
+ defines.set(singlePassLightingDefineId, true);
+ //TODO here we have a problem, this is called once before render, so the define will be set for all passes (in case we have more than NB_LIGHTS lights)
+ //Though the second pass should not render IBL as it is taken care of on first pass like ambient light in phong lighting.
+ //We cannot change the define between passes and the old technique, and for some reason the code fails on mac (renders nothing).
+ if(lights != null) {
+ SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, false);
+ defines.set(nbSkyLightAndReflectionProbesDefineId, skyLightAndReflectionProbes.size());
+ }
+ return super.makeCurrent(assetManager, renderManager, rendererCaps, lights, defines);
+ }
+
+ protected int updateLightListPackToTexture(Shader shader, Geometry g, LightList lightList, int numLights, RenderManager rm, int startIndex, boolean isLightCullStageDraw, int lastTexUnit) {
+ if (numLights == 0) { // this shader does not do lighting, ignore.
+ return 0;
+ }
+
+ Uniform ambientColor = shader.getUniform("g_AmbientLightColor");
+
+ if (startIndex != 0 || isLightCullStageDraw) {
+ // apply additive blending for 2nd and future passes
+ rm.getRenderer().applyRenderState(ADDITIVE_LIGHT);
+ ambientColor.setValue(VarType.Vector4, ColorRGBA.Black);
+ } else {
+ ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, true, ambientLightColor));
+ }
+
+ // render skyLights and reflectionProbes
+ if(!skyLightAndReflectionProbes.isEmpty()){
+ // Matrix4f
+ Uniform skyLightData = shader.getUniform("g_SkyLightData");
+ Uniform skyLightData2 = shader.getUniform("g_SkyLightData2");
+ Uniform skyLightData3 = shader.getUniform("g_SkyLightData3");
+
+ Uniform shCoeffs = shader.getUniform("g_ShCoeffs");
+ Uniform reflectionProbePemMap = shader.getUniform("g_ReflectionEnvMap");
+ Uniform shCoeffs2 = shader.getUniform("g_ShCoeffs2");
+ Uniform reflectionProbePemMap2 = shader.getUniform("g_ReflectionEnvMap2");
+ Uniform shCoeffs3 = shader.getUniform("g_ShCoeffs3");
+ Uniform reflectionProbePemMap3 = shader.getUniform("g_ReflectionEnvMap3");
+
+ LightProbe skyLight = skyLightAndReflectionProbes.get(0);
+ lastTexUnit = SkyLightAndReflectionProbeRender.setSkyLightAndReflectionProbeData(rm, lastTexUnit, skyLightData, shCoeffs, reflectionProbePemMap, skyLight);
+ if (skyLightAndReflectionProbes.size() > 1) {
+ skyLight = skyLightAndReflectionProbes.get(1);
+ lastTexUnit = SkyLightAndReflectionProbeRender.setSkyLightAndReflectionProbeData(rm, lastTexUnit, skyLightData2, shCoeffs2, reflectionProbePemMap2, skyLight);
+ }
+ if (skyLightAndReflectionProbes.size() > 2) {
+ skyLight = skyLightAndReflectionProbes.get(2);
+ SkyLightAndReflectionProbeRender.setSkyLightAndReflectionProbeData(rm, lastTexUnit, skyLightData3, shCoeffs3, reflectionProbePemMap3, skyLight);
+ }
+ } else {
+ Uniform skyLightData = shader.getUniform("g_SkyLightData");
+ //Disable IBL for this pass
+ skyLightData.setValue(VarType.Matrix4, LightProbe.FALLBACK_MATRIX);
+ }
+
+ TempVars vars = TempVars.get();
+ int curIndex;
+ int endIndex = numLights + startIndex;
+ ColorRGBA temp = vars.color;
+ for (curIndex = startIndex; curIndex < endIndex && curIndex < lightList.size(); curIndex++) {
+
+ Light l = lightList.get(curIndex);
+ if (l.getType() == Light.Type.Ambient || l.getType() == Light.Type.Probe) {
+ endIndex++;
+ continue;
+ }
+ ColorRGBA color = l.getColor();
+ //Color
+ temp.r = color.getRed();
+ temp.g = color.getGreen();
+ temp.b = color.getBlue();
+ temp.a = l.getType().getId();
+ lightDataUpdateIO1.setPixel(curIndex, 0, temp);
+
+ switch (l.getType()) {
+ case Directional:
+ DirectionalLight dl = (DirectionalLight) l;
+ Vector3f dir = dl.getDirection();
+ temp.r = dir.getX();
+ temp.g = dir.getY();
+ temp.b = dir.getZ();
+ temp.a = -1;
+ lightDataUpdateIO2.setPixel(curIndex, 0, temp);
+ break;
+ case Point:
+ PointLight pl = (PointLight) l;
+ Vector3f pos = pl.getPosition();
+ float invRadius = pl.getInvRadius();
+ temp.r = pos.getX();
+ temp.g = pos.getY();
+ temp.b = pos.getZ();
+ temp.a = invRadius;
+ lightDataUpdateIO2.setPixel(curIndex, 0, temp);
+ break;
+ case Spot:
+ SpotLight sl = (SpotLight) l;
+ Vector3f pos2 = sl.getPosition();
+ Vector3f dir2 = sl.getDirection();
+ float invRange = sl.getInvSpotRange();
+ float spotAngleCos = sl.getPackedAngleCos();
+ temp.r = pos2.getX();
+ temp.g = pos2.getY();
+ temp.b = pos2.getZ();
+ temp.a = invRange;
+ lightDataUpdateIO2.setPixel(curIndex, 0, temp);
+
+ //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.
+ temp.r = dir2.getX();
+ temp.g = dir2.getY();
+ temp.b = dir2.getZ();
+ temp.a = spotAngleCos;
+ lightDataUpdateIO3.setPixel(curIndex, 0, temp);
+ break;
+ default:
+ throw new UnsupportedOperationException("Unknown type of light: " + l.getType());
+ }
+ }
+ vars.release();
+ lightData1.getImage().setUpdateNeeded();
+ lightData2.getImage().setUpdateNeeded();
+ lightData3.getImage().setUpdateNeeded();
+// Uniform g_LightPackData1 = shader.getUniform("g_LightPackData1");
+// g_LightPackData1.setValue(VarType.Texture2D, lightData1);
+// Uniform g_LightPackData2 = shader.getUniform("g_LightPackData2");
+// g_LightPackData2.setValue(VarType.Texture2D, lightData2);
+// Uniform g_LightPackData3 = shader.getUniform("g_LightPackData3");
+// g_LightPackData3.setValue(VarType.Texture2D, lightData3);
+ g.getMaterial().setTexture("LightPackData1", lightData1);
+ g.getMaterial().setTexture("LightPackData2", lightData2);
+ g.getMaterial().setTexture("LightPackData3", lightData3);
+ return curIndex;
+ }
+
+ /**
+ * Uploads the lights in the light list as two uniform arrays.
+ *
+ * uniform vec4 g_LightColor[numLights];
//
+ * g_LightColor.rgb is the diffuse/specular color of the light.
//
+ * g_Lightcolor.a is the type of light, 0 = Directional, 1 = Point,
//
+ * 2 = Spot.
+ * uniform vec4 g_LightPosition[numLights];
//
+ * g_LightPosition.xyz is the position of the light (for point lights)
+ * // or the direction of the light (for directional lights).
//
+ * g_LightPosition.w is the inverse radius (1/r) of the light (for
+ * attenuation)
+ *
+ * @param shader the Shader being used
+ * @param g the Geometry being rendered
+ * @param lightList the list of lights
+ * @param numLights the number of lights to upload
+ * @param rm to manage rendering
+ * @param startIndex the starting index in the LightList
+ * @param isLightCullStageDraw isLightCullStageDraw
+ * @return the next starting index in the LightList
+ */
+ protected int updateLightListUniforms(Shader shader, Geometry g, LightList lightList, int numLights, RenderManager rm, int startIndex, boolean isLightCullStageDraw) {
+ if (numLights == 0) { // this shader does not do lighting, ignore.
+ return 0;
+ }
+
+ Uniform lightData = shader.getUniform("g_LightData");
+ lightData.setVector4Length(numLights * 3);//8 lights * max 3
+ Uniform ambientColor = shader.getUniform("g_AmbientLightColor");
+
+ if (startIndex != 0 || isLightCullStageDraw) {
+ // apply additive blending for 2nd and future passes
+ rm.getRenderer().applyRenderState(ADDITIVE_LIGHT);
+ ambientColor.setValue(VarType.Vector4, ColorRGBA.Black);
+ } else {
+ ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, true, ambientLightColor));
+ }
+
+ 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 || l.getType() == Light.Type.Probe) {
+ endIndex++;
+ continue;
+ }
+ ColorRGBA color = l.getColor();
+ //Color
+ lightData.setVector4InArray(color.getRed(),
+ color.getGreen(),
+ color.getBlue(),
+ l.getType().getId(),
+ lightDataIndex);
+ lightDataIndex++;
+
+ switch (l.getType()) {
+ case Directional:
+ DirectionalLight dl = (DirectionalLight) l;
+ Vector3f dir = dl.getDirection();
+ lightData.setVector4InArray(dir.getX(), dir.getY(), dir.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();
+ lightData.setVector4InArray(pos.getX(), pos.getY(), pos.getZ(), invRadius, lightDataIndex);
+ lightDataIndex++;
+ //PADDING
+ lightData.setVector4InArray(0, 0, 0, 0, lightDataIndex);
+ lightDataIndex++;
+ break;
+ case Spot:
+ SpotLight sl = (SpotLight) l;
+ Vector3f pos2 = sl.getPosition();
+ Vector3f dir2 = sl.getDirection();
+ float invRange = sl.getInvSpotRange();
+ float spotAngleCos = sl.getPackedAngleCos();
+ lightData.setVector4InArray(pos2.getX(), pos2.getY(), pos2.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.
+ lightData.setVector4InArray(dir2.getX(), dir2.getY(), dir2.getZ(), spotAngleCos, lightDataIndex);
+ lightDataIndex++;
+ break;
+ default:
+ throw new UnsupportedOperationException("Unknown type of light: " + l.getType());
+ }
+ }
+ vars.release();
+ // pad unused buffer space
+ while(lightDataIndex < numLights * 3) {
+ lightData.setVector4InArray(0f, 0f, 0f, 0f, lightDataIndex);
+ lightDataIndex++;
+ }
+ return curIndex;
+ }
+
+ @Override
+ public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) {
+ int nbRenderedLights = 0;
+ Renderer renderer = renderManager.getRenderer();
+ boolean isLightCullStageDraw = false;
+ if(geometry.getUserData(_S_LIGHT_CULL_DRAW_STAGE) != null){
+ isLightCullStageDraw = geometry.getUserData(_S_LIGHT_CULL_DRAW_STAGE);
+ }
+ if(bUseTexturePackMode){
+ Uniform lightCount = shader.getUniform("g_LightCount");
+ SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, true);
+ int count = lights.size();
+ lightCount.setValue(VarType.Int, count);
+ // Divide lights into full screen lights and non-full screen lights. Currently only PointLights with radius are treated as non-full screen lights.
+ // The lights passed in here must be PointLights with valid radii. Another approach is to fill tiles with infinite range Lights.
+ if(count > 0){
+
+ // 从RenderManager获取tileInfo
+ tileInfo = renderManager.getTileInfo();
+ int tileSize = tileInfo.tileSize;
+ int tileWidth = tileInfo.tileWidth;
+ int tileHeight = tileInfo.tileHeight;
+ int tileNum = tileInfo.tileNum;
+ reset(tileWidth, tileHeight, tileNum);
+
+ {
+ Camera camera = renderManager.getCurrentCamera();
+ _viewPortWidth = camera.getWidth() * 0.5f;
+ _viewPortHeight = camera.getHeight() * 0.5f;
+ _vp = camera.getViewProjectionMatrix();
+ Matrix4f v = camera.getViewMatrix();
+ v.get(_matArray1);
+ _tempVec3.set(_matArray1[0], _matArray1[1], _matArray1[2]);
+ _camLeftCoeff = 1.0f / camera.getWorldPlane(1).getNormal().dot(_tempVec3);
+ _tempVec3.set(_matArray1[4], _matArray1[5], _matArray1[6]);
+ _camTopCoeff = 1.0f / camera.getWorldPlane(2).getNormal().dot(_tempVec3);
+ _camLeft.set(_matArray1[0], _matArray1[1], _matArray1[2], -1.0f).multLocal(-1.0f);
+ _camUp.set(_matArray1[4], _matArray1[5], _matArray1[6], 1.0f);
+ }
+
+ // update tiles
+ for(int i = 0;i < count;i++){
+ _lightFrustum = lightClip(lights.get(i));
+ if(_lightFrustum != null){
+ tilesUpdate(tileSize, tileWidth, tileHeight, tileNum, tiles, _lightFrustum, i);
+ }
+ else{
+ // full tilesLight
+ tilesFullUpdate(tileWidth, tileHeight, tileNum, tiles, i);
+ }
+ }
+
+ // Encode light source information
+ lightCount.setValue(VarType.Int, count);
+ tileLightDecode(tileNum, tiles, tileWidth, tileHeight, shader, geometry, lights);
+ while (nbRenderedLights < count) {
+ nbRenderedLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, nbRenderedLights, isLightCullStageDraw, lastTexUnit);
+ renderer.setShader(shader);
+ renderMeshFromGeometry(renderer, geometry);
+ }
+ }
+ }
+ else{
+ // Do not use this branch, but keep it for possible future use
+ int batchSize = renderManager.getSinglePassLightBatchSize();
+ if (lights.size() == 0) {
+ updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, 0, isLightCullStageDraw);
+ renderer.setShader(shader);
+ renderMeshFromGeometry(renderer, geometry);
+ } else {
+ while (nbRenderedLights < lights.size()) {
+ nbRenderedLights = updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, nbRenderedLights, isLightCullStageDraw);
+ renderer.setShader(shader);
+ renderMeshFromGeometry(renderer, geometry);
+ }
+ }
+ }
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/math/FastMath.java b/jme3-core/src/main/java/com/jme3/math/FastMath.java
index 712e322e30..1f482585a2 100644
--- a/jme3-core/src/main/java/com/jme3/math/FastMath.java
+++ b/jme3-core/src/main/java/com/jme3/math/FastMath.java
@@ -843,6 +843,18 @@ public static float determinant(double m00, double m01, double m02,
* (m10 * det12 - m11 * det02 + m12 * det01));
}
+ /**
+ * Returns a random integer between min and max.
+ *
+ * @param min the desired minimum value
+ * @param max the desired maximum value
+ * @return A random int between min (inclusive) to
+ * max (inclusive).
+ */
+ public static float nextRandomFloat(float min, float max) {
+ return (nextRandomFloat() * (max - min + 1.0f)) + min;
+ }
+
/**
* Returns a random float between 0 and 1.
*
diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
index 5969a1d5bd..3539486dca 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
@@ -40,16 +40,21 @@
import com.jme3.material.RenderState;
import com.jme3.material.Technique;
import com.jme3.material.TechniqueDef;
+import com.jme3.material.logic.TileBasedDeferredSinglePassLightingLogic;
import com.jme3.math.Matrix4f;
import com.jme3.post.SceneProcessor;
import com.jme3.profile.AppProfiler;
import com.jme3.profile.AppStep;
import com.jme3.profile.SpStep;
import com.jme3.profile.VpStep;
+import com.jme3.renderer.framegraph.FGGlobal;
+import com.jme3.renderer.framegraph.FGRenderContext;
+import com.jme3.renderer.framegraph.FrameGraph;
import com.jme3.renderer.queue.GeometryList;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
+import com.jme3.renderer.renderPass.*;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
@@ -58,10 +63,8 @@
import com.jme3.shader.Shader;
import com.jme3.shader.UniformBinding;
import com.jme3.shader.UniformBindingManager;
-import com.jme3.shader.VarType;
import com.jme3.system.NullRenderer;
import com.jme3.system.Timer;
-import com.jme3.texture.FrameBuffer;
import com.jme3.util.SafeArrayList;
import java.util.ArrayList;
import java.util.Collections;
@@ -79,6 +82,48 @@
* @see Spatial
*/
public class RenderManager {
+ // TileInfo
+ private TileBasedDeferredSinglePassLightingLogic.TileInfo tileInfo;
+ // todo:Since glTexImage is not used to dynamically adjust lightIndex size currently, this tileSize needs to be set cautiously.
+ private int curTileSize = 64;
+ // frameGraph=============================================================================↓
+ private IRenderGeometry iRenderGeometry;
+ private boolean useFramegraph = true;
+ private FrameGraph frameGraph;
+ private GBufferPass gBufferPass;
+ private DeferredShadingPass deferredShadingPass;
+ private TileDeferredShadingPass tileDeferredShadingPass;
+ private OpaquePass opaquePass;
+ private SkyPass skyPass;
+ private TransparentPass transparentPass;
+ private TranslucentPass translucentPass;
+ private GuiPass guiPass;
+ private PostProcessorPass postProcessorPass;
+ // frameGraph=============================================================================↑
+
+ // RenderPath
+ public enum RenderPath{
+ None(-1, "None"),
+ Forward(0, "Forward"),
+ ForwardPlus(1, "ForwardPlus"),
+ Deferred(2, "Deferred"),
+ TiledDeferred(3, "TiledDeferred")
+ ;
+ private int id;
+ private String info;
+ RenderPath(int id, String info){
+ this.id = id;
+ this.info = info;
+ }
+
+ public int getId() {
+ return id;
+ }
+ public String getInfo(){
+ return info;
+ }
+ }
+ private RenderPath renderPath = RenderPath.Forward;
private static final Logger logger = Logger.getLogger(RenderManager.class.getName());
private final Renderer renderer;
@@ -103,7 +148,6 @@ public class RenderManager {
private LightFilter lightFilter = new DefaultLightFilter();
private TechniqueDef.LightMode preferredLightMode = TechniqueDef.LightMode.MultiPass;
private int singlePassLightBatchSize = 1;
- private MatParamOverride boundDrawBufferId=new MatParamOverride(VarType.Int,"BoundDrawBuffer",0);
/**
@@ -114,9 +158,89 @@ public class RenderManager {
*/
public RenderManager(Renderer renderer) {
this.renderer = renderer;
- this.forcedOverrides.add(boundDrawBufferId);
+ if(useFramegraph){
+ frameGraph = new FrameGraph(new FGRenderContext(null, null, null));
+ gBufferPass = new GBufferPass();
+ deferredShadingPass = new DeferredShadingPass();
+ tileDeferredShadingPass = new TileDeferredShadingPass();
+ opaquePass = new OpaquePass();
+ skyPass = new SkyPass();
+ transparentPass = new TransparentPass();
+ translucentPass = new TranslucentPass();
+ guiPass = new GuiPass();
+ postProcessorPass = new PostProcessorPass("PostPass");
+ }
+ }
+
+ /**
+ * EnableFrameGraph?
+ * @param useFramegraph
+ */
+ public final void enableFramegraph(boolean useFramegraph){
+ this.useFramegraph = useFramegraph;
+ }
+
+ /**
+ * SetTileBasedInfo.
+ * @param tileSize The current size of tiles for partitioning (default 32x32 pixels).
+ * @param tileWidth Number of tiles in the horizontal direction for partitioning.
+ * @param tileHeight Number of tiles in the vertical direction for partitioning.
+ * @param tileNum
+ */
+ private final void setTileInfo(int tileSize, int tileWidth, int tileHeight, int tileNum){
+ if(tileInfo == null){
+ tileInfo = new TileBasedDeferredSinglePassLightingLogic.TileInfo(tileSize, tileWidth, tileHeight, tileNum);
+ }
+ }
+
+ /**
+ * update tile size.
+ * @param tileSize
+ */
+ public final void updateTileSize(int tileSize){
+ if(curTileSize == tileSize)return;
+ curTileSize = tileSize;
+ }
+
+ public TileBasedDeferredSinglePassLightingLogic.TileInfo getTileInfo() {
+ return tileInfo;
+ }
+
+ /**
+ * Set an IRenderGeometry for executing drawing call interfaces for the specified FGPass.
+ * @param iRenderGeometry
+ *
+ * @see IRenderGeometry
+ */
+ public final void setRenderGeometryHandler(IRenderGeometry iRenderGeometry){
+ this.iRenderGeometry = iRenderGeometry;
+ }
+
+ public IRenderGeometry getRenderGeometryHandler() {
+ return iRenderGeometry;
}
+ /**
+ * SetRenderPath.
+ * @param renderPath
+ *
+ * @see RenderManager.RenderPath
+ */
+ public final void setRenderPath(RenderPath renderPath){
+ this.renderPath = renderPath;
+ }
+
+ /**
+ * Return renderPath.
+ * @return Current ActiveRenderPath.
+ *
+ * @see RenderManager.RenderPath
+ */
+ public final RenderPath getRenderPath(){
+ return this.renderPath;
+ }
+
+
/**
* Returns the pre ViewPort with the given name.
*
@@ -400,7 +524,7 @@ public void notifyRescale(float x, float y) {
for (ViewPort vp : preViewPorts) {
notifyRescale(vp, x, y);
}
- for (ViewPort vp : viewPorts) {
+ for (ViewPort vp : viewPorts) {
notifyRescale(vp, x, y);
}
for (ViewPort vp : postViewPorts) {
@@ -633,12 +757,6 @@ public void renderGeometry(Geometry geom) {
setWorldMatrix(geom.getWorldMatrix());
}
- // Use material override to pass the current target index (used in api such as GL ES that do not support glDrawBuffer)
- FrameBuffer currentFb = this.renderer.getCurrentFrameBuffer();
- if (currentFb != null && !currentFb.isMultiTarget()) {
- this.boundDrawBufferId.setValue(currentFb.getTargetIndex());
- }
-
// Perform light filtering if we have a light filter.
LightList lightList = geom.getWorldLightList();
@@ -647,9 +765,11 @@ public void renderGeometry(Geometry geom) {
lightFilter.filterLights(geom, filteredLightList);
lightList = filteredLightList;
}
+ // updateFilterLight
+ geom.setFilterLight(lightList);
Material material = geom.getMaterial();
-
+
// If forcedTechnique exists, we try to force it for the render.
// If it does not exist in the mat def, we check for forcedMaterial and render the geom if not null.
// Otherwise, the geometry is not rendered.
@@ -1171,88 +1291,194 @@ public void renderViewPort(ViewPort vp, float tpf) {
if (!vp.isEnabled()) {
return;
}
- if (prof != null) {
- prof.vpStep(VpStep.BeginRender, vp, null);
- }
- SafeArrayList processors = vp.getProcessors();
- if (processors.isEmpty()) {
- processors = null;
- }
+ if(useFramegraph){
+ RenderPath curRenderPath = vp.getRenderPath() == RenderPath.None ? renderPath : vp.getRenderPath();
- if (processors != null) {
- if (prof != null) {
- prof.vpStep(VpStep.PreFrame, vp, null);
+ frameGraph.reset();
+ frameGraph.getRenderContext().renderManager = this;
+ frameGraph.getRenderContext().renderQueue = vp.getQueue();
+ frameGraph.getRenderContext().viewPort = vp;
+
+ if (prof!=null) prof.vpStep(VpStep.BeginRender, vp, null);
+
+ SafeArrayList processors = vp.getProcessors();
+ if (processors.isEmpty()) {
+ processors = null;
}
- for (SceneProcessor proc : processors.getArray()) {
- if (!proc.isInitialized()) {
- proc.initialize(this, vp);
+
+ if (processors != null) {
+ if (prof != null) prof.vpStep(VpStep.PreFrame, vp, null);
+ for (SceneProcessor proc : processors.getArray()) {
+ if (!proc.isInitialized()) {
+ proc.initialize(this, vp);
+ }
+ proc.setProfiler(this.prof);
+ if (prof != null) prof.spStep(SpStep.ProcPreFrame, proc.getClass().getSimpleName());
+ proc.preFrame(tpf);
}
- proc.setProfiler(this.prof);
- if (prof != null) {
- prof.spStep(SpStep.ProcPreFrame, proc.getClass().getSimpleName());
+ }
+
+ renderer.setFrameBuffer(vp.getOutputFrameBuffer());
+ setCamera(vp.getCamera(), false);
+ if (vp.isClearDepth() || vp.isClearColor() || vp.isClearStencil()) {
+ if (vp.isClearColor()) {
+ renderer.setBackgroundColor(vp.getBackgroundColor());
}
- proc.preFrame(tpf);
+ renderer.clearBuffers(vp.isClearColor(),
+ vp.isClearDepth(),
+ vp.isClearStencil());
}
- }
- renderer.setFrameBuffer(vp.getOutputFrameBuffer());
- setCamera(vp.getCamera(), false);
- if (vp.isClearDepth() || vp.isClearColor() || vp.isClearStencil()) {
- if (vp.isClearColor()) {
- renderer.setBackgroundColor(vp.getBackgroundColor());
+ if (prof!=null) prof.vpStep(VpStep.RenderScene, vp, null);
+ List scenes = vp.getScenes();
+ for (int i = scenes.size() - 1; i >= 0; i--) {
+ renderScene(scenes.get(i), vp);
}
- renderer.clearBuffers(vp.isClearColor(),
- vp.isClearDepth(),
- vp.isClearStencil());
- }
- if (prof != null) {
- prof.vpStep(VpStep.RenderScene, vp, null);
- }
- List scenes = vp.getScenes();
- for (int i = scenes.size() - 1; i >= 0; i--) {
- renderScene(scenes.get(i), vp);
- }
+ if (processors != null) {
+ if (prof!=null) prof.vpStep(VpStep.PostQueue, vp, null);
+ for (SceneProcessor proc : processors.getArray()) {
+ if (prof != null) prof.spStep(SpStep.ProcPostQueue, proc.getClass().getSimpleName());
+ proc.postQueue(vp.getQueue());
+ }
+ }
- if (processors != null) {
+ if(curRenderPath == RenderPath.Deferred){
+ frameGraph.addPass(gBufferPass);
+ deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_0, gBufferPass.getName() + "." + GBufferPass.S_RT_0);
+ deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_1, gBufferPass.getName() + "." + GBufferPass.S_RT_1);
+ deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_2, gBufferPass.getName() + "." + GBufferPass.S_RT_2);
+ deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_3, gBufferPass.getName() + "." + GBufferPass.S_RT_3);
+ deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_4, gBufferPass.getName() + "." + GBufferPass.S_RT_4);
+ deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_LIGHT_DATA, gBufferPass.getName() + "." + GBufferPass.S_LIGHT_DATA);
+ deferredShadingPass.setSinkLinkage(FGGlobal.S_DEFAULT_FB, gBufferPass.getName() + "." + GBufferPass.S_FB);
+ frameGraph.addPass(deferredShadingPass);
+ }
+ else if(curRenderPath == RenderPath.TiledDeferred){
+ curTileSize = getCurrentCamera().getWidth() / 4;
+ int tileWidth = (int)(Math.floor(viewWidth / curTileSize));
+ int tileHeight = (int)(Math.floor(viewHeight / curTileSize));
+ setTileInfo(curTileSize, tileWidth, tileHeight, tileWidth * tileHeight);
+ frameGraph.addPass(gBufferPass);
+ tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_0, gBufferPass.getName() + "." + GBufferPass.S_RT_0);
+ tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_1, gBufferPass.getName() + "." + GBufferPass.S_RT_1);
+ tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_2, gBufferPass.getName() + "." + GBufferPass.S_RT_2);
+ tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_3, gBufferPass.getName() + "." + GBufferPass.S_RT_3);
+ tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_4, gBufferPass.getName() + "." + GBufferPass.S_RT_4);
+ tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_LIGHT_DATA, gBufferPass.getName() + "." + GBufferPass.S_LIGHT_DATA);
+ tileDeferredShadingPass.setSinkLinkage(FGGlobal.S_DEFAULT_FB, gBufferPass.getName() + "." + GBufferPass.S_FB);
+ frameGraph.addPass(tileDeferredShadingPass);
+ }
+ frameGraph.addPass(opaquePass);
+ frameGraph.addPass(skyPass);
+ frameGraph.addPass(transparentPass);
+ frameGraph.addPass(guiPass);
+
+ // todo:A temporary workaround for old pipeline postprocessors, unify later to use FG for internal logic, currently just replace with a simple PostProcessorPass
+// if (processors != null) {
+// if (prof!=null) prof.vpStep(VpStep.PostFrame, vp, null);
+// for (SceneProcessor proc : processors.getArray()) {
+// if (prof != null) prof.spStep(SpStep.ProcPostFrame, proc.getClass().getSimpleName());
+// proc.postFrame(vp.getOutputFrameBuffer());
+// }
+// if (prof != null) prof.vpStep(VpStep.ProcEndRender, vp, null);
+// }
+ frameGraph.addPass(postProcessorPass);
+ //renders the translucent objects queue after processors have been rendered
+ frameGraph.addPass(translucentPass);
+
+ frameGraph.finalize();
+ frameGraph.execute();
+ // clear any remaining spatials that were not rendered.
+ clearQueue(vp);
+
+ if (prof!=null) prof.vpStep(VpStep.EndRender, vp, null);
+ }
+ else{
if (prof != null) {
- prof.vpStep(VpStep.PostQueue, vp, null);
+ prof.vpStep(VpStep.BeginRender, vp, null);
}
- for (SceneProcessor proc : processors.getArray()) {
+
+ SafeArrayList processors = vp.getProcessors();
+ if (processors.isEmpty()) {
+ processors = null;
+ }
+
+ if (processors != null) {
if (prof != null) {
- prof.spStep(SpStep.ProcPostQueue, proc.getClass().getSimpleName());
+ prof.vpStep(VpStep.PreFrame, vp, null);
+ }
+ for (SceneProcessor proc : processors.getArray()) {
+ if (!proc.isInitialized()) {
+ proc.initialize(this, vp);
+ }
+ proc.setProfiler(this.prof);
+ if (prof != null) {
+ prof.spStep(SpStep.ProcPreFrame, proc.getClass().getSimpleName());
+ }
+ proc.preFrame(tpf);
}
- proc.postQueue(vp.getQueue());
}
- }
- if (prof != null) {
- prof.vpStep(VpStep.FlushQueue, vp, null);
- }
- flushQueue(vp);
+ renderer.setFrameBuffer(vp.getOutputFrameBuffer());
+ setCamera(vp.getCamera(), false);
+ if (vp.isClearDepth() || vp.isClearColor() || vp.isClearStencil()) {
+ if (vp.isClearColor()) {
+ renderer.setBackgroundColor(vp.getBackgroundColor());
+ }
+ renderer.clearBuffers(vp.isClearColor(),
+ vp.isClearDepth(),
+ vp.isClearStencil());
+ }
- if (processors != null) {
if (prof != null) {
- prof.vpStep(VpStep.PostFrame, vp, null);
+ prof.vpStep(VpStep.RenderScene, vp, null);
+ }
+ List scenes = vp.getScenes();
+ for (int i = scenes.size() - 1; i >= 0; i--) {
+ renderScene(scenes.get(i), vp);
}
- for (SceneProcessor proc : processors.getArray()) {
+
+ if (processors != null) {
if (prof != null) {
- prof.spStep(SpStep.ProcPostFrame, proc.getClass().getSimpleName());
+ prof.vpStep(VpStep.PostQueue, vp, null);
+ }
+ for (SceneProcessor proc : processors.getArray()) {
+ if (prof != null) {
+ prof.spStep(SpStep.ProcPostQueue, proc.getClass().getSimpleName());
+ }
+ proc.postQueue(vp.getQueue());
}
- proc.postFrame(vp.getOutputFrameBuffer());
}
+
if (prof != null) {
- prof.vpStep(VpStep.ProcEndRender, vp, null);
+ prof.vpStep(VpStep.FlushQueue, vp, null);
}
- }
- //renders the translucent objects queue after processors have been rendered
- renderTranslucentQueue(vp);
- // clear any remaining spatials that were not rendered.
- clearQueue(vp);
+ flushQueue(vp);
- if (prof != null) {
- prof.vpStep(VpStep.EndRender, vp, null);
+ if (processors != null) {
+ if (prof != null) {
+ prof.vpStep(VpStep.PostFrame, vp, null);
+ }
+ for (SceneProcessor proc : processors.getArray()) {
+ if (prof != null) {
+ prof.spStep(SpStep.ProcPostFrame, proc.getClass().getSimpleName());
+ }
+ proc.postFrame(vp.getOutputFrameBuffer());
+ }
+ if (prof != null) {
+ prof.vpStep(VpStep.ProcEndRender, vp, null);
+ }
+ }
+ //renders the translucent objects queue after processors have been rendered
+ renderTranslucentQueue(vp);
+ // clear any remaining spatials that were not rendered.
+ clearQueue(vp);
+
+ if (prof != null) {
+ prof.vpStep(VpStep.EndRender, vp, null);
+ }
}
}
@@ -1308,32 +1534,4 @@ public void render(float tpf, boolean mainFrameBufferActive) {
}
}
}
-
-
- /**
- * Returns true if the draw buffer target id is passed to the shader.
- *
- * @return True if the draw buffer target id is passed to the shaders.
- */
- public boolean getPassDrawBufferTargetIdToShaders() {
- return this.forcedOverrides.contains(boundDrawBufferId);
- }
-
- /**
- * Enable or disable passing the draw buffer target id to the shaders. This
- * is needed to handle FrameBuffer.setTargetIndex correctly in some
- * backends.
- *
- * @param v
- * True to enable, false to disable (default is true)
- */
- public void setPassDrawBufferTargetIdToShaders(boolean v) {
- if (v) {
- if (!this.forcedOverrides.contains(boundDrawBufferId)) {
- this.forcedOverrides.add(boundDrawBufferId);
- }
- } else {
- this.forcedOverrides.remove(boundDrawBufferId);
- }
- }
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/ViewPort.java b/jme3-core/src/main/java/com/jme3/renderer/ViewPort.java
index 6f0424fb30..7fb6a49be4 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/ViewPort.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/ViewPort.java
@@ -107,6 +107,8 @@ public class ViewPort {
protected boolean clearStencil = false;
private boolean enabled = true;
+ private RenderManager.RenderPath renderPath = RenderManager.RenderPath.None;
+
/**
* Creates a new viewport. User code should generally use these methods instead:
*
@@ -124,6 +126,18 @@ public ViewPort(String name, Camera cam) {
this.cam = cam;
}
+ /**
+ * forceRenderPath,if None use GlobalRenderPath
+ * @param renderPath
+ */
+ public void setRenderPath(RenderManager.RenderPath renderPath) {
+ this.renderPath = renderPath;
+ }
+
+ public RenderManager.RenderPath getRenderPath() {
+ return renderPath;
+ }
+
/**
* Returns the name of the viewport as set in the constructor.
*
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java
new file mode 100644
index 0000000000..e58f0082f8
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java
@@ -0,0 +1,20 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package com.jme3.renderer.framegraph;
+
+/**
+ *
+ * @author JohnKkk
+ */
+public abstract class FGBindable {
+ private final static String _S_DEFAULT_BINDABLE_UID = "";
+
+ public void bind(FGRenderContext renderContext){}
+
+ public String getUID(){
+ assert false;
+ return _S_DEFAULT_BINDABLE_UID;
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java
new file mode 100644
index 0000000000..35f165fbcb
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java
@@ -0,0 +1,42 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package com.jme3.renderer.framegraph;
+
+import java.util.ArrayList;
+
+/**
+ *
+ * @author JohnKkk
+ */
+public class FGBindingPass extends FGPass{
+ protected ArrayList binds;
+ protected FGBindingPass(String name){
+ this(name, new ArrayList());
+ }
+ protected FGBindingPass(String name, ArrayList binds){
+ super(name);
+ this.binds = binds;
+ }
+
+ public void addBind(FGBindable bind){
+ binds.add(bind);
+ }
+
+ public void addBindSink(String name){
+ int index = binds.size() - 1;
+ registerSink(new FGContainerBindableSink(name, binds, index));
+ }
+
+ public void bindAll(FGRenderContext renderContext){
+ // 绑定所有对象
+ for(FGBindable bind : binds){
+ bind.bind(renderContext);
+ }
+ }
+
+ @Override
+ public void execute(FGRenderContext renderContext) {
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGCallbackPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGCallbackPass.java
new file mode 100644
index 0000000000..86e79fede2
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGCallbackPass.java
@@ -0,0 +1,34 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package com.jme3.renderer.framegraph;
+
+/**
+ *
+ * @author JohnKkk
+ */
+public class FGCallbackPass extends FGBindingPass{
+ public static interface IFGCallbackInterface{
+ void callbackPass();
+ }
+ private IFGCallbackInterface iFGCallbackInterface;
+
+ private FGCallbackPass(String name, IFGCallbackInterface ifgci) {
+ super(name);
+ iFGCallbackInterface = ifgci;
+ }
+
+ @Override
+ public void execute(FGRenderContext renderContext) {
+ bindAll(renderContext);
+ if(iFGCallbackInterface != null){
+ iFGCallbackInterface.callbackPass();
+ }
+ }
+
+ public final static FGCallbackPass makePass(String passName, IFGCallbackInterface iFGCallbackInterface){
+ return new FGCallbackPass(passName, iFGCallbackInterface);
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGComputePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGComputePass.java
new file mode 100644
index 0000000000..1977529645
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGComputePass.java
@@ -0,0 +1,17 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package com.jme3.renderer.framegraph;
+
+/**
+ *
+ * @author JohnKkk
+ */
+public class FGComputePass extends FGBindingPass{
+
+ public FGComputePass(String name) {
+ super(name);
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java
new file mode 100644
index 0000000000..9987fb5cd7
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java
@@ -0,0 +1,75 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package com.jme3.renderer.framegraph;
+
+import java.util.ArrayList;
+
+/**
+ *
+ * @author JohnKkk
+ */
+public class FGContainerBindableSink extends FGSink{
+ protected boolean linked = false;
+ protected ArrayList container;
+ protected int index;
+ protected FGBindableProxy bindableProxy;
+
+ public final static class FGBindableProxy extends FGBindable{
+ public FGBindable targetBindable;
+
+ public FGBindableProxy(FGBindable targetBindable) {
+ this.targetBindable = targetBindable;
+ }
+
+ @Override
+ public void bind(FGRenderContext renderContext) {
+ if(targetBindable != null){
+ targetBindable.bind(renderContext);
+ }
+ }
+ }
+
+ public FGContainerBindableSink(String registeredName, ArrayList container, int index) {
+ super(registeredName);
+ this.container = container;
+ this.index = index;
+ bindableProxy = new FGBindableProxy(null);
+ if(index < this.container.size()){
+ this.container.set(index, bindableProxy);
+ }
+ else{
+ this.container.add(bindableProxy);
+ this.index = this.container.size() - 1;
+ }
+ }
+
+ @Override
+ public void bind(FGSource fgSource) {
+ T p = (T)fgSource.yieldBindable();
+ if(p == null){
+ System.err.println("Binding input [" + getRegisteredName() + "] to output [" + getLinkPassName() + "." + getLinkPassResName() + "] " + " { " + fgSource.getName() + " } ");
+ return;
+ }
+ bindableProxy.targetBindable = p;
+// container.set(index, p);
+ linked = true;
+ }
+
+ @Override
+ public void postLinkValidate() {
+ if(!linked){
+ if(bIsRequired)
+ System.err.println("Unlinked input: " + getRegisteredName());
+ }
+ else{
+ bLinkValidate = true;
+ }
+ }
+
+ @Override
+ public FGBindable getBind() {
+ return bindableProxy.targetBindable;
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java
new file mode 100644
index 0000000000..89dc6951ff
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java
@@ -0,0 +1,69 @@
+package com.jme3.renderer.framegraph;
+
+import com.jme3.texture.FrameBuffer;
+
+import java.util.ArrayList;
+
+/**
+ * @author JohnKkk
+ * @param
+ */
+public class FGFramebufferCopyBindableSink extends FGContainerBindableSink{
+ FramebufferCopyBindableProxy framebufferCopyBindableProxy;
+ public final void setDistFrameBuffer(FrameBuffer distFrameBuffer){
+ framebufferCopyBindableProxy.distFramebuffer = distFrameBuffer;
+ }
+ public FGFramebufferCopyBindableSink(String registeredName, FrameBuffer distFrameBuffer, boolean copyColor, boolean copyDepth, boolean copyStencil, ArrayList container, int index) {
+ super(registeredName, container, index);
+ framebufferCopyBindableProxy = new FramebufferCopyBindableProxy(distFrameBuffer, copyColor, copyDepth, copyStencil);
+ }
+
+ private final static class FramebufferCopyBindableProxy extends FGBindable{
+ FrameBuffer sourceFramebuffer;
+ FrameBuffer distFramebuffer;
+ boolean bCopyColor;
+ boolean bCopyDepth;
+ boolean bCopyStencil;
+
+ public FramebufferCopyBindableProxy(FrameBuffer distFramebuffer, boolean bCopyColor, boolean bCopyDepth, boolean bCopyStencil) {
+ this.distFramebuffer = distFramebuffer;
+ this.bCopyColor = bCopyColor;
+ this.bCopyDepth = bCopyDepth;
+ this.bCopyStencil = bCopyStencil;
+ }
+
+ public void setSourceFramebuffer(FrameBuffer sourceFramebuffer) {
+ this.sourceFramebuffer = sourceFramebuffer;
+ }
+
+ @Override
+ public void bind(FGRenderContext renderContext) {
+ if(this.distFramebuffer != null || this.sourceFramebuffer != null){
+ renderContext.renderManager.getRenderer().copyFrameBuffer(this.sourceFramebuffer, this.distFramebuffer != null ? this.distFramebuffer : renderContext.viewPort.getOutputFrameBuffer(), bCopyColor, bCopyDepth || bCopyStencil);
+ }
+ }
+ }
+
+ @Override
+ public void bind(FGSource fgSource) {
+ T p = (T)fgSource.yieldBindable();
+ if(p == null){
+ System.err.println("Binding input [" + getRegisteredName() + "] to output [" + getLinkPassName() + "." + getLinkPassResName() + "] " + " { " + fgSource.getName() + " } ");
+ return;
+ }
+ if(fgSource instanceof FGFramebufferSource){
+ linked = true;
+ FGFramebufferSource framebufferSource = (FGFramebufferSource)fgSource;
+ framebufferCopyBindableProxy.setSourceFramebuffer(((FGFramebufferSource.FrameBufferSourceProxy)framebufferSource.yieldBindable()).getFrameBuffer());
+ bindableProxy.targetBindable = framebufferCopyBindableProxy;
+ }
+ else{
+ System.err.println(getRegisteredName() + " needs a FGFramebufferSource");
+ }
+ }
+
+ @Override
+ public void postLinkValidate() {
+
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferSource.java
new file mode 100644
index 0000000000..ebac06934a
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferSource.java
@@ -0,0 +1,35 @@
+package com.jme3.renderer.framegraph;
+
+import com.jme3.texture.FrameBuffer;
+
+/**
+ * @author JohnKkk
+ */
+public class FGFramebufferSource extends FGSource{
+ private FrameBufferSourceProxy frameBufferSourceProxy;
+ public final static class FrameBufferSourceProxy extends FGBindable{
+ private FrameBuffer frameBuffer;
+
+ public FrameBufferSourceProxy(FrameBuffer frameBuffer) {
+ this.frameBuffer = frameBuffer;
+ }
+
+ public FrameBuffer getFrameBuffer() {
+ return frameBuffer;
+ }
+ }
+ public FGFramebufferSource(String name, FrameBuffer frameBuffer) {
+ super(name);
+ frameBufferSourceProxy = new FrameBufferSourceProxy(frameBuffer);
+ }
+
+ @Override
+ public void postLinkValidate() {
+
+ }
+
+ @Override
+ public FGBindable yieldBindable() {
+ return frameBufferSourceProxy;
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGGlobal.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGGlobal.java
new file mode 100644
index 0000000000..d1a11880dc
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGGlobal.java
@@ -0,0 +1,32 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package com.jme3.renderer.framegraph;
+
+import java.util.ArrayList;
+
+/**
+ *
+ * @author JohnKkk
+ */
+public class FGGlobal {
+ public final static String S_GLOABLE_PASS_SOURCE_NAME = "$";
+ public final static String S_SCENE_COLOR_FB = "sceneColorFramebuffer";
+ public final static String S_SCENE_COLOR_RT = "sceneColorRT";
+ public final static String S_SCENE_DEPTH_RT = "sceneDepthRT";
+ public final static String S_DEFAULT_FB = "defaultFramebuffer";
+ private final static ArrayList g_Sinks = new ArrayList<>();
+ private final static ArrayList g_Sources = new ArrayList<>();
+ public final static boolean linkSink(FGSink outSink){
+ boolean bound = false;
+ for(FGSource soucre : g_Sources){
+ if(soucre.getName().equals(outSink.getLinkPassResName())){
+ outSink.bind(soucre);
+ bound = true;
+ break;
+ }
+ }
+ return bound;
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
new file mode 100644
index 0000000000..08b12016f6
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
@@ -0,0 +1,113 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package com.jme3.renderer.framegraph;
+
+import java.util.ArrayList;
+
+/**
+ * FGPass.
+ * @author JohnKkk
+ */
+public abstract class FGPass {
+ private String name;
+ private ArrayList sinks;
+ private ArrayList sources;
+ protected boolean resetClearSinksAndSources = false;
+ public FGPass(String name){
+ this.name = name;
+ this.sinks = new ArrayList<>();
+ this.sources = new ArrayList<>();
+ }
+ public void prepare(FGRenderContext renderContext){}
+ public abstract void execute(FGRenderContext renderContext);
+
+ public String getName() {
+ return name;
+ }
+
+ public ArrayList getSinks() {
+ return sinks;
+ }
+
+ public ArrayList getSources() {
+ return sources;
+ }
+
+ public FGSource getSource(String name){
+ for(FGSource src : sources){
+ if(src.getName().equals(name)){
+ return src;
+ }
+ }
+
+ System.err.println("Output name [" + name + "] not fount in pass:" + getName());
+ return null;
+ }
+
+ public FGSink getSink(String registeredName){
+ for(FGSink sink : sinks){
+ if(sink.getRegisteredName().equals(registeredName)){
+ return sink;
+ }
+ }
+ return null;
+ }
+
+ public void setSinkLinkage(String registeredName, String target){
+ FGSink sink = getSink(registeredName);
+
+ String targetSplit[] = target.split("\\.");
+ if(targetSplit.length != 2){
+ System.err.println("Input target has incorrect format");
+ }
+ sink.setTarget(targetSplit[0], targetSplit[1]);
+ }
+
+ protected void registerSink(FGSink sink){
+ // check for overlap of input names
+ for(FGSink si : sinks){
+ if(si.getRegisteredName().equals(sink.getRegisteredName())){
+ System.err.println("Registered input overlaps with existing: " + sink.getRegisteredName());
+ return;
+ }
+ }
+
+ sinks.add(sink);
+ }
+
+ public void registerSource(FGSource source){
+ // check for overlap of output names
+ for(FGSource src : sources){
+ if(src.getName().equals(source.getName())){
+ System.err.println("Registered input overlaps with existing: " + source.getName());
+ return;
+ }
+ }
+
+ sources.add(source);
+ }
+
+ public void reset(){
+ if(resetClearSinksAndSources){
+ this.sources.clear();
+ this.sinks.clear();
+ }
+ }
+
+ public void finalize(){
+ if(sinks != null && sinks.size() > 0){
+ for(FGSink sink : sinks){
+ sink.postLinkValidate();
+ }
+ }
+
+ if(sources != null && sources.size() > 0){
+ for(FGSource src : sources){
+ src.postLinkValidate();
+ }
+ }
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java
new file mode 100644
index 0000000000..6bc35a3891
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java
@@ -0,0 +1,37 @@
+package com.jme3.renderer.framegraph;
+
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.RenderQueue;
+
+/**
+ * @author JohnKkk
+ */
+public class FGRenderContext {
+ // PSO
+ public static class FGPipelineObjectState{
+ public float startDepth;
+ public float endDepth;
+ }
+
+ public RenderManager renderManager;
+ public RenderQueue renderQueue;
+ public ViewPort viewPort;
+ protected FGPipelineObjectState currentPSO;
+
+ public FGRenderContext(RenderManager renderManager, RenderQueue renderQueue, ViewPort viewPort) {
+ this.renderManager = renderManager;
+ this.renderQueue = renderQueue;
+ this.viewPort = viewPort;
+ currentPSO = new FGPipelineObjectState();
+ currentPSO.startDepth = 0;
+ currentPSO.endDepth = 1;
+ }
+ public final void setDepthRange(float start, float end){
+ if(currentPSO.startDepth != start || currentPSO.endDepth != end){
+ renderManager.getRenderer().setDepthRange(start, end);
+ currentPSO.startDepth = start;
+ currentPSO.endDepth = end;
+ }
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java
new file mode 100644
index 0000000000..1504c01d7d
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java
@@ -0,0 +1,64 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package com.jme3.renderer.framegraph;
+
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.GeometryList;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.renderer.renderPass.IRenderGeometry;
+
+/**
+ * All passes that need to perform rendering must inherit from this class.
+ * @author JohnKkk
+ */
+public abstract class FGRenderQueuePass extends FGBindingPass implements IRenderGeometry {
+ protected ViewPort forceViewPort;
+ // It is just geometry data for now. If we extend the RHI interface in the future, it may be adjusted to MeshDrawCommand.
+ protected GeometryList passMeshDrawCommandList;
+ protected boolean canExecute;
+
+ public FGRenderQueuePass(String name) {
+ super(name);
+ }
+
+ public void setForceViewPort(ViewPort forceViewPort) {
+ this.forceViewPort = forceViewPort;
+ }
+
+ /**
+ * Dispatch visible mesh draw commands to process task, to prepare for this pass.
+ * @param renderQueue
+ */
+ public abstract void dispatchPassSetup(RenderQueue renderQueue);
+
+ @Override
+ public void execute(FGRenderContext renderContext) {
+ renderContext.renderManager.setRenderGeometryHandler(this);
+ dispatchPassSetup(renderContext.renderQueue);
+ if(!canExecute){
+ renderContext.renderManager.setRenderGeometryHandler(null);
+ return;
+ }
+ bindAll(renderContext);
+
+ // todo:Use the default queue temporarily to avoid creating a temporary copy
+ if(passMeshDrawCommandList != null && passMeshDrawCommandList.size() > 0){
+ // drawcall
+ }
+ executeDrawCommandList(renderContext);
+ renderContext.renderManager.setRenderGeometryHandler(null);
+ }
+ public abstract void executeDrawCommandList(FGRenderContext renderContext);
+
+ @Override
+ public void reset() {
+ super.reset();
+ if(passMeshDrawCommandList != null && passMeshDrawCommandList.size() > 0){
+ passMeshDrawCommandList.clear();
+ }
+ }
+
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderTargetSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderTargetSource.java
new file mode 100644
index 0000000000..6212e4b6f6
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderTargetSource.java
@@ -0,0 +1,45 @@
+package com.jme3.renderer.framegraph;
+
+import com.jme3.texture.FrameBuffer;
+import com.jme3.texture.Texture;
+
+public class FGRenderTargetSource extends FGSource{
+ RenderTargetSourceProxy renderTargetSourceProxy;
+ public final static class RenderTargetSourceProxy extends FGBindable{
+ FrameBuffer.FrameBufferTextureTarget renderTarget;
+
+ public RenderTargetSourceProxy(FrameBuffer.FrameBufferTextureTarget renderTarget) {
+ this.renderTarget = renderTarget;
+ }
+
+ /**
+ * return RT.
+ * @return
+ */
+ public FrameBuffer.FrameBufferTextureTarget getRenderTarget() {
+ return renderTarget;
+ }
+
+ /**
+ * return RT shaderResource.
+ * @return
+ */
+ public Texture getShaderResource(){
+ return renderTarget.getTexture();
+ }
+ }
+ public FGRenderTargetSource(String name, FrameBuffer.FrameBufferTextureTarget renderTarget) {
+ super(name);
+ renderTargetSourceProxy = new RenderTargetSourceProxy(renderTarget);
+ }
+
+ @Override
+ public void postLinkValidate() {
+
+ }
+
+ @Override
+ public FGBindable yieldBindable() {
+ return renderTargetSourceProxy;
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSink.java
new file mode 100644
index 0000000000..27a8879b5f
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSink.java
@@ -0,0 +1,49 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package com.jme3.renderer.framegraph;
+
+/**
+ *
+ * @author JohnKkk
+ */
+public abstract class FGSink {
+ private String registeredName;
+ private String linkPassName;
+ private String linkPassResName;
+ protected boolean bIsRequired = false;
+ // Always validate?
+ protected boolean bLinkValidate = false;
+ protected FGSink(String registeredName){
+ this.registeredName = registeredName;
+ }
+
+ public boolean isRequired() {
+ return bIsRequired;
+ }
+
+ public String getRegisteredName() {
+ return registeredName;
+ }
+
+ public String getLinkPassName() {
+ return linkPassName;
+ }
+
+ public String getLinkPassResName() {
+ return linkPassResName;
+ }
+
+ public void setTarget(String inPassName, String inPassResName){
+ linkPassName = inPassName;
+ linkPassResName = inPassResName;
+ }
+ public abstract void bind(FGSource fgSource);
+ public abstract void postLinkValidate();
+
+ public boolean isLinkValidate() {
+ return bLinkValidate;
+ }
+ public FGBindable getBind(){return null;}
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSource.java
new file mode 100644
index 0000000000..370cd92d8a
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSource.java
@@ -0,0 +1,22 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package com.jme3.renderer.framegraph;
+
+/**
+ *
+ * @author JohnKkk
+ */
+public abstract class FGSource {
+ private String name;
+ public FGSource(String name){
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ public abstract void postLinkValidate();
+ public abstract FGBindable yieldBindable();
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java
new file mode 100644
index 0000000000..45f71597d8
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java
@@ -0,0 +1,58 @@
+package com.jme3.renderer.framegraph;
+
+import com.jme3.material.Material;
+import com.jme3.shader.VarType;
+
+import java.util.ArrayList;
+
+public class FGTextureBindableSink extends FGContainerBindableSink{
+ private Material material;
+ private TextureBindableProxy textureBindableProxy;
+ private static class TextureBindableProxy extends FGBindable{
+ Material material;
+ VarType bindTextureType;
+ Object bindValue;
+ String bindName;
+
+ public TextureBindableProxy(Material material, String bindName, VarType bindTextureType) {
+ // check bindTextureType
+ this.bindTextureType = bindTextureType;
+ this.material = material;
+ this.bindName = bindName;
+ }
+ public final void setValue(Object value){
+ bindValue = value;
+ }
+
+ @Override
+ public void bind(FGRenderContext renderContext) {
+ super.bind(renderContext);
+ if(material != null && bindName != null){
+ this.material.setParam(bindName, bindTextureType, bindValue);
+ }
+ }
+ }
+ public FGTextureBindableSink(String registeredName, ArrayList container, int index, Material material, VarType bindTextureType) {
+ super(registeredName, container, index);
+ this.material = material;
+ textureBindableProxy = new TextureBindableProxy(material, registeredName, bindTextureType);
+ }
+
+ @Override
+ public void bind(FGSource fgSource) {
+ T p = (T)fgSource.yieldBindable();
+ if(p == null){
+ System.err.println("Binding input [" + getRegisteredName() + "] to output [" + getLinkPassName() + "." + getLinkPassResName() + "] " + " { " + fgSource.getName() + " } ");
+ return;
+ }
+ if(fgSource instanceof FGRenderTargetSource){
+ linked = true;
+ FGRenderTargetSource renderTargetSource = (FGRenderTargetSource)fgSource;
+ textureBindableProxy.setValue(((FGRenderTargetSource.RenderTargetSourceProxy)renderTargetSource.yieldBindable()).getShaderResource());
+ bindableProxy.targetBindable = textureBindableProxy;
+ }
+ else{
+ System.err.println(getRegisteredName() + " needs a FGRenderTargetSource");
+ }
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarBindableSink.java
new file mode 100644
index 0000000000..68207df98c
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarBindableSink.java
@@ -0,0 +1,18 @@
+package com.jme3.renderer.framegraph;
+
+import java.util.ArrayList;
+
+/**
+ * @author JohnKkk
+ * @param
+ */
+public class FGVarBindableSink extends FGContainerBindableSink{
+ public FGVarBindableSink(String registeredName, ArrayList container, int index) {
+ super(registeredName, container, index);
+ }
+
+ @Override
+ public void bind(FGSource fgSource) {
+ super.bind(fgSource);
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java
new file mode 100644
index 0000000000..97fb197457
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java
@@ -0,0 +1,34 @@
+package com.jme3.renderer.framegraph;
+
+/**
+ * @author JohnKkk
+ * @param
+ */
+public class FGVarSource extends FGSource{
+ public static class FGVarBindableProxy extends FGBindable{
+ T value;
+
+ public FGVarBindableProxy(T value) {
+ this.value = value;
+ }
+
+ public T getValue() {
+ return value;
+ }
+ }
+ private FGVarBindableProxy varBindableProxy;
+ public FGVarSource(String name, T value) {
+ super(name);
+ varBindableProxy = new FGVarBindableProxy(value);
+ }
+
+ @Override
+ public void postLinkValidate() {
+
+ }
+
+ @Override
+ public FGBindable yieldBindable() {
+ return varBindableProxy;
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
new file mode 100644
index 0000000000..c50a5354ab
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
@@ -0,0 +1,175 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package com.jme3.renderer.framegraph;
+
+import java.util.ArrayList;
+
+/**
+ * @see https://www.gdcvault.com/play/1024612/FrameGraph-Extensible-Rendering-Architecture-in.
+ * @author JohnKkk
+ */
+public class FrameGraph {
+ private ArrayList passes;
+ private ArrayList globalSources;
+ private ArrayList globalSinks;
+ private boolean finalized = false;
+ private FGRenderContext renderContext;
+
+ public FrameGraph(FGRenderContext renderContext){
+ passes = new ArrayList();
+ globalSinks = new ArrayList();
+ globalSources = new ArrayList();
+ this.renderContext = renderContext;
+ }
+
+ public FGRenderContext getRenderContext() {
+ return renderContext;
+ }
+
+ protected void linkGlobalSinks(){
+ for(FGSink sink : globalSinks){
+ String linkPassName = sink.getLinkPassName();
+ for(FGPass nextPass : passes){
+ if(nextPass.getName().equals(linkPassName)){
+ FGSource source = nextPass.getSource(sink.getLinkPassResName());
+ sink.bind(source);
+ break;
+ }
+ }
+ }
+ }
+
+ protected void linkSinks(FGPass pass){
+ for(FGSink sink : pass.getSinks()){
+ String linkPassName = sink.getLinkPassName();
+
+ if((linkPassName == null || linkPassName.isEmpty())){
+ if(sink.isRequired()){
+ System.err.println("In pass named [" + pass.getName() + "] sink named [" + sink.getRegisteredName() + "] has no target source set.");
+ return;
+ }
+ else{
+ continue;
+ }
+ }
+
+ // check check whether target source is global
+ if(linkPassName.equals(FGGlobal.S_GLOABLE_PASS_SOURCE_NAME)){
+ boolean bound = false;
+ for(FGSource source : globalSources){
+ if(source.getName().equals(sink.getLinkPassResName())){
+ sink.bind(source);
+ bound = true;
+ break;
+ }
+ }
+ if(!bound){
+ bound = FGGlobal.linkSink(sink);
+ if(!bound && sink.isRequired()){
+ System.err.println("Pass named [" + linkPassName + "] not found");
+ return;
+ }
+ }
+ }
+ else{
+ // find source from within existing passes
+ boolean bound = false;
+ for(FGPass nextPass : passes){
+ if(nextPass.getName().equals(linkPassName)){
+ FGSource source = nextPass.getSource(sink.getLinkPassResName());
+ sink.bind(source);
+ bound = true;
+ break;
+ }
+ }
+ if(!bound){
+ bound = FGGlobal.linkSink(sink);
+ if(!bound && sink.isRequired()){
+ System.err.println("Pass named [" + linkPassName + "] not found");
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ public void execute(){
+ assert finalized;
+ for(FGPass nextPass : passes){
+ nextPass.execute(renderContext);
+ }
+ }
+
+ public void reset(){
+ assert finalized;
+ for(FGPass nextPass : passes){
+ nextPass.reset();
+ }
+ passes.clear();
+ if(renderContext != null && renderContext.renderManager != null){
+ renderContext.renderManager.setRenderGeometryHandler(null);
+ }
+ }
+
+ public void addGlobalSource(FGSource source){
+ globalSources.add(source);
+ }
+
+ public void replaceOrAddGlobalSource(FGSource source){
+ int index = -1;
+ for(int i = 0;i < globalSources.size();i++){
+ if(globalSources.get(i).getName().equals(source.getName())){
+ index = i;
+ break;
+ }
+ }
+ if(index >= 0){
+ globalSources.remove(index);
+ }
+ globalSources.add(source);
+ }
+
+ public void addGlobalSink(FGSink sink){
+ globalSinks.add(sink);
+ }
+
+ public final void addPass(FGPass pass){
+ assert !finalized;
+ // validate name uniqueness
+ for(FGPass nextPass : passes){
+ if(nextPass.getName().equals(pass.getName())){
+ System.err.println("Pass name already exists: " + pass.getName());
+ return;
+ }
+ }
+
+ // link outputs from passes (and global outputs) to pass inputs
+ if(pass.getSinks() != null && pass.getSinks().size() > 0)
+ linkSinks(pass);
+
+ // add to container of passes
+ pass.prepare(renderContext);
+ passes.add(pass);
+ }
+
+ public final FGPass findPassByName(String name){
+ for(FGPass nextPass : passes){
+ if(nextPass.getName().equals(name)){
+ return nextPass;
+ }
+ }
+ System.err.println("Failed to find pass name");
+ return null;
+ }
+
+ public final void finalize(){
+ assert !finalized;
+ for(FGPass nextPass : passes){
+ nextPass.finalize();
+ }
+ linkGlobalSinks();
+ finalized = true;
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java b/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java
index e95463f14e..1952629d60 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java
@@ -34,13 +34,14 @@
import com.jme3.post.SceneProcessor;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.renderPass.IRenderGeometry;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
/**
- * RenderQueue is used to queue up and sort
+ * RenderQueue is used to queue up and sort
* {@link Geometry geometries} for rendering.
- *
+ *
* @author Kirill Vainer
*/
public class RenderQueue {
@@ -50,12 +51,14 @@ public class RenderQueue {
private GeometryList transparentList;
private GeometryList translucentList;
private GeometryList skyList;
+ private GeometryList tempList;
/**
* Creates a new RenderQueue, the default {@link GeometryComparator comparators}
* are used for all {@link GeometryList geometry lists}.
*/
public RenderQueue() {
+ this.tempList = new GeometryList(new NullComparator());
this.opaqueList = new GeometryList(new OpaqueComparator());
this.guiList = new GeometryList(new GuiComparator());
this.transparentList = new GeometryList(new TransparentComparator());
@@ -65,49 +68,49 @@ public RenderQueue() {
/**
* The render queue Bucket specifies the bucket
- * to which the spatial will be placed when rendered.
+ * to which the spatial will be placed when rendered.
*
- * The behavior of the rendering will differ depending on which
+ * The behavior of the rendering will differ depending on which
* bucket the spatial is placed. A spatial's queue bucket can be set
* via {@link Spatial#setQueueBucket(com.jme3.renderer.queue.RenderQueue.Bucket) }.
*/
public enum Bucket {
/**
- * The renderer will try to find the optimal order for rendering all
+ * The renderer will try to find the optimal order for rendering all
* objects using this mode.
* You should use this mode for most normal objects, except transparent
* ones, as it could give a nice performance boost to your application.
*/
Opaque,
-
+
/**
* This is the mode you should use for object with
* transparency in them. It will ensure the objects furthest away are
* rendered first. That ensures when another transparent object is drawn on
* top of previously drawn objects, you can see those (and the object drawn
* using Opaque) through the transparent parts of the newly drawn
- * object.
+ * object.
*/
Transparent,
-
+
/**
- * A special mode used for rendering really far away, flat objects -
- * e.g. skies. In this mode, the depth is set to infinity so
+ * A special mode used for rendering really far away, flat objects -
+ * e.g. skies. In this mode, the depth is set to infinity so
* spatials in this bucket will appear behind everything, the downside
* to this bucket is that 3D objects will not be rendered correctly
* due to lack of depth testing.
*/
Sky,
-
+
/**
* A special mode used for rendering transparent objects that
- * should not be affected by {@link SceneProcessor}.
+ * should not be affected by {@link SceneProcessor}.
* Generally this would contain translucent objects, and
* also objects that do not write to the depth buffer such as
* particle emitters.
*/
Translucent,
-
+
/**
* This is a special mode, for drawing 2D object
* without perspective (such as GUI or HUD parts).
@@ -117,7 +120,7 @@ public enum Bucket {
* outside of that range are culled.
*/
Gui,
-
+
/**
* A special mode, that will ensure that this spatial uses the same
* mode as the parent Node does.
@@ -135,22 +138,22 @@ public enum ShadowMode {
* Generally used for special effects like particle emitters.
*/
Off,
-
+
/**
- * Enable casting of shadows but not receiving them.
+ * Enable casting of shadows but not receiving them.
*/
Cast,
-
+
/**
* Enable receiving of shadows but not casting them.
*/
Receive,
-
+
/**
* Enable both receiving and casting of shadows.
*/
CastAndReceive,
-
+
/**
* Inherit the ShadowMode from the parent node.
*/
@@ -237,9 +240,9 @@ public GeometryComparator getGeometryComparator(Bucket bucket) {
* The {@link RenderManager} automatically handles this task
* when flattening the scene graph. The bucket to add
* the geometry is determined by {@link Geometry#getQueueBucket() }.
- *
+ *
* @param g The geometry to add
- * @param bucket The bucket to add to, usually
+ * @param bucket The bucket to add to, usually
* {@link Geometry#getQueueBucket() }.
*/
public void addToQueue(Geometry g, Bucket bucket) {
@@ -265,16 +268,43 @@ public void addToQueue(Geometry g, Bucket bucket) {
}
private void renderGeometryList(GeometryList list, RenderManager rm, Camera cam, boolean clear) {
- list.setCamera(cam); // select camera for sorting
- list.sort();
- for (int i = 0; i < list.size(); i++) {
- Geometry obj = list.get(i);
- assert obj != null;
- rm.renderGeometry(obj);
- obj.queueDistance = Float.NEGATIVE_INFINITY;
+ IRenderGeometry renderGeometryHandler = rm.getRenderGeometryHandler();
+ if(renderGeometryHandler != null){
+ list.setCamera(cam); // select camera for sorting
+ list.sort();
+ tempList.clear();
+ for (int i = 0; i < list.size(); i++) {
+ Geometry obj = list.get(i);
+ assert obj != null;
+ // Check if it is actually rendered
+ if(!renderGeometryHandler.drawGeometry(rm, obj)){
+ tempList.add(obj);
+ }
+ obj.queueDistance = Float.NEGATIVE_INFINITY;
+ }
+ if (clear) {
+ list.clear();
+ // BEGIN-JME3@JohnKkk以便进行后续RendererPath渲染
+ if(tempList.size() > 0){
+ for(int i = 0;i < tempList.size();i++){
+ list.add(tempList.get(i));
+ }
+ }
+ // END-JME3
+ }
}
- if (clear) {
- list.clear();
+ else{
+ list.setCamera(cam); // select camera for sorting
+ list.sort();
+ for (int i = 0; i < list.size(); i++) {
+ Geometry obj = list.get(i);
+ assert obj != null;
+ rm.renderGeometry(obj);
+ obj.queueDistance = Float.NEGATIVE_INFINITY;
+ }
+ if (clear) {
+ list.clear();
+ }
}
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSink.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSink.java
new file mode 100644
index 0000000000..26fa54ad5d
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSink.java
@@ -0,0 +1,17 @@
+package com.jme3.renderer.renderPass;
+
+import com.jme3.renderer.framegraph.FGBindable;
+import com.jme3.renderer.framegraph.FGContainerBindableSink;
+
+import java.util.ArrayList;
+
+public class DeferredLightDataSink extends FGContainerBindableSink {
+ public DeferredLightDataSink(String registeredName, ArrayList container, int index) {
+ super(registeredName, container, index);
+ }
+
+ @Override
+ public void postLinkValidate() {
+ bLinkValidate = bindableProxy.targetBindable != null;
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSource.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSource.java
new file mode 100644
index 0000000000..b932087d63
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSource.java
@@ -0,0 +1,36 @@
+package com.jme3.renderer.renderPass;
+
+import com.jme3.light.LightList;
+import com.jme3.renderer.framegraph.FGBindable;
+import com.jme3.renderer.framegraph.FGSource;
+
+public class DeferredLightDataSource extends FGSource {
+ DeferredLightDataProxy deferredLightDataProxy;
+ public DeferredLightDataSource(String name, LightList lightData) {
+ super(name);
+ deferredLightDataProxy = new DeferredLightDataProxy(lightData);
+ }
+
+ @Override
+ public void postLinkValidate() {
+
+ }
+
+ @Override
+ public FGBindable yieldBindable() {
+ return deferredLightDataProxy;
+ }
+
+ public static class DeferredLightDataProxy extends FGBindable {
+ private LightList lightData;
+
+ public DeferredLightDataProxy(LightList lightData) {
+ this.lightData = lightData;
+ }
+
+ public LightList getLightData() {
+ return lightData;
+ }
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredShadingPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredShadingPass.java
new file mode 100644
index 0000000000..bb8f157817
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredShadingPass.java
@@ -0,0 +1,98 @@
+package com.jme3.renderer.renderPass;
+
+import com.jme3.light.LightList;
+import com.jme3.material.Material;
+import com.jme3.material.MaterialDef;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.framegraph.*;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Geometry;
+import com.jme3.shader.VarType;
+import com.jme3.ui.Picture;
+
+/**
+ * @author JohnKkk
+ */
+public class DeferredShadingPass extends ScreenPass{
+ public final static String S_RT_0 = "Context_InGBuff0";
+ public final static String S_RT_1 = "Context_InGBuff1";
+ public final static String S_RT_2 = "Context_InGBuff2";
+ public final static String S_RT_3 = "Context_InGBuff3";
+ public final static String S_RT_4 = "Context_InGBuff4";
+ public final static String S_LIGHT_DATA = "LIGHT_DATA";
+ public final static String S_EXECUTE_STATE = "EXECUTE_STATE";
+ protected final static String _S_DEFERRED_PASS = "DeferredPass";
+ private static final String _S_DEFERRED_SHADING_PASS_MAT_DEF = "Common/MatDefs/ShadingCommon/DeferredShading.j3md";
+ public DeferredShadingPass(){
+ this("DeferredShadingPass");
+ }
+ public DeferredShadingPass(String name) {
+ super(name, RenderQueue.Bucket.Opaque);
+ }
+
+ @Override
+ public void prepare(FGRenderContext renderContext) {
+ super.prepare(renderContext);
+ ViewPort vp = renderContext.viewPort;
+ if(forceViewPort != null){
+ vp = forceViewPort;
+ }
+ ((FGFramebufferCopyBindableSink)getSink(FGGlobal.S_DEFAULT_FB)).setDistFrameBuffer(vp.getOutputFrameBuffer());
+ }
+
+ protected Material getMaterial(){
+ MaterialDef def = (MaterialDef) assetManager.loadAsset(_S_DEFERRED_SHADING_PASS_MAT_DEF);
+ screenMat = new Material(def);
+ return screenMat;
+ }
+
+ @Override
+ public void init() {
+
+ screenRect = new Picture(getName() + "_rect");
+ screenRect.setWidth(1);
+ screenRect.setHeight(1);
+ screenRect.setMaterial(getMaterial());
+
+ // register Sinks
+ registerSink(new FGTextureBindableSink(S_RT_0, binds, binds.size(), screenMat, VarType.Texture2D));
+ registerSink(new FGTextureBindableSink(S_RT_1, binds, binds.size(), screenMat, VarType.Texture2D));
+ registerSink(new FGTextureBindableSink(S_RT_2, binds, binds.size(), screenMat, VarType.Texture2D));
+ registerSink(new FGTextureBindableSink(S_RT_3, binds, binds.size(), screenMat, VarType.Texture2D));
+ registerSink(new FGTextureBindableSink(S_RT_4, binds, binds.size(), screenMat, VarType.Texture2D));
+ registerSink(new DeferredLightDataSink(S_LIGHT_DATA, binds, binds.size()));
+ registerSink(new FGVarBindableSink(S_EXECUTE_STATE, binds, binds.size()));
+ registerSink(new FGFramebufferCopyBindableSink(FGGlobal.S_DEFAULT_FB, null, false, true, true, binds, binds.size()));
+ }
+
+ @Override
+ public void executeDrawCommandList(FGRenderContext renderContext) {
+ screenMat.selectTechnique(_S_DEFERRED_PASS, renderContext.renderManager);
+ DeferredLightDataSink deferredLightDataSink = (DeferredLightDataSink) getSink(S_LIGHT_DATA);
+ DeferredLightDataSource.DeferredLightDataProxy deferredLightDataProxy = (DeferredLightDataSource.DeferredLightDataProxy) deferredLightDataSink.getBind();
+ LightList lights = deferredLightDataProxy.getLightData();
+ boolean depthWrite = screenMat.getAdditionalRenderState().isDepthWrite();
+ boolean depthTest = screenMat.getAdditionalRenderState().isDepthTest();
+ screenMat.getAdditionalRenderState().setDepthWrite(false);
+ screenMat.getAdditionalRenderState().setDepthTest(false);
+ screenMat.setBoolean("UseLightsCullMode", false);
+ screenRect.updateGeometricState();
+ screenMat.render(screenRect, lights, renderContext.renderManager);
+ screenMat.getAdditionalRenderState().setDepthWrite(depthWrite);
+ screenMat.getAdditionalRenderState().setDepthTest(depthTest);
+ }
+
+ @Override
+ public void dispatchPassSetup(RenderQueue renderQueue) {
+ boolean executeState = getSink(S_EXECUTE_STATE).isLinkValidate() && ((FGVarSource.FGVarBindableProxy)getSink(S_EXECUTE_STATE).getBind()).getValue() == Boolean.TRUE;
+ boolean hasLightData = getSink(S_LIGHT_DATA).isLinkValidate() && ((DeferredLightDataSource.DeferredLightDataProxy)((DeferredLightDataSink) getSink(S_LIGHT_DATA)).getBind()).getLightData().size() > 0;
+ canExecute = hasLightData || executeState;
+ }
+
+ @Override
+ public boolean drawGeometry(RenderManager rm, Geometry geom) {
+ // 不处理任何队列中的绘制
+ return true;
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/ForwardPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/ForwardPass.java
new file mode 100644
index 0000000000..f34c41ae29
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/ForwardPass.java
@@ -0,0 +1,44 @@
+package com.jme3.renderer.renderPass;
+
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.framegraph.FGRenderContext;
+import com.jme3.renderer.framegraph.FGRenderQueuePass;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Geometry;
+
+/**
+ * @author JohnKkk
+ */
+public class ForwardPass extends FGRenderQueuePass {
+ private RenderQueue.Bucket bucket;
+ public ForwardPass(String name, RenderQueue.Bucket bucket) {
+ super(name);
+ this.bucket = bucket;
+ }
+
+ @Override
+ public void executeDrawCommandList(FGRenderContext renderContext) {
+ if(!canExecute)return;
+ Camera cam = null;
+ if(forceViewPort != null){
+ cam = forceViewPort.getCamera();
+ }
+ else{
+ cam = renderContext.viewPort.getCamera();
+ }
+ RenderManager rm = renderContext.renderManager;
+ renderContext.renderQueue.renderQueue(this.bucket, rm, cam, true);
+ }
+
+ @Override
+ public void dispatchPassSetup(RenderQueue renderQueue) {
+ canExecute = !renderQueue.isQueueEmpty(this.bucket);
+ }
+
+ @Override
+ public boolean drawGeometry(RenderManager rm, Geometry geom) {
+ rm.renderGeometry(geom);
+ return true;
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java
new file mode 100644
index 0000000000..3fb84efae1
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java
@@ -0,0 +1,184 @@
+package com.jme3.renderer.renderPass;
+
+import com.jme3.light.Light;
+import com.jme3.light.LightList;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.framegraph.FGFramebufferSource;
+import com.jme3.renderer.framegraph.FGRenderContext;
+import com.jme3.renderer.framegraph.FGRenderTargetSource;
+import com.jme3.renderer.framegraph.FGVarSource;
+import com.jme3.scene.Geometry;
+import com.jme3.texture.FrameBuffer;
+import com.jme3.texture.Image;
+import com.jme3.texture.Texture2D;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author JohnKkk
+ */
+public class GBufferPass extends OpaquePass{
+ private final static String S_GBUFFER_PASS = "GBufferPass";
+ public final static String S_RT_0 = "RT_0";
+ public final static String S_RT_1 = "RT_1";
+ public final static String S_RT_2 = "RT_2";
+ public final static String S_RT_3 = "RT_3";
+ public final static String S_RT_4 = "RT_4";
+ public final static String S_FB = "GBufferFramebuffer";
+ public final static String S_LIGHT_DATA = "LIGHT_DATA";
+ public final static String S_EXECUTE_STATE = "EXECUTE_STATE";
+ private final LightList lightData = new LightList(null);
+ private final List tempLights = new ArrayList();
+ private boolean bHasDraw;
+ // gBuffer
+ private FrameBuffer gBuffer;
+ private Texture2D gBufferData0 = null;
+ private Texture2D gBufferData1 = null;
+ private Texture2D gBufferData2 = null;
+ private Texture2D gBufferData3 = null;
+ private Texture2D gBufferData4 = null;
+ private ColorRGBA gBufferMask = new ColorRGBA(0, 0, 0, 0);
+ private int frameBufferWidth, frameBufferHeight;
+
+ public GBufferPass() {
+ super("GBufferPass");
+ }
+
+ @Override
+ public void executeDrawCommandList(FGRenderContext renderContext) {
+ if(canExecute){
+ bHasDraw = false;
+ tempLights.clear();
+ lightData.clear();
+ ViewPort vp = null;
+ if(forceViewPort != null){
+ vp = forceViewPort;
+ }
+ else{
+ vp = renderContext.viewPort;
+ }
+ reshape(renderContext.renderManager.getRenderer(), vp, vp.getCamera().getWidth(), vp.getCamera().getHeight());
+ FrameBuffer opfb = vp.getOutputFrameBuffer();
+ vp.setOutputFrameBuffer(gBuffer);
+ ColorRGBA opClearColor = vp.getBackgroundColor();
+ gBufferMask.set(opClearColor);
+ gBufferMask.a = 0.0f;
+ renderContext.renderManager.getRenderer().setFrameBuffer(gBuffer);
+ renderContext.renderManager.getRenderer().setBackgroundColor(gBufferMask);
+ renderContext.renderManager.getRenderer().clearBuffers(vp.isClearColor(), vp.isClearDepth(), vp.isClearStencil());
+ String techOrig = renderContext.renderManager.getForcedTechnique();
+ renderContext.renderManager.setForcedTechnique(S_GBUFFER_PASS);
+ super.executeDrawCommandList(renderContext);
+ renderContext.renderManager.setForcedTechnique(techOrig);
+ vp.setOutputFrameBuffer(opfb);
+ renderContext.renderManager.getRenderer().setBackgroundColor(opClearColor);
+ renderContext.renderManager.getRenderer().setFrameBuffer(vp.getOutputFrameBuffer());
+ if(bHasDraw){
+ for(Light light : tempLights){
+ lightData.add(light);
+ }
+// renderContext.renderManager.getRenderer().copyFrameBuffer(gBuffer, vp.getOutputFrameBuffer(), false, true);
+ }
+ }
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ tempLights.clear();
+ lightData.clear();
+ }
+
+ public void reshape(Renderer renderer, ViewPort vp, int w, int h){
+ boolean recreate = false;
+ if(gBuffer != null){
+ if(frameBufferWidth != w || frameBufferHeight != h){
+ gBuffer.deleteObject(renderer);
+
+ frameBufferWidth = w;
+ frameBufferHeight = h;
+
+ recreate = true;
+ }
+ }
+ else{
+ recreate = true;
+ frameBufferWidth = w;
+ frameBufferHeight = h;
+ }
+
+ if(recreate){
+ // recreate
+ // To ensure accurate results, 32bit is used here for generalization.
+ gBufferData0 = new Texture2D(w, h, Image.Format.RGBA32F);
+ gBufferData1 = new Texture2D(w, h, Image.Format.RGBA32F);
+ gBufferData2 = new Texture2D(w, h, Image.Format.RGBA32F);
+ gBufferData3 = new Texture2D(w, h, Image.Format.RGBA32F); // The third buffer provides 32-bit floating point to store high-precision information, such as normals
+ // todo:后续调整为Depth24Stencil8,然后使用一个SceneColorFBO用于渲染所有3D部分,然后将其color_attach_0复制到BackBuffer中
+ // todo:然后开启DepthTest绘制最后的所有GUI
+ this.getSinks().clear();
+ // Depth16/Depth32/Depth32F provide higher precision to prevent clipping when camera gets close, but it seems some devices do not support copying Depth16/Depth32/Depth32F to default FrameBuffer.
+ gBufferData4 = new Texture2D(w, h, Image.Format.Depth);
+ gBuffer = new FrameBuffer(w, h, 1);
+ FrameBuffer.FrameBufferTextureTarget rt0 = FrameBuffer.FrameBufferTarget.newTarget(gBufferData0);
+ FrameBuffer.FrameBufferTextureTarget rt1 = FrameBuffer.FrameBufferTarget.newTarget(gBufferData1);
+ FrameBuffer.FrameBufferTextureTarget rt2 = FrameBuffer.FrameBufferTarget.newTarget(gBufferData2);
+ FrameBuffer.FrameBufferTextureTarget rt3 = FrameBuffer.FrameBufferTarget.newTarget(gBufferData3);
+ FrameBuffer.FrameBufferTextureTarget rt4 = FrameBuffer.FrameBufferTarget.newTarget(gBufferData4);
+ gBuffer.addColorTarget(rt0);
+ gBuffer.addColorTarget(rt1);
+ gBuffer.addColorTarget(rt2);
+ gBuffer.addColorTarget(rt3);
+ gBuffer.setDepthTarget(rt4);
+ gBuffer.setMultiTarget(true);
+ registerSource(new FGRenderTargetSource(S_RT_0, rt0));
+ registerSource(new FGRenderTargetSource(S_RT_1, rt1));
+ registerSource(new FGRenderTargetSource(S_RT_2, rt2));
+ registerSource(new FGRenderTargetSource(S_RT_3, rt3));
+ registerSource(new FGRenderTargetSource(S_RT_4, rt4));
+ registerSource(new DeferredLightDataSource(S_LIGHT_DATA, lightData));
+ registerSource(new FGVarSource(S_EXECUTE_STATE, bHasDraw));
+ registerSource(new FGFramebufferSource(S_FB, gBuffer));
+ }
+ }
+
+ @Override
+ public boolean drawGeometry(RenderManager rm, Geometry geom) {
+ Material material = geom.getMaterial();
+ if(material.getMaterialDef().getTechniqueDefs(rm.getForcedTechnique()) == null)return false;
+ rm.renderGeometry(geom);
+ if(material.getActiveTechnique() != null){
+ // todo:应该使用一个统一的材质材质,其中根据shadingModeId分开着色
+ if(material.getMaterialDef().getTechniqueDefs(S_GBUFFER_PASS) != null){
+ LightList lights = geom.getFilterWorldLights();
+ for(Light light : lights){
+ if(!tempLights.contains(light)){
+ tempLights.add(light);
+ }
+ }
+ // todo:无论是否拥有lights,只要包含GBufferPass的材质物体都会执行DeferredShading,根据shadingModelId着色
+ bHasDraw = true;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void prepare(FGRenderContext renderContext) {
+ super.prepare(renderContext);
+ ViewPort vp = null;
+ if(forceViewPort != null){
+ vp = forceViewPort;
+ }
+ else{
+ vp = renderContext.viewPort;
+ }
+ reshape(renderContext.renderManager.getRenderer(), vp, vp.getCamera().getWidth(), vp.getCamera().getHeight());
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/GuiPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/GuiPass.java
new file mode 100644
index 0000000000..01c3a35734
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/GuiPass.java
@@ -0,0 +1,33 @@
+package com.jme3.renderer.renderPass;
+
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.framegraph.FGRenderContext;
+import com.jme3.renderer.queue.RenderQueue;
+
+/**
+ * @author JohnKkk
+ */
+public class GuiPass extends ForwardPass{
+ @Override
+ public void executeDrawCommandList(FGRenderContext renderContext) {
+ Camera cam = null;
+ if(forceViewPort != null){
+ cam = forceViewPort.getCamera();
+ }
+ else{
+ cam = renderContext.viewPort.getCamera();
+ }
+ if(canExecute){
+ renderContext.setDepthRange(0, 0);
+ renderContext.renderManager.setCamera(cam, true);
+ }
+ super.executeDrawCommandList(renderContext);
+ if(canExecute){
+ renderContext.renderManager.setCamera(cam, false);
+ }
+ }
+
+ public GuiPass() {
+ super("GUIPass", RenderQueue.Bucket.Gui);
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/IRenderGeometry.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/IRenderGeometry.java
new file mode 100644
index 0000000000..d3de38c7c7
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/IRenderGeometry.java
@@ -0,0 +1,17 @@
+package com.jme3.renderer.renderPass;
+
+import com.jme3.renderer.RenderManager;
+import com.jme3.scene.Geometry;
+
+/**
+ * @author JohnKkk
+ */
+public interface IRenderGeometry {
+ /**
+ * Submit the given Geometry to the Pipeline for rendering.
+ * @param rm
+ * @param geom
+ * @return If true is returned, the geometry will be removed from the render Bucket after being rendered.
+ */
+ public boolean drawGeometry(RenderManager rm, Geometry geom);
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/OpaquePass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/OpaquePass.java
new file mode 100644
index 0000000000..96ff9a4737
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/OpaquePass.java
@@ -0,0 +1,25 @@
+package com.jme3.renderer.renderPass;
+
+import com.jme3.renderer.framegraph.FGRenderContext;
+import com.jme3.renderer.queue.RenderQueue;
+
+/**
+ * @author JohnKkk
+ */
+public class OpaquePass extends ForwardPass {
+ public OpaquePass(String name) {
+ super(name, RenderQueue.Bucket.Opaque);
+ }
+
+ @Override
+ public void executeDrawCommandList(FGRenderContext renderContext) {
+ if(canExecute){
+ renderContext.setDepthRange(0, 1);
+ }
+ super.executeDrawCommandList(renderContext);
+ }
+
+ public OpaquePass() {
+ super("ForwardOpaquePass", RenderQueue.Bucket.Opaque);
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/PostProcessorPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/PostProcessorPass.java
new file mode 100644
index 0000000000..05a73579cc
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/PostProcessorPass.java
@@ -0,0 +1,31 @@
+package com.jme3.renderer.renderPass;
+
+import com.jme3.post.SceneProcessor;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.framegraph.FGPass;
+import com.jme3.renderer.framegraph.FGRenderContext;
+import com.jme3.util.SafeArrayList;
+
+/**
+ * @author JohnKkk
+ */
+public class PostProcessorPass extends FGPass {
+ public PostProcessorPass(String name) {
+ super(name);
+ }
+
+ @Override
+ public void execute(FGRenderContext renderContext) {
+ renderContext.setDepthRange(0, 1);
+ ViewPort vp = renderContext.viewPort;
+ SafeArrayList processors = vp.getProcessors();
+ if (processors != null) {
+// if (prof!=null) prof.vpStep(VpStep.PostFrame, vp, null);
+ for (SceneProcessor proc : processors.getArray()) {
+// if (prof != null) prof.spStep(SpStep.ProcPostFrame, proc.getClass().getSimpleName());
+ proc.postFrame(vp.getOutputFrameBuffer());
+ }
+// if (prof != null) prof.vpStep(VpStep.ProcEndRender, vp, null);
+ }
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/ResolveSceneColorPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/ResolveSceneColorPass.java
new file mode 100644
index 0000000000..fea33f6731
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/ResolveSceneColorPass.java
@@ -0,0 +1,63 @@
+package com.jme3.renderer.renderPass;
+
+import com.jme3.material.Material;
+import com.jme3.material.MaterialDef;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.framegraph.*;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Geometry;
+import com.jme3.shader.VarType;
+import com.jme3.ui.Picture;
+
+/**
+ * @author JohnKkk
+ */
+public class ResolveSceneColorPass extends ScreenPass {
+ public final static String S_SCENE_COLOR_RT = "SceneColorRT";
+ public final static String S_SCENE_DEPTH = "SceneDepth";
+ private static final String _S_RESOLVE_SCENE_COLOR_MAT_DEF = "Common/MatDefs/Misc/ResolveSceneColor.j3md";
+
+ public ResolveSceneColorPass(String name) {
+ super(name, RenderQueue.Bucket.Opaque);
+ }
+
+ @Override
+ public void dispatchPassSetup(RenderQueue renderQueue) {
+ canExecute = true;
+ }
+
+ @Override
+ public void executeDrawCommandList(FGRenderContext renderContext) {
+ renderContext.renderManager.getRenderer().setFrameBuffer(null);
+ boolean depthWrite = screenMat.getAdditionalRenderState().isDepthWrite();
+ boolean depthTest = screenMat.getAdditionalRenderState().isDepthTest();
+ screenMat.getAdditionalRenderState().setDepthWrite(false);
+ screenMat.getAdditionalRenderState().setDepthTest(false);
+ screenRect.updateGeometricState();
+ screenMat.render(screenRect, renderContext.renderManager);
+ screenMat.getAdditionalRenderState().setDepthWrite(depthWrite);
+ screenMat.getAdditionalRenderState().setDepthTest(depthTest);
+ }
+ public void updateExposure(float exposure){
+ screenMat.setFloat("Exposure", exposure);
+ }
+
+ @Override
+ public boolean drawGeometry(RenderManager rm, Geometry geom) {
+ return true;
+ }
+
+ @Override
+ public void init() {
+ MaterialDef def = (MaterialDef) assetManager.loadAsset(_S_RESOLVE_SCENE_COLOR_MAT_DEF);
+ screenMat = new Material(def);
+ screenRect = new Picture(getName() + "_rect");
+ screenRect.setWidth(1);
+ screenRect.setHeight(1);
+ screenRect.setMaterial(screenMat);
+
+ // register Sinks
+ registerSink(new FGTextureBindableSink(S_SCENE_COLOR_RT, binds, binds.size(), screenMat, VarType.Texture2D));
+ registerSink(new FGFramebufferCopyBindableSink(FGGlobal.S_DEFAULT_FB, null, false, true, true, binds, binds.size()));
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/ScreenPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/ScreenPass.java
new file mode 100644
index 0000000000..5396e0f2bb
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/ScreenPass.java
@@ -0,0 +1,35 @@
+package com.jme3.renderer.renderPass;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.asset.plugins.ClasspathLocator;
+import com.jme3.asset.plugins.FileLocator;
+import com.jme3.material.Material;
+import com.jme3.material.plugins.J3MLoader;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.shader.plugins.GLSLLoader;
+import com.jme3.system.JmeSystem;
+import com.jme3.ui.Picture;
+
+public abstract class ScreenPass extends ForwardPass{
+ protected static AssetManager assetManager;
+ protected Material screenMat;
+ protected Picture screenRect;
+ public ScreenPass(String name, RenderQueue.Bucket bucket) {
+ super(name, bucket);
+ initAssetManager();
+ init();
+ }
+
+ public abstract void init();
+
+ private static void initAssetManager(){
+ if(assetManager == null){
+ assetManager = JmeSystem.newAssetManager();
+ assetManager.registerLocator(".", FileLocator.class);
+ assetManager.registerLocator("/", ClasspathLocator.class);
+ assetManager.registerLoader(J3MLoader.class, "j3m");
+ assetManager.registerLoader(J3MLoader.class, "j3md");
+ assetManager.registerLoader(GLSLLoader.class, "vert", "frag","geom","tsctrl","tseval","glsllib","glsl");
+ }
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/SkyPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/SkyPass.java
new file mode 100644
index 0000000000..dfe4154987
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/SkyPass.java
@@ -0,0 +1,21 @@
+package com.jme3.renderer.renderPass;
+
+import com.jme3.renderer.framegraph.FGRenderContext;
+import com.jme3.renderer.queue.RenderQueue;
+
+/**
+ * @author JohnKkk
+ */
+public class SkyPass extends ForwardPass{
+ public SkyPass() {
+ super("Sky", RenderQueue.Bucket.Sky);
+ }
+
+ @Override
+ public void executeDrawCommandList(FGRenderContext renderContext) {
+ if(canExecute){
+ renderContext.setDepthRange(1, 1);
+ }
+ super.executeDrawCommandList(renderContext);
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/TileDeferredShadingPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/TileDeferredShadingPass.java
new file mode 100644
index 0000000000..63dce6a330
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/TileDeferredShadingPass.java
@@ -0,0 +1,44 @@
+package com.jme3.renderer.renderPass;
+
+import com.jme3.light.LightList;
+import com.jme3.material.Material;
+import com.jme3.material.MaterialDef;
+import com.jme3.renderer.framegraph.FGRenderContext;
+
+public class TileDeferredShadingPass extends DeferredShadingPass{
+ private static final String _S_TILE_BASED_DEFERRED_SHADING_PASS_MAT_DEF = "Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md";
+ protected final static String _S_TILE_BASED_DEFERRED_PASS = "TileBasedDeferredPass";
+
+ public TileDeferredShadingPass() {
+ super("TileDeferredShadingPass");
+ }
+
+ @Override
+ protected Material getMaterial() {
+ MaterialDef def = (MaterialDef) assetManager.loadAsset(_S_TILE_BASED_DEFERRED_SHADING_PASS_MAT_DEF);
+ screenMat = new Material(def);
+ return screenMat;
+ }
+
+ @Override
+ public void executeDrawCommandList(FGRenderContext renderContext) {
+ DeferredLightDataSink deferredLightDataSink = (DeferredLightDataSink) getSink(S_LIGHT_DATA);
+ DeferredLightDataSource.DeferredLightDataProxy deferredLightDataProxy = (DeferredLightDataSource.DeferredLightDataProxy) deferredLightDataSink.getBind();
+ LightList lights = deferredLightDataProxy.getLightData();
+
+ // Handle FullScreenLights
+ screenMat.selectTechnique(_S_TILE_BASED_DEFERRED_PASS, renderContext.renderManager);
+ boolean depthWrite = screenMat.getAdditionalRenderState().isDepthWrite();
+ boolean depthTest = screenMat.getAdditionalRenderState().isDepthTest();
+ screenMat.getAdditionalRenderState().setDepthTest(false);
+ screenMat.getAdditionalRenderState().setDepthWrite(false);
+ screenMat.setBoolean("UseLightsCullMode", false);
+ screenRect.updateGeometricState();
+ screenMat.render(screenRect, lights, renderContext.renderManager);
+ screenMat.getAdditionalRenderState().setDepthTest(depthTest);
+ screenMat.getAdditionalRenderState().setDepthWrite(depthWrite);
+
+ // Handle non-fullscreen lights
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/TranslucentPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/TranslucentPass.java
new file mode 100644
index 0000000000..713ef95956
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/TranslucentPass.java
@@ -0,0 +1,18 @@
+package com.jme3.renderer.renderPass;
+
+import com.jme3.renderer.framegraph.FGRenderContext;
+import com.jme3.renderer.queue.RenderQueue;
+
+public class TranslucentPass extends ForwardPass{
+ @Override
+ public void executeDrawCommandList(FGRenderContext renderContext) {
+ if(canExecute){
+ renderContext.setDepthRange(0, 1);
+ }
+ super.executeDrawCommandList(renderContext);
+ }
+
+ public TranslucentPass() {
+ super("TranslucentPass", RenderQueue.Bucket.Translucent);
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/TransparentPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/TransparentPass.java
new file mode 100644
index 0000000000..e473b1f830
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/TransparentPass.java
@@ -0,0 +1,21 @@
+package com.jme3.renderer.renderPass;
+
+import com.jme3.renderer.framegraph.FGRenderContext;
+import com.jme3.renderer.queue.RenderQueue;
+
+/**
+ * @author JohnKkk
+ */
+public class TransparentPass extends ForwardPass{
+ @Override
+ public void executeDrawCommandList(FGRenderContext renderContext) {
+ if(canExecute){
+ renderContext.setDepthRange(0, 1);
+ }
+ super.executeDrawCommandList(renderContext);
+ }
+
+ public TransparentPass() {
+ super("TransparentPass", RenderQueue.Bucket.Transparent);
+ }
+}
diff --git a/jme3-core/src/main/java/com/jme3/scene/Spatial.java b/jme3-core/src/main/java/com/jme3/scene/Spatial.java
index 2fe1775d3e..dea54b355c 100644
--- a/jme3-core/src/main/java/com/jme3/scene/Spatial.java
+++ b/jme3-core/src/main/java/com/jme3/scene/Spatial.java
@@ -137,6 +137,7 @@ public enum BatchHint {
*/
protected LightList localLights;
protected transient LightList worldLights;
+ protected transient LightList filterWorldLights;
protected SafeArrayList localOverrides;
protected SafeArrayList worldOverrides;
@@ -247,7 +248,7 @@ boolean requiresUpdates() {
* call setRequiresUpdate(false) in their constructors to receive
* optimal behavior if they don't require updateLogicalState() to be
* called even if there are no controls.
- *
+ *
* @param f true→require updates, false→don't require updates
*/
protected void setRequiresUpdates(boolean f) {
@@ -434,6 +435,18 @@ public LightList getWorldLightList() {
return worldLights;
}
+ /**
+ * set Current filterLight.
+ * @param filterLight
+ */
+ public void setFilterLight(LightList filterLight){
+ filterWorldLights = filterLight;
+ }
+
+ public LightList getFilterWorldLights() {
+ return filterWorldLights;
+ }
+
/**
* Get the local material parameter overrides.
*
@@ -1595,7 +1608,7 @@ public Collection getUserDataKeys() {
* @see java.util.regex.Pattern
*/
public boolean matches(Class extends Spatial> spatialSubclass,
- String nameRegex) {
+ String nameRegex) {
if (spatialSubclass != null && !spatialSubclass.isInstance(this)) {
return false;
}
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md
index ec85c0729e..6fe7c03962 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md
@@ -129,6 +129,12 @@ MaterialDef Phong Lighting {
Float ExpFog
Float ExpSqFog
+ // Context GBuffer Data
+ Texture2D Context_InGBuff0
+ Texture2D Context_InGBuff1
+ Texture2D Context_InGBuff2
+ Texture2D Context_InGBuff3
+ Texture2D Context_InGBuff4
}
Technique {
@@ -257,6 +263,50 @@ MaterialDef Phong Lighting {
}
+ Technique GBufferPass{
+ Pipeline Deferred
+ VertexShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/Light/LightingGBufferPack.vert
+ FragmentShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/Light/LightingGBufferPack.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ NormalMatrix
+ WorldNormalMatrix
+ WorldViewMatrix
+ ViewMatrix
+ CameraPosition
+ WorldMatrix
+ ViewProjectionMatrix
+ }
+
+ Defines {
+ VERTEX_COLOR : UseVertexColor
+ 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 : EnvMapAsSphereMap
+ NUM_BONES : NumberOfBones
+ INSTANCING : UseInstancing
+ NUM_MORPH_TARGETS: NumberOfMorphTargets
+ NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers
+
+ // fog - jayfella
+ USE_FOG : UseFog
+ FOG_LINEAR : LinearFog
+ FOG_EXP : ExpFog
+ FOG_EXPSQ : ExpSqFog
+ }
+ }
Technique PostShadow {
VertexShader GLSL310 GLSL300 GLSL150 GLSL100: Common/MatDefs/Shadow/PostShadow.vert
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/LightingGBufferPack.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/LightingGBufferPack.frag
new file mode 100644
index 0000000000..f4911adb5d
--- /dev/null
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/LightingGBufferPack.frag
@@ -0,0 +1,212 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+#import "Common/ShaderLib/Deferred.glsllib"
+#import "Common/ShaderLib/Parallax.glsllib"
+#import "Common/ShaderLib/Optics.glsllib"
+#ifndef VERTEX_LIGHTING
+ #import "Common/ShaderLib/BlinnPhongLighting.glsllib"
+ #import "Common/ShaderLib/Lighting.glsllib"
+#endif
+// shading model
+#import "Common/ShaderLib/ShadingModel.glsllib"
+
+// fog - jayfella
+#ifdef USE_FOG
+#import "Common/ShaderLib/MaterialFog.glsllib"
+varying float fog_distance;
+uniform vec4 m_FogColor;
+
+#ifdef FOG_LINEAR
+uniform vec2 m_LinearFog;
+#endif
+
+#ifdef FOG_EXP
+uniform float m_ExpFog;
+#endif
+
+#ifdef FOG_EXPSQ
+uniform float m_ExpSqFog;
+#endif
+
+#endif // end fog
+
+varying vec2 texCoord;
+#ifdef SEPARATE_TEXCOORD
+ varying vec2 texCoord2;
+#endif
+
+varying vec3 AmbientSum;
+varying vec4 DiffuseSum;
+varying vec3 SpecularSum;
+
+#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;
+ varying vec3 vPos;
+ uniform vec3 g_CameraPosition;
+#endif
+
+#ifdef LIGHTMAP
+ uniform sampler2D m_LightMap;
+#endif
+
+#ifdef NORMALMAP
+ uniform sampler2D m_NormalMap;
+ varying vec4 vTangent;
+#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(NORMALMAP) || defined(PARALLAXMAP)
+ vec3 norm = normalize(vNormal);
+ vec3 tan = normalize(vTangent.xyz);
+ mat3 tbnMat = mat3(tan, vTangent.w * cross( (norm), (tan)), norm);
+ #endif
+
+ #if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) && !defined(VERTEX_LIGHTING)
+ vec3 viewDir = normalize(g_CameraPosition - vPos);
+ vec3 vViewDir = viewDir * tbnMat;
+ #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 compliant with normal maps generated with blender.
+ //see http://hub.jmonkeyengine.org/forum/topic/parallax-mapping-fundamental-bug/#post-256898
+ //for more explanation.
+ //mat3 tbnMat = mat3(vTangent.xyz, vTangent.w * cross( (vNormal), (vTangent.xyz)), vNormal.xyz);
+
+ if (!gl_FrontFacing)
+ {
+ tbnMat[2] = -tbnMat[2];
+ }
+ vec3 normal = tbnMat * normalize((normalHeight.xyz * vec3(2.0,-2.0,2.0) - vec3(1.0,-1.0,1.0)));
+ normal = normalize(normal);
+ #elif !defined(VERTEX_LIGHTING)
+ vec3 normal = normalize(vNormal);
+
+ if (!gl_FrontFacing)
+ {
+ normal = -normal;
+ }
+ #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
+
+ // pack
+ Context_OutGBuff3.xyz = normal;
+ Context_OutGBuff0.a = alpha;
+
+// #ifdef USE_REFLECTION
+// vec4 refColor = Optics_GetEnvColor(m_EnvMap, refVec.xyz);
+// #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);
+// #endif
+//
+// vec3 DiffuseSum2 = DiffuseSum.rgb;
+// #ifdef COLORRAMP
+// DiffuseSum2.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb;
+// SpecularSum2.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb;
+// light.xy = vec2(1.0);
+// #endif
+ Context_OutGBuff0.rgb = diffuseColor.rgb * DiffuseSum.rgb;
+ Context_OutGBuff1.rgb = specularColor.rgb * SpecularSum.rgb * 100.0f + AmbientSum * 0.01f;
+ Context_OutGBuff1.a = m_Shininess;
+
+ // shading model id
+ Context_OutGBuff2.a = LEGACY_LIGHTING;
+}
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/LightingGBufferPack.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/LightingGBufferPack.vert
new file mode 100644
index 0000000000..b8a1598c9b
--- /dev/null
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/LightingGBufferPack.vert
@@ -0,0 +1,149 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+#import "Common/ShaderLib/Instancing.glsllib"
+#import "Common/ShaderLib/Skinning.glsllib"
+#import "Common/ShaderLib/Lighting.glsllib"
+#import "Common/ShaderLib/MorphAnim.glsllib"
+
+#ifdef VERTEX_LIGHTING
+ #import "Common/ShaderLib/BlinnPhongLighting.glsllib"
+#endif
+
+// fog - jayfella
+#ifdef USE_FOG
+varying float fog_distance;
+uniform vec3 g_CameraPosition;
+#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
+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 vec4 vTangent;
+ #endif
+#else
+ #ifdef COLORRAMP
+ uniform sampler2D m_ColorRamp;
+ #endif
+#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_MORPH_TARGETS
+ #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING)
+ Morph_Compute(modelSpacePos, modelSpaceNorm, modelSpaceTan);
+ #else
+ Morph_Compute(modelSpacePos, modelSpaceNorm);
+ #endif
+ #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 wPosition = TransformWorld(modelSpacePos).xyz;
+ vec3 wNormal = normalize(TransformWorldNormal(modelSpaceNorm));
+
+ #if (defined(NORMALMAP) || defined(PARALLAXMAP)) && !defined(VERTEX_LIGHTING)
+ vTangent = vec4(TransformWorldNormal(modelSpaceTan).xyz,inTangent.w);
+ vNormal = wNormal;
+ vPos = wPosition;
+ #elif !defined(VERTEX_LIGHTING)
+ vNormal = wNormal;
+ vPos = wPosition;
+ #endif
+
+ #ifdef MATERIAL_COLORS
+ AmbientSum = m_Ambient.rgb;
+ SpecularSum = m_Specular.rgb;
+ DiffuseSum = m_Diffuse;
+ #else
+ // Defaults: Ambient and diffuse are white, specular is black.
+ AmbientSum = vec3(1.0);
+ SpecularSum = vec3(0.0);
+ DiffuseSum = vec4(1.0);
+ #endif
+ #ifdef VERTEX_COLOR
+ AmbientSum *= inColor.rgb;
+ DiffuseSum *= inColor;
+ #endif
+
+// #ifdef USE_REFLECTION
+// computeRef(modelSpacePos);
+// #endif
+
+ #ifdef USE_FOG
+ fog_distance = distance(g_CameraPosition, (TransformWorld(modelSpacePos)).xyz);
+ #endif
+}
\ No newline at end of file
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md
index 2b2d5453f4..a9aba47d6d 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md
@@ -125,6 +125,13 @@ MaterialDef PBR Lighting {
Boolean UseVertexColor
Boolean BackfaceShadows : false
+
+ // Context GBuffer Data
+ Texture2D Context_InGBuff0
+ Texture2D Context_InGBuff1
+ Texture2D Context_InGBuff2
+ Texture2D Context_InGBuff3
+ Texture2D Context_InGBuff4
}
Technique {
@@ -207,6 +214,49 @@ MaterialDef PBR Lighting {
}
+ Technique GBufferPass{
+ Pipeline Deferred
+ VertexShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/Light/PBRLightingGBufferPack.vert
+ FragmentShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/Light/PBRLightingGBufferPack.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ CameraPosition
+ WorldMatrix
+ WorldNormalMatrix
+ ViewProjectionMatrix
+ ViewMatrix
+ }
+
+ Defines {
+ BASECOLORMAP : BaseColorMap
+ NORMALMAP : NormalMap
+ METALLICMAP : MetallicMap
+ ROUGHNESSMAP : RoughnessMap
+ EMISSIVEMAP : EmissiveMap
+ EMISSIVE : Emissive
+ SPECGLOSSPIPELINE : UseSpecGloss
+ PARALLAXMAP : ParallaxMap
+ NORMALMAP_PARALLAX : PackedNormalParallax
+ STEEP_PARALLAX : SteepParallax
+ LIGHTMAP : LightMap
+ SEPARATE_TEXCOORD : SeparateTexCoord
+ DISCARD_ALPHA : AlphaDiscardThreshold
+ NUM_BONES : NumberOfBones
+ INSTANCING : UseInstancing
+ USE_PACKED_MR: MetallicRoughnessMap
+ USE_PACKED_SG: SpecularGlossinessMap
+ SPECULARMAP : SpecularMap
+ GLOSSINESSMAP : GlossinessMap
+ NORMAL_TYPE: NormalType
+ VERTEX_COLOR : UseVertexColor
+ AO_MAP: LightMapAsAOMap
+ AO_PACKED_IN_MR_MAP : AoPackedInMRMap
+ NUM_MORPH_TARGETS: NumberOfMorphTargets
+ NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers
+ HORIZON_FADE: HorizonFade
+ }
+ }
Technique PostShadow {
VertexShader GLSL310 GLSL300 GLSL150 GLSL100: Common/MatDefs/Shadow/PostShadow.vert
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLightingGBufferPack.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLightingGBufferPack.frag
new file mode 100644
index 0000000000..6784362a83
--- /dev/null
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLightingGBufferPack.frag
@@ -0,0 +1,258 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+#import "Common/ShaderLib/PBR.glsllib"
+#import "Common/ShaderLib/Parallax.glsllib"
+#import "Common/ShaderLib/Lighting.glsllib"
+#import "Common/ShaderLib/Deferred.glsllib"
+
+// shading model
+#import "Common/ShaderLib/ShadingModel.glsllib"
+// octahedral
+#import "Common/ShaderLib/Octahedral.glsllib"
+
+varying vec2 texCoord;
+#ifdef SEPARATE_TEXCOORD
+ varying vec2 texCoord2;
+#endif
+
+varying vec4 Color;
+
+uniform vec3 g_CameraPosition;
+
+uniform float m_Roughness;
+uniform float m_Metallic;
+
+varying vec3 wPosition;
+
+
+#if NB_PROBES >= 1
+ uniform samplerCube g_PrefEnvMap;
+ uniform vec3 g_ShCoeffs[9];
+ uniform mat4 g_LightProbeData;
+#endif
+#if NB_PROBES >= 2
+ uniform samplerCube g_PrefEnvMap2;
+ uniform vec3 g_ShCoeffs2[9];
+ uniform mat4 g_LightProbeData2;
+#endif
+#if NB_PROBES == 3
+ uniform samplerCube g_PrefEnvMap3;
+ uniform vec3 g_ShCoeffs3[9];
+ uniform mat4 g_LightProbeData3;
+#endif
+
+#ifdef BASECOLORMAP
+ uniform sampler2D m_BaseColorMap;
+#endif
+
+#ifdef USE_PACKED_MR
+ uniform sampler2D m_MetallicRoughnessMap;
+#else
+ #ifdef METALLICMAP
+ uniform sampler2D m_MetallicMap;
+ #endif
+ #ifdef ROUGHNESSMAP
+ uniform sampler2D m_RoughnessMap;
+ #endif
+#endif
+
+#ifdef EMISSIVE
+ uniform vec4 m_Emissive;
+#endif
+#ifdef EMISSIVEMAP
+ uniform sampler2D m_EmissiveMap;
+#endif
+#if defined(EMISSIVE) || defined(EMISSIVEMAP)
+ uniform float m_EmissivePower;
+ uniform float m_EmissiveIntensity;
+#endif
+
+#ifdef SPECGLOSSPIPELINE
+
+ uniform vec4 m_Specular;
+ uniform float m_Glossiness;
+ #ifdef USE_PACKED_SG
+ uniform sampler2D m_SpecularGlossinessMap;
+ #else
+ uniform sampler2D m_SpecularMap;
+ uniform sampler2D m_GlossinessMap;
+ #endif
+#endif
+
+#ifdef PARALLAXMAP
+ uniform sampler2D m_ParallaxMap;
+#endif
+#if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP)))
+ uniform float m_ParallaxHeight;
+#endif
+
+#ifdef LIGHTMAP
+ uniform sampler2D m_LightMap;
+#endif
+
+#if defined(NORMALMAP) || defined(PARALLAXMAP)
+ uniform sampler2D m_NormalMap;
+ varying vec4 wTangent;
+#endif
+varying vec3 wNormal;
+
+#ifdef DISCARD_ALPHA
+ uniform float m_AlphaDiscardThreshold;
+#endif
+
+void main(){
+ vec2 newTexCoord;
+ vec3 viewDir = normalize(g_CameraPosition - wPosition);
+
+ vec3 norm = normalize(wNormal);
+ #if defined(NORMALMAP) || defined(PARALLAXMAP)
+ vec3 tan = normalize(wTangent.xyz);
+ mat3 tbnMat = mat3(tan, wTangent.w * cross( (norm), (tan)), norm);
+ #endif
+
+ #if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP)))
+ vec3 vViewDir = viewDir * tbnMat;
+ #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 BASECOLORMAP
+ vec4 albedo = texture2D(m_BaseColorMap, newTexCoord) * Color;
+ #else
+ vec4 albedo = Color;
+ #endif
+
+ //ao in r channel, roughness in green channel, metallic in blue channel!
+ vec3 aoRoughnessMetallicValue = vec3(1.0, 1.0, 0.0);
+ #ifdef USE_PACKED_MR
+ aoRoughnessMetallicValue = texture2D(m_MetallicRoughnessMap, newTexCoord).rgb;
+ float Roughness = aoRoughnessMetallicValue.g * max(m_Roughness, 1e-4);
+ float Metallic = aoRoughnessMetallicValue.b * max(m_Metallic, 0.0);
+ #else
+ #ifdef ROUGHNESSMAP
+ float Roughness = texture2D(m_RoughnessMap, newTexCoord).r * max(m_Roughness, 1e-4);
+ #else
+ float Roughness = max(m_Roughness, 1e-4);
+ #endif
+ #ifdef METALLICMAP
+ float Metallic = texture2D(m_MetallicMap, newTexCoord).r * max(m_Metallic, 0.0);
+ #else
+ float Metallic = max(m_Metallic, 0.0);
+ #endif
+ #endif
+
+ float alpha = albedo.a;
+
+ #ifdef DISCARD_ALPHA
+ if(alpha < m_AlphaDiscardThreshold){
+ discard;
+ }
+ #endif
+
+ // ***********************
+ // Read from textures
+ // ***********************
+ #if defined(NORMALMAP)
+ 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 compliant 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, NORMAL_TYPE * 2.0, 2.0) - vec3(1.0, NORMAL_TYPE * 1.0, 1.0)));
+ normal = normalize(tbnMat * normal);
+ //normal = normalize(normal * inverse(tbnMat));
+ #else
+ vec3 normal = norm;
+ #endif
+
+ #ifdef SPECGLOSSPIPELINE
+
+ #ifdef USE_PACKED_SG
+ vec4 specularColor = texture2D(m_SpecularGlossinessMap, newTexCoord);
+ float glossiness = specularColor.a * m_Glossiness;
+ specularColor *= m_Specular;
+ #else
+ #ifdef SPECULARMAP
+ vec4 specularColor = texture2D(m_SpecularMap, newTexCoord);
+ #else
+ vec4 specularColor = vec4(1.0);
+ #endif
+ #ifdef GLOSSINESSMAP
+ float glossiness = texture2D(m_GlossinessMap, newTexCoord).r * m_Glossiness;
+ #else
+ float glossiness = m_Glossiness;
+ #endif
+ specularColor *= m_Specular;
+ #endif
+ vec4 diffuseColor = albedo;// * (1.0 - max(max(specularColor.r, specularColor.g), specularColor.b));
+ Roughness = 1.0 - glossiness;
+ vec3 fZero = specularColor.xyz;
+ #else
+ float specular = 0.5;
+ float nonMetalSpec = 0.08 * specular;
+ vec4 specularColor = (nonMetalSpec - nonMetalSpec * Metallic) + albedo * Metallic;
+ vec4 diffuseColor = albedo - albedo * Metallic;
+ vec3 fZero = vec3(specular);
+ #endif
+
+ vec3 ao = vec3(1.0);
+
+ #ifdef LIGHTMAP
+ vec3 lightMapColor;
+ #ifdef SEPARATE_TEXCOORD
+ lightMapColor = texture2D(m_LightMap, texCoord2).rgb;
+ #else
+ lightMapColor = texture2D(m_LightMap, texCoord).rgb;
+ #endif
+ #ifdef AO_MAP
+ lightMapColor.gb = lightMapColor.rr;
+ ao = lightMapColor;
+ #else
+ diffuseColor.rgb *= lightMapColor;
+ #endif
+ specularColor.rgb *= lightMapColor;
+ #endif
+
+ #if defined(AO_PACKED_IN_MR_MAP) && defined(USE_PACKED_MR)
+ ao = aoRoughnessMetallicValue.rrr;
+ #endif
+
+ float ndotv = max( dot( normal, viewDir ),0.0);
+
+ #if defined(EMISSIVE) || defined (EMISSIVEMAP)
+ #ifdef EMISSIVEMAP
+ vec4 emissive = texture2D(m_EmissiveMap, newTexCoord);
+ #else
+ vec4 emissive = m_Emissive;
+ #endif
+ Context_OutGBuff2.rgb = (emissive * pow(emissive.a, m_EmissivePower) * m_EmissiveIntensity).rgb;
+ #endif
+ // pack
+ vec2 n1 = octEncode(normal);
+ vec2 n2 = octEncode(norm);
+ Context_OutGBuff3.xy = n1;
+ Context_OutGBuff3.zw = n2;
+ Context_OutGBuff0.rgb = floor(diffuseColor.rgb * 100.0f) + ao * 0.1f;
+ Context_OutGBuff1.rgb = floor(specularColor.rgb * 100.0f) + fZero * 0.1f;
+ Context_OutGBuff1.a = Roughness;
+ Context_OutGBuff0.a = alpha;
+
+ // shading model id
+ Context_OutGBuff2.a = STANDARD_LIGHTING;
+}
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLightingGBufferPack.vert b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLightingGBufferPack.vert
new file mode 100644
index 0000000000..b910a8d4b2
--- /dev/null
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLightingGBufferPack.vert
@@ -0,0 +1,74 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+#import "Common/ShaderLib/Instancing.glsllib"
+#import "Common/ShaderLib/Skinning.glsllib"
+#import "Common/ShaderLib/MorphAnim.glsllib"
+
+uniform vec4 m_BaseColor;
+uniform vec4 g_AmbientLightColor;
+varying vec2 texCoord;
+
+#ifdef SEPARATE_TEXCOORD
+ varying vec2 texCoord2;
+ attribute vec2 inTexCoord2;
+#endif
+
+varying vec4 Color;
+
+attribute vec3 inPosition;
+attribute vec2 inTexCoord;
+attribute vec3 inNormal;
+
+#ifdef VERTEX_COLOR
+ attribute vec4 inColor;
+#endif
+
+varying vec3 wNormal;
+varying vec3 wPosition;
+#if defined(NORMALMAP) || defined(PARALLAXMAP)
+ attribute vec4 inTangent;
+ varying vec4 wTangent;
+#endif
+
+void main(){
+ vec4 modelSpacePos = vec4(inPosition, 1.0);
+ vec3 modelSpaceNorm = inNormal;
+
+ #if ( defined(NORMALMAP) || defined(PARALLAXMAP)) && !defined(VERTEX_LIGHTING)
+ vec3 modelSpaceTan = inTangent.xyz;
+ #endif
+
+ #ifdef NUM_MORPH_TARGETS
+ #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING)
+ Morph_Compute(modelSpacePos, modelSpaceNorm, modelSpaceTan);
+ #else
+ Morph_Compute(modelSpacePos, modelSpaceNorm);
+ #endif
+ #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
+
+ wPosition = TransformWorld(modelSpacePos).xyz;
+ wNormal = TransformWorldNormal(modelSpaceNorm);
+
+ #if defined(NORMALMAP) || defined(PARALLAXMAP)
+ wTangent = vec4(TransformWorldNormal(modelSpaceTan),inTangent.w);
+ #endif
+
+ Color = m_BaseColor;
+
+ #ifdef VERTEX_COLOR
+ Color *= inColor;
+ #endif
+}
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag
new file mode 100644
index 0000000000..89746d1b2e
--- /dev/null
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag
@@ -0,0 +1,231 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+#import "Common/ShaderLib/Deferred.glsllib"
+#import "Common/ShaderLib/Parallax.glsllib"
+#import "Common/ShaderLib/Optics.glsllib"
+#import "Common/ShaderLib/BlinnPhongLighting.glsllib"
+#import "Common/ShaderLib/Lighting.glsllib"
+#import "Common/ShaderLib/PBR.glsllib"
+#import "Common/ShaderLib/ShadingModel.glsllib"
+// octahedral
+#import "Common/ShaderLib/Octahedral.glsllib"
+// skyLight and reflectionProbe
+#import "Common/ShaderLib/SkyLightReflectionProbe.glsllib"
+#if defined(USE_LIGHTS_CULL_MODE)
+ uniform vec2 g_ResolutionInverse;
+#else
+ varying vec2 texCoord;
+#endif
+
+varying mat4 viewProjectionMatrixInverse;
+uniform mat4 g_ViewMatrix;
+uniform vec3 g_CameraPosition;
+uniform vec4 g_AmbientLightColor;
+
+#if defined(USE_TEXTURE_PACK_MODE)
+ uniform int g_LightCount;
+ uniform sampler2D m_LightPackData1;
+ uniform sampler2D m_LightPackData2;
+ uniform sampler2D m_LightPackData3;
+#else
+ uniform vec4 g_LightData[NB_LIGHTS];
+#endif
+
+
+void main(){
+ vec2 innerTexCoord;
+#if defined(USE_LIGHTS_CULL_MODE)
+ innerTexCoord = gl_FragCoord.xy * g_ResolutionInverse;
+#else
+ innerTexCoord = texCoord;
+#endif
+ // unpack GBuffer
+ vec4 shadingInfo = texture2D(Context_InGBuff2, innerTexCoord);
+ int shadingModelId = int(floor(shadingInfo.a));
+ // Perform corresponding pixel shading based on the shading model
+ if(IS_LIT(shadingModelId)){
+ // lit shading model
+ // todo:For now, use the big branch first, and extract the common parts later
+ if(shadingModelId == LEGACY_LIGHTING){
+ vec3 vPos = getPosition(innerTexCoord, viewProjectionMatrixInverse);
+ vec4 buff1 = texture2D(Context_InGBuff1, innerTexCoord);
+ vec4 diffuseColor = texture2D(Context_InGBuff0, innerTexCoord);
+ vec3 specularColor = floor(buff1.rgb) * 0.01f;
+ vec3 AmbientSum = min(fract(buff1.rgb) * 100.0f, vec3(1.0f)) * g_AmbientLightColor.rgb;
+ float Shininess = buff1.a;
+ float alpha = diffuseColor.a;
+ vec3 normal = texture2D(Context_InGBuff3, innerTexCoord).xyz;
+ vec3 viewDir = normalize(g_CameraPosition - vPos);
+
+
+ gl_FragColor.rgb = AmbientSum * diffuseColor.rgb;
+ gl_FragColor.a = alpha;
+ int lightNum = 0;
+ #if defined(USE_TEXTURE_PACK_MODE)
+ float lightTexSizeInv = 1.0f / (float(PACK_NB_LIGHTS) - 1.0f);
+ lightNum = g_LightCount;
+ #else
+ lightNum = NB_LIGHTS;
+ #endif
+ for( int i = 0;i < lightNum; ){
+ #if defined(USE_TEXTURE_PACK_MODE)
+ vec4 lightColor = texture2D(m_LightPackData1, vec2(i * lightTexSizeInv, 0));
+ vec4 lightData1 = texture2D(m_LightPackData2, vec2(i * lightTexSizeInv, 0));
+ #else
+ vec4 lightColor = g_LightData[i];
+ vec4 lightData1 = g_LightData[i+1];
+ #endif
+ 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
+ #if defined(USE_TEXTURE_PACK_MODE)
+ spotFallOff = computeSpotFalloff(texture2D(m_LightPackData3, vec2(i * lightTexSizeInv, 0)), lightVec);
+ #else
+ spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec);
+ #endif
+ #if __VERSION__ >= 110
+ }
+ #endif
+
+ #ifdef NORMALMAP
+ //Normal map -> lighting is computed in tangent space
+ lightDir.xyz = normalize(lightDir.xyz * tbnMat);
+ #else
+ //no Normal map -> lighting is computed in view space
+ lightDir.xyz = normalize(lightDir.xyz);
+ #endif
+
+ vec2 light = computeLighting(normal, viewDir, lightDir.xyz, lightDir.w * spotFallOff , Shininess);
+
+ // Workaround, since it is not possible to modify varying variables
+ // #ifdef USE_REFLECTION
+ // // Interpolate light specularity toward reflection color
+ // // Multiply result by specular map
+ // specularColor = mix(specularColor * light.y, refColor, refVec.w) * specularColor;
+ // light.y = 1.0;
+ // #endif
+ //
+ // #ifdef COLORRAMP
+ // diffuseColor.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb;
+ // specularColor.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb;
+ // light.xy = vec2(1.0);
+ // #endif
+
+ gl_FragColor.rgb += lightColor.rgb * diffuseColor.rgb * vec3(light.x) +
+ lightColor.rgb * specularColor.rgb * vec3(light.y);
+ #if defined(USE_TEXTURE_PACK_MODE)
+ i++;
+ #else
+ i+=3;
+ #endif
+ }
+ }
+ else if(shadingModelId == STANDARD_LIGHTING){
+ // todo:
+ vec3 vPos = getPosition(innerTexCoord, viewProjectionMatrixInverse);
+ vec4 buff0 = texture2D(Context_InGBuff0, innerTexCoord);
+ vec4 buff1 = texture2D(Context_InGBuff1, innerTexCoord);
+ vec3 emissive = shadingInfo.rgb;
+ vec3 diffuseColor = floor(buff0.rgb) * 0.01f;
+ vec3 specularColor = floor(buff1.rgb) * 0.01f;
+ vec3 ao = min(fract(buff0.rgb) * 10.0f, vec3(1.0f));
+ vec3 fZero = min(fract(buff1.rgb) * 10.0f, vec3(0.5f));
+ float Roughness = buff1.a;
+ float alpha = buff0.a;
+ vec4 n1n2 = texture2D(Context_InGBuff3, innerTexCoord);
+ vec3 normal = octDecode(n1n2.xy);
+ vec3 norm = octDecode(n1n2.zw);
+ vec3 viewDir = normalize(g_CameraPosition - vPos);
+
+ float ndotv = max( dot( normal, viewDir ),0.0);
+ int lightNum = 0;
+ #if defined(USE_TEXTURE_PACK_MODE)
+ float lightTexSizeInv = 1.0f / (float(PACK_NB_LIGHTS) - 1.0f);
+ lightNum = g_LightCount;
+ #else
+ lightNum = NB_LIGHTS;
+ #endif
+ gl_FragColor.rgb = vec3(0.0);
+ for( int i = 0;i < lightNum; ){
+ #if defined(USE_TEXTURE_PACK_MODE)
+ vec4 lightColor = texture2D(m_LightPackData1, vec2(i * lightTexSizeInv, 0));
+ vec4 lightData1 = texture2D(m_LightPackData2, vec2(i * lightTexSizeInv, 0));
+ #else
+ vec4 lightColor = g_LightData[i];
+ vec4 lightData1 = g_LightData[i+1];
+ #endif
+ 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
+ #if defined(USE_TEXTURE_PACK_MODE)
+ spotFallOff = computeSpotFalloff(texture2D(m_LightPackData3, vec2(i * lightTexSizeInv, 0)), lightVec);
+ #else
+ spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec);
+ #endif
+ #if __VERSION__ >= 110
+ }
+ #endif
+
+ #ifdef NORMALMAP
+ //Normal map -> lighting is computed in tangent space
+ lightDir.xyz = normalize(lightDir.xyz * tbnMat);
+ #else
+ //no Normal map -> lighting is computed in view space
+ lightDir.xyz = normalize(lightDir.xyz);
+ #endif
+
+ vec3 directDiffuse;
+ vec3 directSpecular;
+
+ float hdotv = PBR_ComputeDirectLight(normal, lightDir.xyz, viewDir,
+ lightColor.rgb, fZero, Roughness, ndotv,
+ directDiffuse, directSpecular);
+
+ vec3 directLighting = diffuseColor.rgb *directDiffuse + directSpecular;
+
+ // Workaround, since it is not possible to modify varying variables
+ // #ifdef USE_REFLECTION
+ // // Interpolate light specularity toward reflection color
+ // // Multiply result by specular map
+ // specularColor = mix(specularColor * light.y, refColor, refVec.w) * specularColor;
+ // light.y = 1.0;
+ // #endif
+ //
+ // #ifdef COLORRAMP
+ // diffuseColor.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb;
+ // specularColor.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb;
+ // light.xy = vec2(1.0);
+ // #endif
+
+ gl_FragColor.rgb += directLighting * spotFallOff;
+ #if defined(USE_TEXTURE_PACK_MODE)
+ i++;
+ #else
+ i++;
+ #endif
+ }
+ // skyLight and reflectionProbe
+ vec3 skyLightAndReflection = renderSkyLightAndReflectionProbes(viewDir, vPos, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao);
+ gl_FragColor.rgb += skyLightAndReflection;
+ gl_FragColor.rgb += emissive;
+ gl_FragColor.a = alpha;
+ }
+ else if(shadingModelId == SUBSURFACE_SCATTERING){
+ // todo:
+ }
+ }
+ else if(shadingModelId == UNLIT){
+ // todo:
+ }
+}
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md
new file mode 100644
index 0000000000..dd1c1bc7f4
--- /dev/null
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md
@@ -0,0 +1,42 @@
+MaterialDef DeferredShading {
+
+ MaterialParameters {
+ // For instancing
+ Boolean UseInstancing
+ // UseLightsCull
+ Boolean UseLightsCullMode
+
+ // Context GBuffer Data
+ Texture2D Context_InGBuff0
+ Texture2D Context_InGBuff1
+ Texture2D Context_InGBuff2
+ Texture2D Context_InGBuff3
+ Texture2D Context_InGBuff4
+
+ // LightData
+ Texture2D LightPackData1
+ Texture2D LightPackData2
+ Texture2D LightPackData3
+ }
+
+ Technique DeferredPass{
+ Pipeline Deferred
+ LightMode DeferredSinglePass
+
+ VertexShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/ShadingCommon/DeferredShading.vert
+ FragmentShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/ShadingCommon/DeferredShading.frag
+
+ WorldParameters {
+ CameraPosition
+ WorldViewProjectionMatrix
+ ViewProjectionMatrix
+ ResolutionInverse
+ }
+
+ Defines {
+ INSTANCING : UseInstancing
+ USE_LIGHTS_CULL_MODE : UseLightsCullMode
+ }
+ }
+
+}
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.vert b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.vert
new file mode 100644
index 0000000000..cfb28fcf4a
--- /dev/null
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.vert
@@ -0,0 +1,23 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+#import "Common/ShaderLib/Instancing.glsllib"
+varying vec2 texCoord;
+
+attribute vec3 inPosition;
+#if !defined(USE_LIGHTS_CULL_MODE)
+ attribute vec2 inTexCoord;
+#endif
+
+varying mat4 viewProjectionMatrixInverse;
+
+void main(){
+#if !defined(USE_LIGHTS_CULL_MODE)
+ texCoord = inTexCoord;
+ vec4 pos = vec4(inPosition, 1.0);
+ gl_Position = vec4(sign(pos.xy-vec2(0.5)), 0.0, 1.0);
+#else
+ gl_Position = TransformWorldViewProjection(vec4(inPosition, 1.0));// g_WorldViewProjectionMatrix * modelSpacePos;
+#endif
+
+ viewProjectionMatrixInverse = GetViewProjectionMatrixInverse();
+
+}
\ No newline at end of file
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
new file mode 100644
index 0000000000..88c72a2c10
--- /dev/null
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
@@ -0,0 +1,356 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+#import "Common/ShaderLib/Deferred.glsllib"
+#import "Common/ShaderLib/Parallax.glsllib"
+#import "Common/ShaderLib/Optics.glsllib"
+#import "Common/ShaderLib/BlinnPhongLighting.glsllib"
+#import "Common/ShaderLib/Lighting.glsllib"
+#import "Common/ShaderLib/PBR.glsllib"
+#import "Common/ShaderLib/ShadingModel.glsllib"
+// octahedral
+#import "Common/ShaderLib/Octahedral.glsllib"
+// skyLight and reflectionProbe
+#import "Common/ShaderLib/SkyLightReflectionProbe.glsllib"
+#if defined(USE_LIGHTS_CULL_MODE)
+ uniform vec2 g_ResolutionInverse;
+#else
+ varying vec2 texCoord;
+#endif
+
+varying mat4 viewProjectionMatrixInverse;
+uniform mat4 g_ViewMatrix;
+uniform vec3 g_CameraPosition;
+uniform vec4 g_AmbientLightColor;
+
+
+
+#if defined(USE_TEXTURE_PACK_MODE)
+ uniform int g_LightCount;
+ uniform sampler2D m_LightPackData1;
+ uniform sampler2D m_LightPackData2;
+ uniform sampler2D m_LightPackData3;
+#else
+ uniform vec4 g_LightData[NB_LIGHTS];
+#endif
+uniform int g_TileLightOffsetSize;
+uniform sampler2D m_TileLightDecode;
+uniform sampler2D m_TileLightIndex;
+
+void main(){
+ vec2 innerTexCoord;
+#if defined(USE_LIGHTS_CULL_MODE)
+ innerTexCoord = gl_FragCoord.xy * g_ResolutionInverse;
+#else
+ innerTexCoord = texCoord;
+#endif
+ // unpack GBuffer
+ vec4 shadingInfo = texture2D(Context_InGBuff2, innerTexCoord);
+ int shadingModelId = int(floor(shadingInfo.a));
+ // Perform corresponding pixel shading based on the shading model
+ if(IS_LIT(shadingModelId)){
+ // lit shading model
+ // todo:For now, use the big branch first, and extract the common parts later
+ if(shadingModelId == LEGACY_LIGHTING){
+ vec3 vPos = getPosition(innerTexCoord, viewProjectionMatrixInverse);
+ vec4 buff1 = texture2D(Context_InGBuff1, innerTexCoord);
+ vec4 diffuseColor = texture2D(Context_InGBuff0, innerTexCoord);
+ vec3 specularColor = floor(buff1.rgb) * 0.01f;
+ vec3 AmbientSum = min(fract(buff1.rgb) * 100.0f, vec3(1.0f)) * g_AmbientLightColor.rgb;
+ float Shininess = buff1.a;
+ float alpha = diffuseColor.a;
+ vec3 normal = texture2D(Context_InGBuff3, innerTexCoord).xyz;
+ vec3 viewDir = normalize(g_CameraPosition - vPos);
+
+
+ gl_FragColor.rgb = AmbientSum * diffuseColor.rgb;
+ gl_FragColor.a = alpha;
+ int lightNum = 0;
+ #if defined(USE_TEXTURE_PACK_MODE)
+ float lightTexSizeInv = 1.0f / (float(PACK_NB_LIGHTS) - 1.0f);
+ lightNum = g_LightCount;
+ #else
+ lightNum = NB_LIGHTS;
+ #endif
+
+ // Tile Based Shading
+ // get tile info
+ vec3 tile = texture2D(m_TileLightDecode, innerTexCoord).xyz;
+ int uoffset = int(tile.x);
+ int voffset = int(tile.z);
+ int count = int(tile.y);
+ if(count > 0){
+ int lightId;
+ float temp;
+ int offset;
+ // Normalize lightIndex sampling range to unit space
+ float uvSize = 1.0f / (g_TileLightOffsetSize - 1.0f);
+ vec2 lightUV;
+ vec2 lightDataUV;
+ for(int i = 0;i < count;){
+ temp = float(uoffset + i);
+ offset = 0;
+
+ if(temp >= g_TileLightOffsetSize){
+ temp -= g_TileLightOffsetSize;
+ offset++;
+ }
+ if(temp == g_TileLightOffsetSize){
+ temp = 0.0f;
+ }
+
+ // lightIndexUV
+ lightUV = vec2(temp * uvSize, float(voffset + offset) * uvSize);
+ lightId = int(texture2D(m_TileLightIndex, lightUV).x);
+ lightDataUV = vec2(float(lightId) * lightTexSizeInv, 0.0f);
+
+ #if defined(USE_TEXTURE_PACK_MODE)
+ vec4 lightColor = texture2D(m_LightPackData1, lightDataUV);
+ vec4 lightData1 = texture2D(m_LightPackData2, lightDataUV);
+ #else
+ vec4 lightColor = g_LightData[lightId*3];
+ vec4 lightData1 = g_LightData[lightId*3+1];
+ #endif
+ 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
+ #if defined(USE_TEXTURE_PACK_MODE)
+ spotFallOff = computeSpotFalloff(texture2D(m_LightPackData3, lightDataUV), lightVec);
+ #else
+ spotFallOff = computeSpotFalloff(g_LightData[lightId*3+2], lightVec);
+ #endif
+ #if __VERSION__ >= 110
+ }
+ #endif
+
+ #ifdef NORMALMAP
+ //Normal map -> lighting is computed in tangent space
+ lightDir.xyz = normalize(lightDir.xyz * tbnMat);
+ #else
+ //no Normal map -> lighting is computed in view space
+ lightDir.xyz = normalize(lightDir.xyz);
+ #endif
+
+ vec2 light = computeLighting(normal, viewDir, lightDir.xyz, lightDir.w * spotFallOff , Shininess);
+
+ // Workaround, since it is not possible to modify varying variables
+ // #ifdef USE_REFLECTION
+ // // Interpolate light specularity toward reflection color
+ // // Multiply result by specular map
+ // specularColor = mix(specularColor * light.y, refColor, refVec.w) * specularColor;
+ // light.y = 1.0;
+ // #endif
+ //
+ // #ifdef COLORRAMP
+ // diffuseColor.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb;
+ // specularColor.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb;
+ // light.xy = vec2(1.0);
+ // #endif
+
+ gl_FragColor.rgb += lightColor.rgb * diffuseColor.rgb * vec3(light.x) +
+ lightColor.rgb * specularColor.rgb * vec3(light.y);
+ #if defined(USE_TEXTURE_PACK_MODE)
+ i++;
+ #else
+ i++;
+ #endif
+ }
+ }
+// for( int i = 0;i < lightNum; ){
+// #if defined(USE_TEXTURE_PACK_MODE)
+// vec4 lightColor = texture2D(m_LightPackData1, vec2(i * lightTexSizeInv, 0));
+// vec4 lightData1 = texture2D(m_LightPackData2, vec2(i * lightTexSizeInv, 0));
+// #else
+// vec4 lightColor = g_LightData[i];
+// vec4 lightData1 = g_LightData[i+1];
+// #endif
+// 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
+// #if defined(USE_TEXTURE_PACK_MODE)
+// spotFallOff = computeSpotFalloff(texture2D(m_LightPackData3, vec2(i * lightTexSizeInv, 0)), lightVec);
+// #else
+// spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec);
+// #endif
+// #if __VERSION__ >= 110
+// }
+// #endif
+//
+// #ifdef NORMALMAP
+// //Normal map -> lighting is computed in tangent space
+// lightDir.xyz = normalize(lightDir.xyz * tbnMat);
+// #else
+// //no Normal map -> lighting is computed in view space
+// lightDir.xyz = normalize(lightDir.xyz);
+// #endif
+//
+// vec2 light = computeLighting(normal, viewDir, lightDir.xyz, lightDir.w * spotFallOff , Shininess);
+//
+// // Workaround, since it is not possible to modify varying variables
+// // #ifdef USE_REFLECTION
+// // // Interpolate light specularity toward reflection color
+// // // Multiply result by specular map
+// // specularColor = mix(specularColor * light.y, refColor, refVec.w) * specularColor;
+// // light.y = 1.0;
+// // #endif
+// //
+// // #ifdef COLORRAMP
+// // diffuseColor.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb;
+// // specularColor.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb;
+// // light.xy = vec2(1.0);
+// // #endif
+//
+// gl_FragColor.rgb += lightColor.rgb * diffuseColor.rgb * vec3(light.x) +
+// lightColor.rgb * specularColor.rgb * vec3(light.y);
+// #if defined(USE_TEXTURE_PACK_MODE)
+// i++;
+// #else
+// i+=3;
+// #endif
+// }
+ }
+ else if(shadingModelId == STANDARD_LIGHTING){
+ // todo:
+ vec3 vPos = getPosition(innerTexCoord, viewProjectionMatrixInverse);
+ vec4 buff0 = texture2D(Context_InGBuff0, innerTexCoord);
+ vec4 buff1 = texture2D(Context_InGBuff1, innerTexCoord);
+ vec3 emissive = shadingInfo.rgb;
+ vec3 diffuseColor = floor(buff0.rgb) * 0.01f;
+ vec3 specularColor = floor(buff1.rgb) * 0.01f;
+ vec3 ao = min(fract(buff0.rgb) * 10.0f, vec3(1.0f));
+ vec3 fZero = min(fract(buff1.rgb) * 10.0f, vec3(0.5f));
+ float Roughness = buff1.a;
+ float alpha = buff0.a;
+ vec4 n1n2 = texture2D(Context_InGBuff3, innerTexCoord);
+ vec3 normal = octDecode(n1n2.xy);
+ vec3 norm = octDecode(n1n2.zw);
+ vec3 viewDir = normalize(g_CameraPosition - vPos);
+
+ float ndotv = max( dot( normal, viewDir ),0.0);
+ int lightNum = 0;
+ #if defined(USE_TEXTURE_PACK_MODE)
+ float lightTexSizeInv = 1.0f / (float(PACK_NB_LIGHTS) - 1.0f);
+ lightNum = g_LightCount;
+ #else
+ lightNum = NB_LIGHTS;
+ #endif
+ gl_FragColor.rgb = vec3(0.0);
+ // Tile Based Shading
+ // get tile info
+ vec3 tile = texture2D(m_TileLightDecode, innerTexCoord).xyz;
+ int uoffset = int(tile.x);
+ int voffset = int(tile.z);
+ int count = int(tile.y);
+ if(count > 0){
+ int lightId;
+ float temp;
+ int offset;
+ // Normalize lightIndex sampling range to unit space
+ float uvSize = 1.0f / (g_TileLightOffsetSize - 1.0f);
+ vec2 lightUV;
+ vec2 lightDataUV;
+ for (int i = 0;i < count;){
+ temp = float(uoffset + i);
+ offset = 0;
+
+ if (temp >= g_TileLightOffsetSize){
+ temp -= g_TileLightOffsetSize;
+ offset++;
+ }
+ if (temp == g_TileLightOffsetSize){
+ temp = 0.0f;
+ }
+
+ // lightIndexUV
+ lightUV = vec2(temp * uvSize, float(voffset + offset) * uvSize);
+ lightId = int(texture2D(m_TileLightIndex, lightUV).x);
+ lightDataUV = vec2(float(lightId) * lightTexSizeInv, 0.0f);
+
+ #if defined(USE_TEXTURE_PACK_MODE)
+ vec4 lightColor = texture2D(m_LightPackData1, lightDataUV);
+ vec4 lightData1 = texture2D(m_LightPackData2, lightDataUV);
+ #else
+ vec4 lightColor = g_LightData[lightId*3];
+ vec4 lightData1 = g_LightData[lightId*3+1];
+ #endif
+ 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
+ #if defined(USE_TEXTURE_PACK_MODE)
+ spotFallOff = computeSpotFalloff(texture2D(m_LightPackData3, lightDataUV), lightVec);
+ #else
+ spotFallOff = computeSpotFalloff(g_LightData[lightId*3+2], lightVec);
+ #endif
+ #if __VERSION__ >= 110
+ }
+ #endif
+
+ #ifdef NORMALMAP
+ //Normal map -> lighting is computed in tangent space
+ lightDir.xyz = normalize(lightDir.xyz * tbnMat);
+ #else
+ //no Normal map -> lighting is computed in view space
+ lightDir.xyz = normalize(lightDir.xyz);
+ #endif
+
+ vec3 directDiffuse;
+ vec3 directSpecular;
+
+ float hdotv = PBR_ComputeDirectLight(normal, lightDir.xyz, viewDir,
+ lightColor.rgb, fZero, Roughness, ndotv,
+ directDiffuse, directSpecular);
+
+ vec3 directLighting = diffuseColor.rgb *directDiffuse + directSpecular;
+
+ // Workaround, since it is not possible to modify varying variables
+ // #ifdef USE_REFLECTION
+ // // Interpolate light specularity toward reflection color
+ // // Multiply result by specular map
+ // specularColor = mix(specularColor * light.y, refColor, refVec.w) * specularColor;
+ // light.y = 1.0;
+ // #endif
+ //
+ // #ifdef COLORRAMP
+ // diffuseColor.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb;
+ // specularColor.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb;
+ // light.xy = vec2(1.0);
+ // #endif
+
+ gl_FragColor.rgb += directLighting * spotFallOff;
+ #if defined(USE_TEXTURE_PACK_MODE)
+ i++;
+ #else
+ i++;
+ #endif
+ }
+ }
+ // skyLight and reflectionProbe
+ vec3 skyLightAndReflection = renderSkyLightAndReflectionProbes(viewDir, vPos, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao);
+ gl_FragColor.rgb += skyLightAndReflection;
+ gl_FragColor.rgb += emissive;
+ gl_FragColor.a = alpha;
+ }
+ else if(shadingModelId == SUBSURFACE_SCATTERING){
+ // todo:
+ }
+ }
+ else if(shadingModelId == UNLIT){
+ // todo:
+ }
+}
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md
new file mode 100644
index 0000000000..06a2047c4a
--- /dev/null
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md
@@ -0,0 +1,46 @@
+MaterialDef DeferredShading {
+
+ MaterialParameters {
+ // For instancing
+ Boolean UseInstancing
+ // UseLightsCull
+ Boolean UseLightsCullMode
+
+ // Context GBuffer Data
+ Texture2D Context_InGBuff0
+ Texture2D Context_InGBuff1
+ Texture2D Context_InGBuff2
+ Texture2D Context_InGBuff3
+ Texture2D Context_InGBuff4
+
+ // LightData
+ Texture2D LightPackData1
+ Texture2D LightPackData2
+ Texture2D LightPackData3
+
+ // TileInfo
+ Texture2D TileLightDecode
+ Texture2D TileLightIndex
+ }
+
+ Technique TileBasedDeferredPass{
+ Pipeline Deferred
+ LightMode TileBasedDeferredSinglePass
+
+ VertexShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/ShadingCommon/DeferredShading.vert
+ FragmentShader GLSL310 GLSL300 GLSL100 GLSL150: Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
+
+ WorldParameters {
+ CameraPosition
+ WorldViewProjectionMatrix
+ ViewProjectionMatrix
+ ResolutionInverse
+ }
+
+ Defines {
+ INSTANCING : UseInstancing
+ USE_LIGHTS_CULL_MODE : UseLightsCullMode
+ }
+ }
+
+}
diff --git a/jme3-core/src/main/resources/Common/ShaderLib/Deferred.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/Deferred.glsllib
new file mode 100644
index 0000000000..bc8c4cfa06
--- /dev/null
+++ b/jme3-core/src/main/resources/Common/ShaderLib/Deferred.glsllib
@@ -0,0 +1,65 @@
+#ifndef _JME_CONTEXT_
+#define _JME_CONTEXT_
+
+#if __VERSION__ >= 120
+layout(location = 0) out vec4 outColor0;
+layout(location = 1) out vec4 outColor1;
+layout(location = 2) out vec4 outColor2;
+layout(location = 3) out vec4 outColor3;
+layout(location = 4) out vec4 outColor4;
+#define Context_OutGBuff0 outColor0
+#define Context_OutGBuff1 outColor1
+#define Context_OutGBuff2 outColor2
+#define Context_OutGBuff3 outColor3
+#define Context_OutGBuff4 outColor4
+#else
+#define Context_OutGBuff0 gl_FragData[0]
+#define Context_OutGBuff1 gl_FragData[1]
+#define Context_OutGBuff2 gl_FragData[2]
+#define Context_OutGBuff3 gl_FragData[3]
+#define Context_OutGBuff4 gl_FragData[4]
+#endif
+
+
+uniform sampler2D m_Context_InGBuff0;
+uniform sampler2D m_Context_InGBuff1;
+uniform sampler2D m_Context_InGBuff2;
+uniform sampler2D m_Context_InGBuff3;
+uniform sampler2D m_Context_InGBuff4;
+#define Context_InGBuff0 m_Context_InGBuff0
+#define Context_InGBuff1 m_Context_InGBuff1
+#define Context_InGBuff2 m_Context_InGBuff2
+#define Context_InGBuff3 m_Context_InGBuff3
+#define Context_InGBuff4 m_Context_InGBuff4
+
+#endif
+#define GBUFFER_DEPTH Context_InGBuff4
+
+vec3 decodeNormal(in vec4 enc){
+ vec4 nn = enc * vec4(2.0,2.0,0.0,0.0) + vec4(-1.0,-1.0,1.0,-1.0);
+ float l = dot(nn.xyz, -nn.xyw);
+ nn.z = l;
+ nn.xy *= sqrt(l);
+ return nn.xyz * vec3(2.0) + vec3(0.0,0.0,-1.0);
+}
+
+vec3 getPosition(in vec2 texCoord, in float depth, in mat4 matrixInverse){
+ vec4 pos;
+ pos.xy = (texCoord * vec2(2.0)) - vec2(1.0);
+ pos.z = depth * 2.0 - 1.0;
+ pos.w = 1.0;
+ pos = matrixInverse * pos;
+ pos.xyz /= pos.w;
+ return pos.xyz;
+}
+
+vec3 getPosition(in vec2 texCoord, in mat4 matrixInverse){
+ float depth = texture2D(GBUFFER_DEPTH, texCoord).r;
+ vec4 pos;
+ pos.xy = (texCoord * vec2(2.0)) - vec2(1.0);
+ pos.z = depth * 2.0 - 1.0;
+ pos.w = 1.0;
+ pos = matrixInverse * pos;
+ pos.xyz /= pos.w;
+ return pos.xyz;
+}
\ No newline at end of file
diff --git a/jme3-core/src/main/resources/Common/ShaderLib/GLSLCompat.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/GLSLCompat.glsllib
index 77cb34c8c0..3bb8a0f629 100644
--- a/jme3-core/src/main/resources/Common/ShaderLib/GLSLCompat.glsllib
+++ b/jme3-core/src/main/resources/Common/ShaderLib/GLSLCompat.glsllib
@@ -1,15 +1,5 @@
-#ifdef FRAGMENT_SHADER
- precision highp float;
- precision highp int;
- precision highp sampler2DArray;
- precision highp sampler2DShadow;
- precision highp samplerCube;
- precision highp sampler3D;
- precision highp sampler2D;
- #if __VERSION__ >= 310
- precision highp sampler2DMS;
- #endif
-
+#if __VERSION__ >= 130
+#extension GL_ARB_explicit_attrib_location : enable
#endif
#if defined GL_ES
@@ -33,25 +23,11 @@
#endif
#if __VERSION__ >= 130
-
-#ifdef FRAGMENT_SHADER
- #ifdef GL_ES
- #ifdef BOUND_DRAW_BUFFER
- #for i=0..15 ( #if $i<=BOUND_DRAW_BUFFER $0 #endif )
- #if BOUND_DRAW_BUFFER == $i
- layout( location = $i ) out highp vec4 outFragColor;
- #else
- layout( location = $i ) out highp vec4 outNOP$i;
- #endif
- #endfor
- #else
- out highp vec4 outFragColor;
- #endif
- #else
- out vec4 outFragColor;
- #endif
+# ifdef GL_ES
+out highp vec4 outFragColor;
+# else
+out vec4 outFragColor;
#endif
-
# define texture1D texture
# define texture2D texture
# define texture3D texture
diff --git a/jme3-core/src/main/resources/Common/ShaderLib/Instancing.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/Instancing.glsllib
index 37c3a40cf2..bf3f6e2e3f 100644
--- a/jme3-core/src/main/resources/Common/ShaderLib/Instancing.glsllib
+++ b/jme3-core/src/main/resources/Common/ShaderLib/Instancing.glsllib
@@ -26,6 +26,13 @@ uniform mat4 g_WorldViewProjectionMatrix;
uniform mat4 g_ViewProjectionMatrix;
uniform mat3 g_NormalMatrix;
uniform mat3 g_WorldNormalMatrix;
+mat4 GetViewProjectionMatrixInverse(){
+ return inverse(g_ViewProjectionMatrix);
+}
+
+mat4 GetProjectionMatrixInverse(){
+ return inverse(g_ProjectionMatrix);
+}
#if defined INSTANCING
diff --git a/jme3-core/src/main/resources/Common/ShaderLib/Octahedral.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/Octahedral.glsllib
new file mode 100644
index 0000000000..5406c4029d
--- /dev/null
+++ b/jme3-core/src/main/resources/Common/ShaderLib/Octahedral.glsllib
@@ -0,0 +1,43 @@
+// -*- c++ -*-
+
+/** Efficient GPU implementation of the octahedral unit vector encoding from
+
+ Cigolle, Donow, Evangelakos, Mara, McGuire, Meyer,
+ A Survey of Efficient Representations for Independent Unit Vectors, Journal of Computer Graphics Techniques (JCGT), vol. 3, no. 2, 1-30, 2014
+
+ Available online http://jcgt.org/published/0003/02/01/
+*/
+#ifndef G3D_octahedral_glsl
+#define G3D_octahedral_glsl
+
+
+float signNotZero(float f){
+ return(f >= 0.0) ? 1.0 : -1.0;
+}
+vec2 signNotZero(vec2 v) {
+ return vec2(signNotZero(v.x), signNotZero(v.y));
+}
+
+/** Assumes that v is a unit vector. The result is an octahedral vector on the [-1, +1] square. */
+vec2 octEncode(in vec3 v) {
+ float l1norm = abs(v.x) + abs(v.y) + abs(v.z);
+ vec2 result = v.xy * (1.0 / l1norm);
+ if (v.z < 0.0) {
+ result = (1.0 - abs(result.yx)) * signNotZero(result.xy);
+ }
+ return result;
+}
+
+
+/** Returns a unit vector. Argument o is an octahedral vector packed via octEncode,
+ on the [-1, +1] square*/
+vec3 octDecode(vec2 o) {
+ vec3 v = vec3(o.x, o.y, 1.0 - abs(o.x) - abs(o.y));
+ if (v.z < 0.0) {
+ v.xy = (1.0 - abs(v.yx)) * signNotZero(v.xy);
+ }
+ return normalize(v);
+}
+
+
+#endif
diff --git a/jme3-core/src/main/resources/Common/ShaderLib/ShadingModel.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/ShadingModel.glsllib
new file mode 100644
index 0000000000..b12bfe685d
--- /dev/null
+++ b/jme3-core/src/main/resources/Common/ShaderLib/ShadingModel.glsllib
@@ -0,0 +1,18 @@
+// SHADING_MODEL
+// 0 is clearRT mask
+#define LEGACY_LIGHTING 1
+#define STANDARD_LIGHTING 2
+#define UNLIT 3
+#define SUBSURFACE_SCATTERING 4
+
+#define IS_LIT(SHADING_MODEL_ID) (SHADING_MODEL_ID == LEGACY_LIGHTING || SHADING_MODEL_ID == STANDARD_LIGHTING || SHADING_MODEL_ID == SUBSURFACE_SCATTERING)
+
+
+#ifdef USE_REFLECTION_PROBE
+ uniform vec3 m_FresnelParams;
+ vec4 computeProbeRef(in vec3 wPosition, in vec3 wNormal, in vec3 wViewDir, in float VdotN){
+ vec4 refVec;
+ refVec.xyz = reflect(wViewDir, wNormal);
+ refVec.w = m_FresnelParams.x + m_FresnelParams.y * pow(1.0 + VdotN, m_FresnelParams.z);
+ }
+#endif
\ No newline at end of file
diff --git a/jme3-core/src/main/resources/Common/ShaderLib/SkyLightReflectionProbe.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/SkyLightReflectionProbe.glsllib
new file mode 100644
index 0000000000..4063da45a7
--- /dev/null
+++ b/jme3-core/src/main/resources/Common/ShaderLib/SkyLightReflectionProbe.glsllib
@@ -0,0 +1,70 @@
+// BEGIN@JohnKkk,render skyLights and reflectionProbe
+// sky lights and reflection probes
+#if NB_SKY_LIGHT_AND_REFLECTION_PROBES >= 1
+uniform samplerCube g_ReflectionEnvMap;
+uniform vec3 g_ShCoeffs[9];
+uniform mat4 g_SkyLightData;
+#endif
+#if NB_SKY_LIGHT_AND_REFLECTION_PROBES >= 2
+uniform samplerCube g_ReflectionEnvMap2;
+uniform vec3 g_ShCoeffs2[9];
+uniform mat4 g_SkyLightData2;
+#endif
+#if NB_SKY_LIGHT_AND_REFLECTION_PROBES == 3
+uniform samplerCube g_ReflectionEnvMap3;
+uniform vec3 g_ShCoeffs3[9];
+uniform mat4 g_SkyLightData3;
+#endif
+vec3 renderSkyLightAndReflectionProbes(in vec3 viewDir, in vec3 wPosition, in vec3 normal, in vec3 norm, in float Roughness, in vec3 diffuseColor, in vec3 specularColor, in float ndotv, in vec3 ao){
+ vec3 result = vec3(0);
+ vec4 difColor = vec4(diffuseColor, 1.0f);
+ vec4 specColor = vec4(specularColor, 1.0f);
+ #if NB_SKY_LIGHT_AND_REFLECTION_PROBES >= 1
+ vec3 color1 = vec3(0.0);
+ vec3 color2 = vec3(0.0);
+ vec3 color3 = vec3(0.0);
+ float weight1 = 1.0;
+ float weight2 = 0.0;
+ float weight3 = 0.0;
+
+ float ndf = renderProbe(viewDir, wPosition, normal, norm, Roughness, difColor, specColor, ndotv, ao, g_SkyLightData, g_ShCoeffs, g_ReflectionEnvMap, color1);
+ #if NB_SKY_LIGHT_AND_REFLECTION_PROBES >= 2
+ float ndf2 = renderProbe(viewDir, wPosition, normal, norm, Roughness, difColor, specColor, ndotv, ao, g_SkyLightData2, g_ShCoeffs2, g_ReflectionEnvMap2, color2);
+ #endif
+ #if NB_SKY_LIGHT_AND_REFLECTION_PROBES == 3
+ float ndf3 = renderProbe(viewDir, wPosition, normal, norm, Roughness, difColor, specColor, ndotv, ao, g_SkyLightData3, g_ShCoeffs3, g_ReflectionEnvMap3, color3);
+ #endif
+
+ #if NB_SKY_LIGHT_AND_REFLECTION_PROBES >= 2
+ float invNdf = max(1.0 - ndf,0.0);
+ float invNdf2 = max(1.0 - ndf2,0.0);
+ float sumNdf = ndf + ndf2;
+ float sumInvNdf = invNdf + invNdf2;
+ #if NB_SKY_LIGHT_AND_REFLECTION_PROBES == 3
+ float invNdf3 = max(1.0 - ndf3,0.0);
+ sumNdf += ndf3;
+ sumInvNdf += invNdf3;
+ weight3 = ((1.0 - (ndf3 / sumNdf)) / (NB_PROBES - 1)) * (invNdf3 / sumInvNdf);
+ #endif
+
+ weight1 = ((1.0 - (ndf / sumNdf)) / (NB_PROBES - 1)) * (invNdf / sumInvNdf);
+ weight2 = ((1.0 - (ndf2 / sumNdf)) / (NB_PROBES - 1)) * (invNdf2 / sumInvNdf);
+
+ float weightSum = weight1 + weight2 + weight3;
+
+ weight1 /= weightSum;
+ weight2 /= weightSum;
+ weight3 /= weightSum;
+ #endif
+
+ #ifdef USE_AMBIENT_LIGHT
+ color1.rgb *= g_AmbientLightColor.rgb;
+ color2.rgb *= g_AmbientLightColor.rgb;
+ color3.rgb *= g_AmbientLightColor.rgb;
+ #endif
+ result.rgb += color1 * clamp(weight1,0.0,1.0) + color2 * clamp(weight2,0.0,1.0) + color3 * clamp(weight3,0.0,1.0);
+
+ #endif
+ return result;
+}
+// END@render skyLights and reflectionProbe
\ No newline at end of file
diff --git a/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java b/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java
index 0a0c0403c2..0fef61733e 100644
--- a/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java
+++ b/jme3-core/src/plugins/java/com/jme3/material/plugins/J3MLoader.java
@@ -64,7 +64,7 @@
public class J3MLoader implements AssetLoader {
private static final Logger logger = Logger.getLogger(J3MLoader.class.getName());
- // private ErrorLogger errors;
+ // private ErrorLogger errors;
private ShaderNodeLoaderDelegate nodesLoaderDelegate;
boolean isUseNodes = false;
int langSize = 0;
@@ -121,6 +121,17 @@ private void readShaderDefinition(Shader.ShaderType shaderType, String name, Str
}
}
+ // Pipeline
+ private void readPipeline(String statement) throws IOException{
+ String[] split = statement.split(whitespacePattern);
+ if (split.length != 2){
+ throw new IOException("Pipeline statement syntax incorrect");
+ }
+
+ TechniqueDef.Pipeline pl = TechniqueDef.Pipeline.valueOf(split[1]);
+ technique.setPipeline(pl);
+ }
+
// LightMode
private void readLightMode(String statement) throws IOException{
String[] split = statement.split(whitespacePattern);
@@ -131,15 +142,15 @@ private void readLightMode(String statement) throws IOException{
LightMode lm = LightMode.valueOf(split[1]);
technique.setLightMode(lm);
}
-
-
+
+
// LightMode
private void readLightSpace(String statement) throws IOException{
String[] split = statement.split(whitespacePattern);
if (split.length != 2){
throw new IOException("LightSpace statement syntax incorrect");
}
- TechniqueDef.LightSpace ls = TechniqueDef.LightSpace.valueOf(split[1]);
+ TechniqueDef.LightSpace ls = TechniqueDef.LightSpace.valueOf(split[1]);
technique.setLightSpace(ls);
}
@@ -299,7 +310,7 @@ private Texture parseTextureType(final VarType type, final String value) {
for (final TextureOptionValue textureOptionValue : textureOptionValues) {
textureOptionValue.applyToTexture(texture);
}
- }
+ }
return texture;
}
@@ -313,28 +324,28 @@ private Object readValue(final VarType type, final String value) throws IOExcept
if (split.length != 1){
throw new IOException("Float value parameter must have 1 entry: " + value);
}
- return Float.parseFloat(split[0]);
+ return Float.parseFloat(split[0]);
case Vector2:
if (split.length != 2){
throw new IOException("Vector2 value parameter must have 2 entries: " + value);
}
return new Vector2f(Float.parseFloat(split[0]),
- Float.parseFloat(split[1]));
+ Float.parseFloat(split[1]));
case Vector3:
if (split.length != 3){
throw new IOException("Vector3 value parameter must have 3 entries: " + value);
}
return new Vector3f(Float.parseFloat(split[0]),
- Float.parseFloat(split[1]),
- Float.parseFloat(split[2]));
+ Float.parseFloat(split[1]),
+ Float.parseFloat(split[2]));
case Vector4:
if (split.length != 4){
throw new IOException("Vector4 value parameter must have 4 entries: " + value);
}
return new ColorRGBA(Float.parseFloat(split[0]),
- Float.parseFloat(split[1]),
- Float.parseFloat(split[2]),
- Float.parseFloat(split[3]));
+ Float.parseFloat(split[1]),
+ Float.parseFloat(split[2]),
+ Float.parseFloat(split[3]));
case Int:
if (split.length != 1){
throw new IOException("Int value parameter must have 1 entry: " + value);
@@ -538,12 +549,12 @@ private void readDefine(String statement) throws IOException{
MatParam param = materialDef.getMaterialParam(paramName);
if (param == null) {
logger.log(Level.WARNING, "In technique ''{0}'':\n"
- + "Define ''{1}'' mapped to non-existent"
- + " material parameter ''{2}'', ignoring.",
+ + "Define ''{1}'' mapped to non-existent"
+ + " material parameter ''{2}'', ignoring.",
new Object[]{technique.getName(), defineName, paramName});
return;
}
-
+
VarType paramType = param.getVarType();
technique.addShaderParamDefine(paramName, paramType, defineName);
}else{
@@ -566,6 +577,8 @@ private void readTechniqueStatement(Statement statement) throws IOException{
split[0].equals("TessellationControlShader") ||
split[0].equals("TessellationEvaluationShader")) {
readShaderStatement(statement.getLine());
+ }else if(split[0].equals("Pipeline")){
+ readPipeline(statement.getLine());
}else if (split[0].equals("LightMode")){
readLightMode(statement.getLine());
}else if (split[0].equals("LightSpace")){
@@ -609,7 +622,7 @@ private void readTransparentStatement(String statement) throws IOException{
}
material.setTransparent(parseBoolean(split[1]));
}
-
+
private static String createShaderPrologue(List presetDefines) {
DefineList dl = new DefineList(presetDefines.size());
for (int i = 0; i < presetDefines.size(); i++) {
@@ -653,6 +666,12 @@ private void readTechnique(Statement techStat) throws IOException{
case SinglePass:
technique.setLogic(new SinglePassLightingLogic(technique));
break;
+ case DeferredSinglePass:
+ technique.setLogic(new DeferredSinglePassLightingLogic(technique));
+ break;
+ case TileBasedDeferredSinglePass:
+ technique.setLogic(new TileBasedDeferredSinglePassLightingLogic(technique));
+ break;
case StaticPass:
technique.setLogic(new StaticPassLightingLogic(technique));
break;
@@ -667,7 +686,7 @@ private void readTechnique(Statement techStat) throws IOException{
if(isUseNodes){
//used for caching later, the shader here is not a file.
-
+
// KIRILL 9/19/2015
// Not sure if this is needed anymore, since shader caching
// is now done by TechniqueDef.
From 8479dd3d06db7ceb556982dd1a434dede8219cb5 Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Mon, 9 Oct 2023 11:14:58 +0800
Subject: [PATCH 002/111] jme3-examples:Added a set of test cases for
renderPath.
---
.../renderpath/TestDeferredPBRShading.java | 180 ++++
.../renderpath/TestDeferredShading.java | 111 +++
.../TestDeferredShadingPathShadow.java | 116 +++
.../renderpath/TestRenderPathChanged.java | 110 +++
.../TestSimpleDeferredLighting.java | 768 ++++++++++++++++++
.../TestTileBasedDeferredShading.java | 101 +++
6 files changed, 1386 insertions(+)
create mode 100644 jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java
create mode 100644 jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java
create mode 100644 jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java
create mode 100644 jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathChanged.java
create mode 100644 jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java
create mode 100644 jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java
new file mode 100644
index 0000000000..c24ebb29d5
--- /dev/null
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredPBRShading.java
@@ -0,0 +1,180 @@
+package jme3test.renderpath;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.environment.EnvironmentCamera;
+import com.jme3.environment.LightProbeFactory;
+import com.jme3.environment.generation.JobProgressAdapter;
+import com.jme3.environment.util.EnvMapUtils;
+import com.jme3.environment.util.LightsDebugState;
+import com.jme3.input.ChaseCamera;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.LightProbe;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.ToneMapFilter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.texture.plugins.ktx.KTXLoader;
+import com.jme3.util.SkyFactory;
+import com.jme3.util.mikktspace.MikktspaceTangentGenerator;
+
+public class TestDeferredPBRShading extends SimpleApplication {
+ private DirectionalLight dl;
+
+ private float roughness = 0.0f;
+
+ private Node modelNode;
+ private int frame = 0;
+ private Material pbrMat;
+ private Geometry model;
+ private Node tex;
+ @Override
+ public void simpleInitApp() {
+ // Baking irradiance data requires the Forward path!
+ renderManager.setRenderPath(RenderManager.RenderPath.Forward);
+
+ roughness = 1.0f;
+ assetManager.registerLoader(KTXLoader.class, "ktx");
+
+ viewPort.setBackgroundColor(ColorRGBA.White);
+ modelNode = new Node("modelNode");
+ model = (Geometry) assetManager.loadModel("Models/Tank/tank.j3o");
+ MikktspaceTangentGenerator.generate(model);
+ modelNode.attachChild(model);
+
+ dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
+ rootNode.addLight(dl);
+ dl.setColor(ColorRGBA.White);
+ rootNode.attachChild(modelNode);
+
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+ int numSamples = context.getSettings().getSamples();
+ if (numSamples > 0) {
+ fpp.setNumSamples(numSamples);
+ }
+
+// fpp.addFilter(new FXAAFilter());
+ fpp.addFilter(new ToneMapFilter(Vector3f.UNIT_XYZ.mult(1.0f)));
+// fpp.addFilter(new SSAOFilter(0.5f, 3, 0.2f, 0.2f));
+ viewPort.addProcessor(fpp);
+
+ //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Sky_Cloudy.hdr", SkyFactory.EnvMapType.EquirectMap);
+ Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Path.hdr", SkyFactory.EnvMapType.EquirectMap);
+ //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", SkyFactory.EnvMapType.CubeMap);
+ //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/road.hdr", SkyFactory.EnvMapType.EquirectMap);
+ rootNode.attachChild(sky);
+
+ pbrMat = assetManager.loadMaterial("Models/Tank/tank.j3m");
+ model.setMaterial(pbrMat);
+
+
+ final EnvironmentCamera envCam = new EnvironmentCamera(256, new Vector3f(0, 3f, 0));
+ stateManager.attach(envCam);
+
+ LightsDebugState debugState = new LightsDebugState();
+ stateManager.attach(debugState);
+
+ ChaseCamera chaser = new ChaseCamera(cam, modelNode, inputManager);
+ chaser.setDragToRotate(true);
+ chaser.setMinVerticalRotation(-FastMath.HALF_PI);
+ chaser.setMaxDistance(1000);
+ chaser.setSmoothMotion(true);
+ chaser.setRotationSensitivity(10);
+ chaser.setZoomSensitivity(5);
+ flyCam.setEnabled(false);
+ //flyCam.setMoveSpeed(100);
+
+ inputManager.addListener(new ActionListener() {
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (name.equals("debug") && isPressed) {
+ if (tex == null) {
+ return;
+ }
+ if (tex.getParent() == null) {
+ guiNode.attachChild(tex);
+ } else {
+ tex.removeFromParent();
+ }
+ }
+
+ if (name.equals("rup") && isPressed) {
+ roughness = FastMath.clamp(roughness + 0.1f, 0.0f, 1.0f);
+ pbrMat.setFloat("Roughness", roughness);
+ }
+ if (name.equals("rdown") && isPressed) {
+ roughness = FastMath.clamp(roughness - 0.1f, 0.0f, 1.0f);
+ pbrMat.setFloat("Roughness", roughness);
+ }
+
+
+ if (name.equals("up") && isPressed) {
+ model.move(0, tpf * 100f, 0);
+ }
+
+ if (name.equals("down") && isPressed) {
+ model.move(0, -tpf * 100f, 0);
+ }
+ if (name.equals("left") && isPressed) {
+ model.move(0, 0, tpf * 100f);
+ }
+ if (name.equals("right") && isPressed) {
+ model.move(0, 0, -tpf * 100f);
+ }
+ if (name.equals("light") && isPressed) {
+ dl.setDirection(cam.getDirection().normalize());
+ }
+ }
+ }, "toggle", "light", "up", "down", "left", "right", "debug", "rup", "rdown");
+
+ inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_RETURN));
+ inputManager.addMapping("light", new KeyTrigger(KeyInput.KEY_F));
+ inputManager.addMapping("up", new KeyTrigger(KeyInput.KEY_UP));
+ inputManager.addMapping("down", new KeyTrigger(KeyInput.KEY_DOWN));
+ inputManager.addMapping("left", new KeyTrigger(KeyInput.KEY_LEFT));
+ inputManager.addMapping("right", new KeyTrigger(KeyInput.KEY_RIGHT));
+ inputManager.addMapping("debug", new KeyTrigger(KeyInput.KEY_D));
+ inputManager.addMapping("rup", new KeyTrigger(KeyInput.KEY_T));
+ inputManager.addMapping("rdown", new KeyTrigger(KeyInput.KEY_G));
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ frame++;
+
+ if (frame == 2) {
+ modelNode.removeFromParent();
+ final LightProbe probe = LightProbeFactory.makeProbe(stateManager.getState(EnvironmentCamera.class), rootNode, new JobProgressAdapter() {
+
+ @Override
+ public void done(LightProbe result) {
+ System.err.println("Done rendering env maps");
+ tex = EnvMapUtils.getCubeMapCrossDebugViewWithMipMaps(result.getPrefilteredEnvMap(), assetManager);
+ // Now, switching to the Deferred rendering path.
+ renderManager.setRenderPath(RenderManager.RenderPath.Deferred);
+ }
+ });
+ probe.getArea().setRadius(100);
+ rootNode.addLight(probe);
+ //getStateManager().getState(EnvironmentManager.class).addEnvProbe(probe);
+
+ }
+ if (frame > 10 && modelNode.getParent() == null) {
+ rootNode.attachChild(modelNode);
+ }
+ }
+
+ public static void main(String[] args) {
+ TestDeferredPBRShading testDeferredPBRShading = new TestDeferredPBRShading();
+ testDeferredPBRShading.start();
+ }
+}
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java
new file mode 100644
index 0000000000..a959f68375
--- /dev/null
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java
@@ -0,0 +1,111 @@
+package jme3test.renderpath;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.PointLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.BloomFilter;
+import com.jme3.post.filters.ToneMapFilter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.instancing.InstancedNode;
+import com.jme3.scene.shape.Quad;
+import com.jme3.scene.shape.Sphere;
+
+/**
+ * https://en.wikipedia.org/wiki/Deferred_shading/
+ * @author JohnKkk
+ */
+public class TestDeferredShading extends SimpleApplication {
+ private Material material;
+ @Override
+ public void simpleInitApp() {
+ // Test Forward↓
+// renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass);
+// renderManager.setSinglePassLightBatchSize(30);
+// renderManager.setRenderPath(RenderManager.RenderPath.Forward);
+ renderManager.setRenderPath(RenderManager.RenderPath.Deferred);
+ Quad quad = new Quad(15, 15);
+ Geometry geo = new Geometry("Floor", quad);
+ material = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ material.setFloat("Shininess", 25);
+ material.setColor("Ambient", ColorRGBA.White);
+ material.setColor("Diffuse", ColorRGBA.White);
+ material.setColor("Specular", ColorRGBA.White);
+ material.setBoolean("UseMaterialColors", true);
+ geo.setMaterial(material);
+ geo.rotate((float) Math.toRadians(-90), 0, 0);
+ geo.setLocalTranslation(-7, 0, -7);
+ rootNode.attachChild(geo);
+
+ Sphere sphere = new Sphere(15, 15, 0.1f);
+ Geometry sp = new Geometry("sp", sphere);
+ sp.setMaterial(material.clone());
+ sp.getMaterial().setBoolean("UseInstancing", true);
+ ColorRGBA colors[] = new ColorRGBA[]{
+ ColorRGBA.White,
+ ColorRGBA.Red,
+ ColorRGBA.Blue,
+ ColorRGBA.Green,
+ ColorRGBA.Yellow,
+ ColorRGBA.Orange,
+ ColorRGBA.Brown,
+ };
+
+ InstancedNode instancedNode = new InstancedNode("sp");
+ for(int i = 0;i < 1000;i++){
+ PointLight pl = new PointLight();
+ pl.setColor(colors[i % colors.length]);
+ pl.setPosition(new Vector3f(FastMath.nextRandomFloat(-5.0f, 5.0f), 0.1f, FastMath.nextRandomFloat(-20.0f, -10.0f)));
+// pl.setPosition(new Vector3f(0, 1, 0));
+ pl.setRadius(1.0f);
+ rootNode.addLight(pl);
+ Geometry g = sp.clone(false);
+// g.getMaterial().setColor("Ambient", ColorRGBA.Gray);
+// g.getMaterial().setColor("Diffuse", colors[i % colors.length]);
+ g.setLocalTranslation(pl.getPosition());
+ instancedNode.attachChild(g);
+ }
+ instancedNode.instance();
+ rootNode.attachChild(instancedNode);
+
+
+// AmbientLight ambientLight = new AmbientLight(new ColorRGBA(0.15f, 0.15f, 0.15f, 1.0f));
+// rootNode.addLight(ambientLight);
+// DirectionalLight sun = new DirectionalLight();
+// sun.setDirection((new Vector3f(-0.5f, -0.5f, -0.5f)).normalizeLocal());
+// sun.setColor(ColorRGBA.Gray);
+// rootNode.addLight(sun);
+
+
+ cam.setLocation(new Vector3f(0, 2, 0));
+ cam.lookAtDirection(Vector3f.UNIT_Z.negate(), Vector3f.UNIT_Y);
+ flyCam.setMoveSpeed(10.0f);
+
+
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+ int numSamples = context.getSettings().getSamples();
+ if (numSamples > 0) {
+ fpp.setNumSamples(numSamples);
+ }
+
+ BloomFilter bloom=new BloomFilter();
+ bloom.setDownSamplingFactor(1);
+ bloom.setBlurScale(1.1f);
+ bloom.setExposurePower(1.30f);
+ bloom.setExposureCutOff(0.3f);
+ bloom.setBloomIntensity(1.15f);
+ fpp.addFilter(bloom);
+
+ fpp.addFilter(new ToneMapFilter(Vector3f.UNIT_XYZ.mult(2.5f)));
+ viewPort.addProcessor(fpp);
+ }
+
+ public static void main(String[] args) {
+ TestDeferredShading testTileBasedDeferredShading = new TestDeferredShading();
+ testTileBasedDeferredShading.start();
+ }
+}
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java
new file mode 100644
index 0000000000..a22da79b91
--- /dev/null
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShadingPathShadow.java
@@ -0,0 +1,116 @@
+package jme3test.renderpath;
+
+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.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.shape.Quad;
+import com.jme3.shadow.DirectionalLightShadowFilter;
+
+/**
+ * Under the deferred rendering path, only screen space post processing shadows can be used.
+ * @author JohnKkk
+ */
+public class TestDeferredShadingPathShadow extends SimpleApplication implements ActionListener {
+ private RenderManager.RenderPath currentRenderPath;
+ private BitmapText hitText;
+
+ private void makeHudText() {
+ guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
+ hitText = new BitmapText(guiFont, false);
+ hitText.setSize(guiFont.getCharSet().getRenderedSize());
+ hitText.setText("RendererPath : "+ currentRenderPath.getInfo());
+ hitText.setLocalTranslation(0, cam.getHeight(), 0);
+ guiNode.attachChild(hitText);
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Material boxMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ Node tank = (Node) assetManager.loadModel("Models/HoverTank/Tank2.mesh.xml");
+ tank.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
+ tank.setLocalScale(0.3f);
+ rootNode.attachChild(tank);
+
+ Quad plane = new Quad(10, 10);
+ Geometry planeGeo = new Geometry("Plane", plane);
+ planeGeo.setShadowMode(RenderQueue.ShadowMode.Receive);
+ planeGeo.rotate(-45, 0, 0);
+ planeGeo.setLocalTranslation(-5, -5, 0);
+ Material planeMat = boxMat.clone();
+ planeMat.setBoolean("UseMaterialColors", true);
+ planeMat.setColor("Ambient", ColorRGBA.White);
+ planeMat.setColor("Diffuse", ColorRGBA.Gray);
+ planeGeo.setMaterial(planeMat);
+ rootNode.attachChild(planeGeo);
+
+
+ DirectionalLight sun = new DirectionalLight();
+ sun.setDirection((new Vector3f(-0.5f, -0.5f, -0.5f)).normalizeLocal());
+ sun.setColor(ColorRGBA.White);
+ rootNode.addLight(sun);
+ DirectionalLightShadowFilter dlsf = new DirectionalLightShadowFilter(assetManager, 1024, 1);
+ dlsf.setLight(sun);
+
+ sun = new DirectionalLight();
+ sun.setDirection((new Vector3f(0.5f, -0.5f, -0.5f)).normalizeLocal());
+ sun.setColor(ColorRGBA.White);
+ rootNode.addLight(sun);
+ DirectionalLightShadowFilter dlsf2 = new DirectionalLightShadowFilter(assetManager, 1024, 1);
+ dlsf2.setLight(sun);
+
+ sun = new DirectionalLight();
+ sun.setDirection((new Vector3f(0.0f, -0.5f, -0.5f)).normalizeLocal());
+ sun.setColor(ColorRGBA.White);
+ rootNode.addLight(sun);
+ DirectionalLightShadowFilter dlsf3 = new DirectionalLightShadowFilter(assetManager, 1024, 1);
+ dlsf3.setLight(sun);
+
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+ fpp.addFilter(dlsf);
+ fpp.addFilter(dlsf2);
+ fpp.addFilter(dlsf3);
+ viewPort.addProcessor(fpp);
+
+ inputManager.addListener(this, "toggleRenderPath");
+ inputManager.addMapping("toggleRenderPath", new KeyTrigger(KeyInput.KEY_SPACE));
+
+ currentRenderPath = RenderManager.RenderPath.Forward;
+ renderManager.setRenderPath(currentRenderPath);
+ makeHudText();
+
+ flyCam.setMoveSpeed(20.0f);
+ }
+
+ public static void main(String[] args) {
+ TestDeferredShadingPathShadow testDeferredShadingPathShadow = new TestDeferredShadingPathShadow();
+ testDeferredShadingPathShadow.start();
+ }
+
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if(name.equals("toggleRenderPath") && !isPressed){
+ if(currentRenderPath == RenderManager.RenderPath.Deferred){
+ currentRenderPath = RenderManager.RenderPath.TiledDeferred;
+ }
+ else if(currentRenderPath == RenderManager.RenderPath.TiledDeferred){
+ currentRenderPath = RenderManager.RenderPath.Forward;
+ }
+ else{
+ currentRenderPath = RenderManager.RenderPath.Deferred;
+ }
+ renderManager.setRenderPath(currentRenderPath);
+ hitText.setText("RendererPath : "+ currentRenderPath.getInfo());
+ }
+ }
+}
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathChanged.java b/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathChanged.java
new file mode 100644
index 0000000000..68fb71f65c
--- /dev/null
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathChanged.java
@@ -0,0 +1,110 @@
+package jme3test.renderpath;
+
+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.Light;
+import com.jme3.light.LightList;
+import com.jme3.light.PointLight;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.RenderManager;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+
+/**
+ * This demonstrates how to switch the rendering path at runtime.
+ * @author JohnKkk
+ */
+public class TestRenderPathChanged extends SimpleApplication implements ActionListener {
+ private RenderManager.RenderPath currentRenderPath;
+ private BitmapText hitText;
+
+ private void makeHudText() {
+ guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
+ hitText = new BitmapText(guiFont, false);
+ hitText.setSize(guiFont.getCharSet().getRenderedSize());
+ hitText.setText("RendererPath : "+ currentRenderPath.getInfo());
+ hitText.setLocalTranslation(0, cam.getHeight(), 0);
+ guiNode.attachChild(hitText);
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Node scene = (Node) assetManager.loadModel("Scenes/ManyLights/Main.scene");
+ rootNode.attachChild(scene);
+ Node n = (Node) rootNode.getChild(0);
+ final LightList lightList = n.getWorldLightList();
+ final Geometry g = (Geometry) n.getChild("Grid-geom-1");
+
+ g.getMaterial().setColor("Ambient", new ColorRGBA(0.2f, 0.2f, 0.2f, 1f));
+ g.getMaterial().setBoolean("VertexLighting", false);
+
+ int nb = 0;
+ for (Light light : lightList) {
+ nb++;
+ PointLight p = (PointLight) light;
+ if (nb > 60) {
+ n.removeLight(light);
+ } else {
+ int rand = FastMath.nextRandomInt(0, 3);
+ switch (rand) {
+ case 0:
+ light.setColor(ColorRGBA.Red);
+ break;
+ case 1:
+ light.setColor(ColorRGBA.Yellow);
+ break;
+ case 2:
+ light.setColor(ColorRGBA.Green);
+ break;
+ case 3:
+ light.setColor(ColorRGBA.Orange);
+ break;
+ }
+ }
+ }
+
+ cam.setLocation(new Vector3f(-180.61f, 64, 7.657533f));
+ cam.lookAtDirection(new Vector3f(0.93f, -0.344f, 0.044f), Vector3f.UNIT_Y);
+
+ cam.setLocation(new Vector3f(-26.85569f, 15.701239f, -19.206047f));
+ cam.lookAtDirection(new Vector3f(0.13871355f, -0.6151029f, 0.7761488f), Vector3f.UNIT_Y);
+
+
+ inputManager.addListener(this, "toggleRenderPath");
+ inputManager.addMapping("toggleRenderPath", new KeyTrigger(KeyInput.KEY_SPACE));
+
+ // set RenderPath
+ currentRenderPath = RenderManager.RenderPath.Forward;
+ renderManager.setRenderPath(currentRenderPath);
+ makeHudText();
+
+ flyCam.setMoveSpeed(20.0f);
+ }
+
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if(name.equals("toggleRenderPath") && !isPressed){
+ if(currentRenderPath == RenderManager.RenderPath.Deferred){
+ currentRenderPath = RenderManager.RenderPath.TiledDeferred;
+ }
+ else if(currentRenderPath == RenderManager.RenderPath.TiledDeferred){
+ currentRenderPath = RenderManager.RenderPath.Forward;
+ }
+ else{
+ currentRenderPath = RenderManager.RenderPath.Deferred;
+ }
+ renderManager.setRenderPath(currentRenderPath);
+ hitText.setText("RendererPath : "+ currentRenderPath.getInfo());
+ }
+ }
+
+ public static void main(String[] args) {
+ TestRenderPathChanged testRenderPathChanged = new TestRenderPathChanged();
+ testRenderPathChanged.start();
+ }
+}
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java
new file mode 100644
index 0000000000..8d35e523dc
--- /dev/null
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TestSimpleDeferredLighting.java
@@ -0,0 +1,768 @@
+/*
+ * Copyright (c) 2009-2021 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.renderpath;
+
+import com.jme3.app.ChaseCameraAppState;
+import com.jme3.app.SimpleApplication;
+import com.jme3.asset.TextureKey;
+import com.jme3.environment.EnvironmentCamera;
+import com.jme3.environment.LightProbeFactory;
+import com.jme3.environment.generation.JobProgressAdapter;
+import com.jme3.environment.util.EnvMapUtils;
+import com.jme3.environment.util.LightsDebugState;
+import com.jme3.font.BitmapText;
+import com.jme3.input.ChaseCamera;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.AnalogListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.light.*;
+import com.jme3.material.Material;
+import com.jme3.math.*;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.ToneMapFilter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Mesh;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.instancing.InstancedGeometry;
+import com.jme3.scene.shape.Quad;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.shadow.DirectionalLightShadowFilter;
+import com.jme3.system.AppSettings;
+import com.jme3.texture.Texture;
+import com.jme3.texture.plugins.ktx.KTXLoader;
+import com.jme3.util.SkyFactory;
+import com.jme3.util.TangentBinormalGenerator;
+import com.jme3.util.mikktspace.MikktspaceTangentGenerator;
+
+public class TestSimpleDeferredLighting extends SimpleApplication implements ActionListener {
+ private RenderManager.RenderPath currentRenderPath;
+ private boolean bUseFramegraph = true;
+ private Material mat;
+ private BitmapText hitText;
+
+ private int sceneId;
+
+ private float angle;
+ private float angles[];
+ private PointLight pl;
+ private PointLight pls[];
+ private Spatial lightMdl;
+ private Geometry lightMdls[];
+
+ private final Vector3f lightDir = new Vector3f(-1, -1, .5f).normalizeLocal();
+ private float parallaxHeight = 0.05f;
+ private boolean steep = false;
+ private InstancedGeometry instancedGeometry;
+ private DirectionalLight dl;
+
+ private float roughness = 0.0f;
+
+ private Node modelNode;
+ private int frame = 0;
+ private Material pbrMat;
+ private Geometry model;
+ private Node tex;
+
+ public static void main(String[] args){
+ TestSimpleDeferredLighting app = new TestSimpleDeferredLighting();
+ AppSettings appSettings = new AppSettings(true);
+ appSettings.setRenderer(AppSettings.LWJGL_OPENGL40);
+ app.setSettings(appSettings);
+ app.start();
+ }
+ private void testScene1(){
+ sceneId = 0;
+ Geometry teapot = (Geometry) assetManager.loadModel("Models/Teapot/Teapot.obj");
+ TangentBinormalGenerator.generate(teapot.getMesh(), true);
+
+ teapot.setLocalScale(2f);
+ renderManager.setSinglePassLightBatchSize(1);
+ mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+// m_currentTechnique = TechniqueDef.DEFAULT_TECHNIQUE_NAME;
+// mat.selectTechnique(m_currentTechnique, getRenderManager());
+// mat.selectTechnique("GBuf");
+// System.out.println("tech:" + mat.getMaterialDef().getTechniqueDefsNames().toString());
+ mat.setFloat("Shininess", 25);
+// mat.setBoolean("UseMaterialColors", true);
+ cam.setLocation(new Vector3f(0.015041917f, 0.4572918f, 5.2874837f));
+ cam.setRotation(new Quaternion(-1.8875003E-4f, 0.99882424f, 0.04832061f, 0.0039016632f));
+
+// mat.setTexture("ColorRamp", assetManager.loadTexture("Textures/ColorRamp/cloudy.png"));
+//
+// mat.setBoolean("VTangent", true);
+// mat.setBoolean("Minnaert", true);
+// mat.setBoolean("WardIso", true);
+// mat.setBoolean("VertexLighting", true);
+// mat.setBoolean("LowQuality", true);
+// mat.setBoolean("HighQuality", true);
+
+ mat.setColor("Ambient", ColorRGBA.Black);
+ mat.setColor("Diffuse", ColorRGBA.Gray);
+ mat.setColor("Specular", ColorRGBA.Gray);
+
+ teapot.setMaterial(mat);
+ rootNode.attachChild(teapot);
+
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
+ dl.setColor(ColorRGBA.White);
+ rootNode.addLight(dl);
+ }
+ private void testScene2(){
+ sceneId = 1;
+ Sphere sphMesh = new Sphere(32, 32, 1);
+ sphMesh.setTextureMode(Sphere.TextureMode.Projected);
+ sphMesh.updateGeometry(32, 32, 1, false, false);
+ TangentBinormalGenerator.generate(sphMesh);
+
+ Geometry sphere = new Geometry("Rock Ball", sphMesh);
+ mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");
+// m_currentTechnique = TechniqueDef.DEFAULT_TECHNIQUE_NAME;
+// mat.selectTechnique(m_currentTechnique, getRenderManager());
+ sphere.setMaterial(mat);
+ rootNode.attachChild(sphere);
+
+ lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));
+ lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ rootNode.attachChild(lightMdl);
+
+ pl = new PointLight();
+ pl.setColor(ColorRGBA.White);
+ pl.setPosition(new Vector3f(0f, 0f, 4f));
+ rootNode.addLight(pl);
+ }
+ private void testScene3(){
+ renderManager.setSinglePassLightBatchSize(300);
+ sceneId = 2;
+ Node tank = (Node) assetManager.loadModel("Models/HoverTank/Tank2.mesh.xml");
+ rootNode.attachChild(tank);
+
+
+
+ pls = new PointLight[2];
+ angles = new float[pls.length];
+ ColorRGBA colors[] = new ColorRGBA[]{
+ ColorRGBA.White,
+ ColorRGBA.Red,
+ ColorRGBA.Blue,
+ ColorRGBA.Green,
+ ColorRGBA.Yellow,
+ ColorRGBA.Orange,
+ ColorRGBA.Brown,
+ };
+ Material pml = assetManager.loadMaterial("Common/Materials/RedColor.j3m");
+ lightMdls = new Geometry[pls.length];
+ for(int i = 0;i < pls.length;i++){
+ pls[i] = new PointLight();
+ pls[i].setColor(colors[pls.length % colors.length]);
+ pls[i].setRadius(FastMath.nextRandomFloat(1.0f, 2.0f));
+ pls[i].setPosition(new Vector3f(FastMath.nextRandomFloat(-1.0f, 1.0f), FastMath.nextRandomFloat(-1.0f, 1.0f), FastMath.nextRandomFloat(-1.0f, 1.0f)));
+ rootNode.addLight(pls[i]);
+
+ lightMdls[i] = new Geometry("Light", new Sphere(10, 10, 0.02f));
+ lightMdls[i].setMaterial(pml);
+ lightMdls[i].getMesh().setStatic();
+ rootNode.attachChild(lightMdls[i]);
+ }
+
+// DirectionalLight dl = new DirectionalLight();
+// dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
+// dl.setColor(ColorRGBA.Green);
+// rootNode.addLight(dl);
+ }
+ public Geometry putShape(Mesh shape, ColorRGBA color, float lineWidth){
+ Geometry g = new Geometry("shape", shape);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.getAdditionalRenderState().setWireframe(true);
+ mat.getAdditionalRenderState().setLineWidth(lineWidth);
+ mat.setColor("Color", color);
+ g.setMaterial(mat);
+ rootNode.attachChild(g);
+ return g;
+ }
+ private void testScene4(){
+ renderManager.setSinglePassLightBatchSize(300);
+ sceneId = 3;
+ Node tank = (Node) assetManager.loadModel("Models/HoverTank/Tank2.mesh.xml");
+ rootNode.attachChild(tank);
+
+ ColorRGBA colors[] = new ColorRGBA[]{
+ ColorRGBA.White,
+ ColorRGBA.Red,
+ ColorRGBA.Blue,
+ ColorRGBA.Green,
+ ColorRGBA.Yellow,
+ ColorRGBA.Orange,
+ ColorRGBA.Brown,
+ };
+ PointLight p1 = new PointLight(new Vector3f(0, 1, 0), ColorRGBA.White);
+ PointLight p2 = new PointLight(new Vector3f(1, 0, 0), ColorRGBA.Green);
+ p1.setRadius(10);
+ p2.setRadius(10);
+ rootNode.addLight(p1);
+ rootNode.addLight(p2);
+
+// Geometry g = putShape(new WireSphere(1), ColorRGBA.Yellow, 1);
+// g.setLocalTranslation(p1.getPosition());
+// g.setLocalScale(p1.getRadius() * 0.5f);
+//
+// g = putShape(new WireSphere(1), ColorRGBA.Yellow, 1);
+// g.setLocalTranslation(p2.getPosition());
+// g.setLocalScale(p2.getRadius());
+
+// DirectionalLight dl = new DirectionalLight();
+// dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
+// dl.setColor(ColorRGBA.White);
+// rootNode.addLight(dl);
+ }
+ private void testScene5(){
+ sceneId = 4;
+ // setupLighting
+ DirectionalLight dl = new DirectionalLight();
+ dl.setDirection(lightDir);
+ dl.setColor(new ColorRGBA(.9f, .9f, .9f, 1));
+ rootNode.addLight(dl);
+ // setupSkyBox
+ rootNode.attachChild(SkyFactory.createSky(assetManager, "Scenes/Beach/FullskiesSunset0068.dds", SkyFactory.EnvMapType.CubeMap));
+ // setupFloor
+ mat = assetManager.loadMaterial("Textures/Terrain/BrickWall/BrickWall.j3m");
+
+ Node floorGeom = new Node("floorGeom");
+ Quad q = new Quad(100, 100);
+ q.scaleTextureCoordinates(new Vector2f(10, 10));
+ Geometry g = new Geometry("geom", q);
+ g.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
+ floorGeom.attachChild(g);
+
+
+ TangentBinormalGenerator.generate(floorGeom);
+ floorGeom.setLocalTranslation(-50, 22, 60);
+ //floorGeom.setLocalScale(100);
+
+ floorGeom.setMaterial(mat);
+ rootNode.attachChild(floorGeom);
+ // setupSignpost
+ Spatial signpost = assetManager.loadModel("Models/Sign Post/Sign Post.mesh.xml");
+ Material matSp = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m");
+ TangentBinormalGenerator.generate(signpost);
+ signpost.setMaterial(matSp);
+ signpost.rotate(0, FastMath.HALF_PI, 0);
+ signpost.setLocalTranslation(12, 23.5f, 30);
+ signpost.setLocalScale(4);
+ signpost.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
+ // other
+ rootNode.attachChild(signpost);
+ cam.setLocation(new Vector3f(-15.445636f, 30.162927f, 60.252777f));
+ cam.setRotation(new Quaternion(0.05173137f, 0.92363626f, -0.13454558f, 0.35513034f));
+ flyCam.setMoveSpeed(30);
+ inputManager.addListener(new AnalogListener() {
+
+ @Override
+ public void onAnalog(String name, float value, float tpf) {
+ if ("heightUP".equals(name)) {
+ parallaxHeight += 0.01;
+ mat.setFloat("ParallaxHeight", parallaxHeight);
+ }
+ if ("heightDown".equals(name)) {
+ parallaxHeight -= 0.01;
+ parallaxHeight = Math.max(parallaxHeight, 0);
+ mat.setFloat("ParallaxHeight", parallaxHeight);
+ }
+
+ }
+ }, "heightUP", "heightDown");
+ inputManager.addMapping("heightUP", new KeyTrigger(KeyInput.KEY_I));
+ inputManager.addMapping("heightDown", new KeyTrigger(KeyInput.KEY_K));
+
+ inputManager.addListener(new ActionListener() {
+
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (isPressed && "toggleSteep".equals(name)) {
+ steep = !steep;
+ mat.setBoolean("SteepParallax", steep);
+ }
+ }
+ }, "toggleSteep");
+ inputManager.addMapping("toggleSteep", new KeyTrigger(KeyInput.KEY_O));
+ }
+ private void testScene6(){
+ sceneId = 6;
+ final Node buggy = (Node) assetManager.loadModel("Models/Buggy/Buggy.j3o");
+
+ TextureKey key = new TextureKey("Textures/Sky/Bright/BrightSky.dds", true);
+ key.setGenerateMips(true);
+ key.setTextureTypeHint(Texture.Type.CubeMap);
+ final Texture tex = assetManager.loadTexture(key);
+
+ for (Spatial geom : buggy.getChildren()) {
+ if (geom instanceof Geometry) {
+ Material m = ((Geometry) geom).getMaterial();
+ m.setTexture("EnvMap", tex);
+ m.setVector3("FresnelParams", new Vector3f(0.05f, 0.18f, 0.11f));
+ }
+ }
+
+ flyCam.setEnabled(false);
+
+ ChaseCamera chaseCam = new ChaseCamera(cam, inputManager);
+ chaseCam.setLookAtOffset(new Vector3f(0,0.5f,-1.0f));
+ buggy.addControl(chaseCam);
+ rootNode.attachChild(buggy);
+ rootNode.attachChild(SkyFactory.createSky(assetManager, tex,
+ SkyFactory.EnvMapType.CubeMap));
+
+ DirectionalLight l = new DirectionalLight();
+ l.setDirection(new Vector3f(0, -1, -1));
+ rootNode.addLight(l);
+ }
+ private void testScene7(){
+ sceneId = 6;
+ Node scene = (Node) assetManager.loadModel("Scenes/ManyLights/Main.scene");
+ rootNode.attachChild(scene);
+ Node n = (Node) rootNode.getChild(0);
+ final LightList lightList = n.getWorldLightList();
+ final Geometry g = (Geometry) n.getChild("Grid-geom-1");
+
+ g.getMaterial().setColor("Ambient", new ColorRGBA(0.2f, 0.2f, 0.2f, 1f));
+ g.getMaterial().setBoolean("VertexLighting", false);
+
+ /* A colored lit cube. Needs light source! */
+// Geometry boxGeo = new Geometry("shape", new Box(1, 1, 1));
+// Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+// mat.getAdditionalRenderState().setWireframe(true);
+// mat.setColor("Color", ColorRGBA.Green);
+// mat.setBoolean("UseInstancing", true);
+// boxGeo.setMaterial(mat);
+//
+// InstancedNode instancedNode = new InstancedNode("instanced_node");
+// n.attachChild(instancedNode);
+ int nb = 0;
+ for (Light light : lightList) {
+ nb++;
+ PointLight p = (PointLight) light;
+ if (nb > 60) {
+ n.removeLight(light);
+ } else {
+ int rand = FastMath.nextRandomInt(0, 3);
+ switch (rand) {
+ case 0:
+ light.setColor(ColorRGBA.Red);
+ break;
+ case 1:
+ light.setColor(ColorRGBA.Yellow);
+ break;
+ case 2:
+ light.setColor(ColorRGBA.Green);
+ break;
+ case 3:
+ light.setColor(ColorRGBA.Orange);
+ break;
+ }
+ }
+// Geometry b = boxGeo.clone(false);
+// instancedNode.attachChild(b);
+// b.setLocalTranslation(p.getPosition().x, p.getPosition().y, p.getPosition().z);
+// b.setLocalScale(p.getRadius() * 0.5f);
+
+ }
+// instancedNode.instance();
+// for(int i = 0,num = instancedNode.getChildren().size();i < num;i++){
+// if(instancedNode.getChild(i) instanceof InstancedGeometry){
+// instancedGeometry = (InstancedGeometry)instancedNode.getChild(i);
+// instancedGeometry.setForceNumVisibleInstances(2);
+// }
+// }
+
+
+// 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(-180.61f, 64, 7.657533f));
+ cam.lookAtDirection(new Vector3f(0.93f, -0.344f, 0.044f), Vector3f.UNIT_Y);
+
+ cam.setLocation(new Vector3f(-26.85569f, 15.701239f, -19.206047f));
+ cam.lookAtDirection(new Vector3f(0.13871355f, -0.6151029f, 0.7761488f), Vector3f.UNIT_Y);
+ }
+ private void testScene8(){
+ Quad quadMesh = new Quad(512,512);
+ Geometry quad = new Geometry("Quad", quadMesh);
+ quad.setQueueBucket(RenderQueue.Bucket.Opaque);
+
+ mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.setTexture("ColorMap", assetManager.loadTexture("Textures/ColoredTex/Monkey.png"));
+ quad.setMaterial(mat);
+
+ rootNode.attachChild(quad);
+ }
+ private void testScene9(){
+ viewPort.setBackgroundColor(ColorRGBA.Black);
+
+ dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
+ rootNode.addLight(dl);
+ dl.setColor(ColorRGBA.White);
+
+ ChaseCameraAppState chaser = new ChaseCameraAppState();
+ chaser.setDragToRotate(true);
+ chaser.setMinVerticalRotation(-FastMath.HALF_PI);
+ chaser.setMaxDistance(1000);
+ chaser.setInvertVerticalAxis(true);
+ getStateManager().attach(chaser);
+ chaser.setTarget(rootNode);
+ flyCam.setEnabled(false);
+
+ Geometry sphere = new Geometry("sphere", new Sphere(32, 32, 1));
+ final Material m = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md");
+ m.setColor("BaseColor", ColorRGBA.Black);
+ m.setFloat("Metallic", 0f);
+ m.setFloat("Roughness", roughness);
+ sphere.setMaterial(m);
+ rootNode.attachChild(sphere);
+
+ inputManager.addListener(new ActionListener() {
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+
+ if (name.equals("rup") && isPressed) {
+ roughness = FastMath.clamp(roughness + 0.1f, 0.0f, 1.0f);
+ m.setFloat("Roughness", roughness);
+ }
+ if (name.equals("rdown") && isPressed) {
+ roughness = FastMath.clamp(roughness - 0.1f, 0.0f, 1.0f);
+ m.setFloat("Roughness", roughness);
+ }
+
+ if (name.equals("light") && isPressed) {
+ dl.setDirection(cam.getDirection().normalize());
+ }
+ }
+ }, "light", "rup", "rdown");
+
+
+ inputManager.addMapping("light", new KeyTrigger(KeyInput.KEY_F));
+ inputManager.addMapping("rup", new KeyTrigger(KeyInput.KEY_UP));
+ inputManager.addMapping("rdown", new KeyTrigger(KeyInput.KEY_DOWN));
+ }
+ private void testScene10(){
+ sceneId = 9;
+ roughness = 1.0f;
+ assetManager.registerLoader(KTXLoader.class, "ktx");
+
+ viewPort.setBackgroundColor(ColorRGBA.White);
+ modelNode = new Node("modelNode");
+ model = (Geometry) assetManager.loadModel("Models/Tank/tank.j3o");
+ MikktspaceTangentGenerator.generate(model);
+ modelNode.attachChild(model);
+
+ dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
+ rootNode.addLight(dl);
+ dl.setColor(ColorRGBA.White);
+ rootNode.attachChild(modelNode);
+
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+ int numSamples = context.getSettings().getSamples();
+ if (numSamples > 0) {
+ fpp.setNumSamples(numSamples);
+ }
+
+// fpp.addFilter(new FXAAFilter());
+ fpp.addFilter(new ToneMapFilter(Vector3f.UNIT_XYZ.mult(4.0f)));
+// fpp.addFilter(new SSAOFilter(0.5f, 3, 0.2f, 0.2f));
+ viewPort.addProcessor(fpp);
+
+ //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Sky_Cloudy.hdr", SkyFactory.EnvMapType.EquirectMap);
+ Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Path.hdr", SkyFactory.EnvMapType.EquirectMap);
+ //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", SkyFactory.EnvMapType.CubeMap);
+ //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/road.hdr", SkyFactory.EnvMapType.EquirectMap);
+ rootNode.attachChild(sky);
+
+ pbrMat = assetManager.loadMaterial("Models/Tank/tank.j3m");
+ model.setMaterial(pbrMat);
+
+
+ final EnvironmentCamera envCam = new EnvironmentCamera(256, new Vector3f(0, 3f, 0));
+ stateManager.attach(envCam);
+
+// EnvironmentManager envManager = new EnvironmentManager();
+// stateManager.attach(envManager);
+
+ // envManager.setScene(rootNode);
+
+ LightsDebugState debugState = new LightsDebugState();
+ stateManager.attach(debugState);
+
+ ChaseCamera chaser = new ChaseCamera(cam, modelNode, inputManager);
+ chaser.setDragToRotate(true);
+ chaser.setMinVerticalRotation(-FastMath.HALF_PI);
+ chaser.setMaxDistance(1000);
+ chaser.setSmoothMotion(true);
+ chaser.setRotationSensitivity(10);
+ chaser.setZoomSensitivity(5);
+ flyCam.setEnabled(false);
+ //flyCam.setMoveSpeed(100);
+
+ inputManager.addListener(new ActionListener() {
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if (name.equals("debug") && isPressed) {
+ if (tex == null) {
+ return;
+ }
+ if (tex.getParent() == null) {
+ guiNode.attachChild(tex);
+ } else {
+ tex.removeFromParent();
+ }
+ }
+
+ if (name.equals("rup") && isPressed) {
+ roughness = FastMath.clamp(roughness + 0.1f, 0.0f, 1.0f);
+ pbrMat.setFloat("Roughness", roughness);
+ }
+ if (name.equals("rdown") && isPressed) {
+ roughness = FastMath.clamp(roughness - 0.1f, 0.0f, 1.0f);
+ pbrMat.setFloat("Roughness", roughness);
+ }
+
+
+ if (name.equals("up") && isPressed) {
+ model.move(0, tpf * 100f, 0);
+ }
+
+ if (name.equals("down") && isPressed) {
+ model.move(0, -tpf * 100f, 0);
+ }
+ if (name.equals("left") && isPressed) {
+ model.move(0, 0, tpf * 100f);
+ }
+ if (name.equals("right") && isPressed) {
+ model.move(0, 0, -tpf * 100f);
+ }
+ if (name.equals("light") && isPressed) {
+ dl.setDirection(cam.getDirection().normalize());
+ }
+ }
+ }, "toggle", "light", "up", "down", "left", "right", "debug", "rup", "rdown");
+
+ inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_RETURN));
+ inputManager.addMapping("light", new KeyTrigger(KeyInput.KEY_F));
+ inputManager.addMapping("up", new KeyTrigger(KeyInput.KEY_UP));
+ inputManager.addMapping("down", new KeyTrigger(KeyInput.KEY_DOWN));
+ inputManager.addMapping("left", new KeyTrigger(KeyInput.KEY_LEFT));
+ inputManager.addMapping("right", new KeyTrigger(KeyInput.KEY_RIGHT));
+ inputManager.addMapping("debug", new KeyTrigger(KeyInput.KEY_D));
+ inputManager.addMapping("rup", new KeyTrigger(KeyInput.KEY_T));
+ inputManager.addMapping("rdown", new KeyTrigger(KeyInput.KEY_G));
+ }
+ private void testScene11(){
+// Box boxMesh = new Box(0.5f,0.5f,0.5f);
+// Geometry boxGeo = new Geometry("Colored Box", boxMesh);
+// boxGeo.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
+ Material boxMat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+// boxMat.setBoolean("UseMaterialColors", true);
+// boxMat.setColor("Ambient", ColorRGBA.Green);
+// boxMat.setColor("Diffuse", ColorRGBA.Green);
+// boxGeo.setMaterial(boxMat);
+// rootNode.attachChild(boxGeo);
+ Node tank = (Node) assetManager.loadModel("Models/HoverTank/Tank2.mesh.xml");
+ tank.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
+ tank.setLocalScale(0.3f);
+ rootNode.attachChild(tank);
+
+ Quad plane = new Quad(10, 10);
+ Geometry planeGeo = new Geometry("Plane", plane);
+ planeGeo.setShadowMode(RenderQueue.ShadowMode.Receive);
+ planeGeo.rotate(-45, 0, 0);
+ planeGeo.setLocalTranslation(-5, -5, 0);
+ Material planeMat = boxMat.clone();
+ planeMat.setBoolean("UseMaterialColors", true);
+ planeMat.setColor("Ambient", ColorRGBA.White);
+ planeMat.setColor("Diffuse", ColorRGBA.Gray);
+ planeGeo.setMaterial(planeMat);
+ rootNode.attachChild(planeGeo);
+
+
+ DirectionalLight sun = new DirectionalLight();
+ sun.setDirection((new Vector3f(-0.5f, -0.5f, -0.5f)).normalizeLocal());
+ sun.setColor(ColorRGBA.White);
+ rootNode.addLight(sun);
+ DirectionalLightShadowFilter dlsf = new DirectionalLightShadowFilter(assetManager, 1024, 1);
+ dlsf.setLight(sun);
+
+ sun = new DirectionalLight();
+ sun.setDirection((new Vector3f(0.5f, -0.5f, -0.5f)).normalizeLocal());
+ sun.setColor(ColorRGBA.White);
+ rootNode.addLight(sun);
+ DirectionalLightShadowFilter dlsf2 = new DirectionalLightShadowFilter(assetManager, 1024, 1);
+ dlsf2.setLight(sun);
+
+ sun = new DirectionalLight();
+ sun.setDirection((new Vector3f(0.0f, -0.5f, -0.5f)).normalizeLocal());
+ sun.setColor(ColorRGBA.White);
+ rootNode.addLight(sun);
+ DirectionalLightShadowFilter dlsf3 = new DirectionalLightShadowFilter(assetManager, 1024, 1);
+ dlsf3.setLight(sun);
+
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+ fpp.addFilter(dlsf);
+ fpp.addFilter(dlsf2);
+ fpp.addFilter(dlsf3);
+ viewPort.addProcessor(fpp);
+ }
+
+ @Override
+ public void simpleInitApp() {
+ currentRenderPath = RenderManager.RenderPath.Forward;
+ renderManager.setRenderPath(currentRenderPath);
+ testScene10();
+// cam.setFrustumPerspective(45.0f, 4.0f / 3.0f, 0.01f, 100.0f);
+ flyCam.setMoveSpeed(10.0f);
+ // deferred下闪烁
+// testScene7();
+
+
+// MaterialDebugAppState debug = new MaterialDebugAppState();
+// debug.registerBinding("Common/ShaderLib/BlinnPhongLighting.glsllib", teapot);
+// stateManager.attach(debug);
+ setPauseOnLostFocus(false);
+ flyCam.setDragToRotate(true);
+ flyCam.setMoveSpeed(50.0f);
+
+ makeHudText();
+ registerInput();
+ }
+
+ private void makeHudText() {
+ guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
+ hitText = new BitmapText(guiFont, false);
+ hitText.setSize(guiFont.getCharSet().getRenderedSize());
+ hitText.setText("RendererPath : "+ currentRenderPath.getInfo());
+ hitText.setLocalTranslation(0, cam.getHeight(), 0);
+ guiNode.attachChild(hitText);
+ }
+
+ private void registerInput(){
+ inputManager.addListener(this, "toggleRenderPath");
+ inputManager.addListener(this, "toggleFramegraph");
+ inputManager.addListener(this, "addInstNum");
+ inputManager.addListener(this, "deleteInstNum");
+ inputManager.addMapping("toggleRenderPath", new KeyTrigger(KeyInput.KEY_SPACE));
+ inputManager.addMapping("toggleFramegraph", new KeyTrigger(KeyInput.KEY_N));
+ inputManager.addMapping("addInstNum", new KeyTrigger(KeyInput.KEY_1));
+ inputManager.addMapping("deleteInstNum", new KeyTrigger(KeyInput.KEY_2));
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+ if(sceneId == 1){
+ angle += tpf * 0.25f;
+ angle %= FastMath.TWO_PI;
+
+ pl.setPosition(new Vector3f(FastMath.cos(angle) * 4f, 0.5f, FastMath.sin(angle) * 4f));
+ lightMdl.setLocalTranslation(pl.getPosition());
+ }
+ else if(sceneId == 2){
+// float t = 0;
+// for(int i = 0;i < pls.length;i++){
+// t = i * 1.0f / pls.length * 1.5f + 1.5f;
+// angles[i] += tpf * ((i + 1)) / pls.length;
+// angles[i] %= FastMath.TWO_PI;
+//
+// pls[i].setPosition(new Vector3f(FastMath.cos(angles[i]) * t, i *1.0f / pls.length, FastMath.sin(angles[i]) * t));
+// lightMdls[i].setLocalTranslation(pls[i].getPosition());
+// }
+ }
+ else if(sceneId == 9){
+ frame++;
+
+ if (frame == 2) {
+ modelNode.removeFromParent();
+ final LightProbe probe = LightProbeFactory.makeProbe(stateManager.getState(EnvironmentCamera.class), rootNode, new JobProgressAdapter() {
+
+ @Override
+ public void done(LightProbe result) {
+ System.err.println("Done rendering env maps");
+ tex = EnvMapUtils.getCubeMapCrossDebugViewWithMipMaps(result.getPrefilteredEnvMap(), assetManager);
+ }
+ });
+ probe.getArea().setRadius(100);
+ rootNode.addLight(probe);
+ //getStateManager().getState(EnvironmentManager.class).addEnvProbe(probe);
+
+ }
+ if (frame > 10 && modelNode.getParent() == null) {
+ rootNode.attachChild(modelNode);
+ }
+ }
+// System.out.println("cam.pos:" + cam.getLocation());
+// System.out.println("cam.look:" + cam.getDirection());
+ }
+
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if(name.equals("toggleFramegraph") && !isPressed){
+ bUseFramegraph = !bUseFramegraph;
+ renderManager.enableFramegraph(bUseFramegraph);
+ }
+ if(name.equals("toggleRenderPath") && !isPressed){
+ if(currentRenderPath == RenderManager.RenderPath.Deferred){
+ currentRenderPath = RenderManager.RenderPath.TiledDeferred;
+ }
+ else if(currentRenderPath == RenderManager.RenderPath.TiledDeferred){
+ currentRenderPath = RenderManager.RenderPath.Forward;
+ }
+ else{
+ currentRenderPath = RenderManager.RenderPath.Deferred;
+ }
+ renderManager.setRenderPath(currentRenderPath);
+// getRenderManager().setForcedTechnique(null);
+ hitText.setText("RendererPath : "+ currentRenderPath.getInfo());
+ }
+// if(name.equals("addInstNum") && !isPressed){
+// if(sceneId == 6){
+// instancedGeometry.setForceNumVisibleInstances(instancedGeometry.getNumVisibleInstances() + 1);
+// }
+// }
+// else if(name.equals("deleteInstNum") && !isPressed){
+// if(sceneId == 6){
+// instancedGeometry.setForceNumVisibleInstances(instancedGeometry.getNumVisibleInstances() - 1);
+// }
+// }
+ }
+}
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java
new file mode 100644
index 0000000000..5c51cb46a8
--- /dev/null
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java
@@ -0,0 +1,101 @@
+package jme3test.renderpath;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.PointLight;
+import com.jme3.material.Material;
+import com.jme3.material.TechniqueDef;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.ToneMapFilter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.instancing.InstancedNode;
+import com.jme3.scene.shape.Quad;
+import com.jme3.scene.shape.Sphere;
+
+/**
+ * https://leifnode.com/2015/05/tiled-deferred-shading/
+ * @author JohnKkk
+ */
+public class TestTileBasedDeferredShading extends SimpleApplication {
+ private Material material;
+ @Override
+ public void simpleInitApp() {
+ renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass);
+ renderManager.setSinglePassLightBatchSize(30);
+ renderManager.setRenderPath(RenderManager.RenderPath.Forward);
+ Quad quad = new Quad(15, 15);
+ Geometry geo = new Geometry("Floor", quad);
+ material = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
+ material.setFloat("Shininess", 25);
+ material.setColor("Ambient", ColorRGBA.White);
+ material.setColor("Diffuse", ColorRGBA.White);
+ material.setColor("Specular", ColorRGBA.White);
+ material.setBoolean("UseMaterialColors", true);
+ geo.setMaterial(material);
+ geo.rotate((float) Math.toRadians(-90), 0, 0);
+ geo.setLocalTranslation(-7, 0, -7);
+ rootNode.attachChild(geo);
+
+ Sphere sphere = new Sphere(15, 15, 0.1f);
+ Geometry sp = new Geometry("sp", sphere);
+ sp.setMaterial(material.clone());
+ sp.getMaterial().setBoolean("UseInstancing", true);
+ ColorRGBA colors[] = new ColorRGBA[]{
+ ColorRGBA.White,
+ ColorRGBA.Red,
+ ColorRGBA.Blue,
+ ColorRGBA.Green,
+ ColorRGBA.Yellow,
+ ColorRGBA.Orange,
+ ColorRGBA.Brown,
+ };
+
+ InstancedNode instancedNode = new InstancedNode("sp");
+ for(int i = 0;i < 1000;i++){
+ PointLight pl = new PointLight();
+ pl.setColor(colors[i % colors.length]);
+ pl.setPosition(new Vector3f(FastMath.nextRandomFloat(-5.0f, 5.0f), 0.1f, FastMath.nextRandomFloat(-20.0f, -10.0f)));
+// pl.setPosition(new Vector3f(0, 1, 0));
+ pl.setRadius(1.0f);
+ rootNode.addLight(pl);
+ Geometry g = sp.clone(false);
+// g.getMaterial().setColor("Ambient", ColorRGBA.Gray);
+// g.getMaterial().setColor("Diffuse", colors[i % colors.length]);
+ g.setLocalTranslation(pl.getPosition());
+ instancedNode.attachChild(g);
+ }
+ instancedNode.instance();
+ rootNode.attachChild(instancedNode);
+
+
+// AmbientLight ambientLight = new AmbientLight(new ColorRGBA(0.15f, 0.15f, 0.15f, 1.0f));
+// rootNode.addLight(ambientLight);
+// DirectionalLight sun = new DirectionalLight();
+// sun.setDirection((new Vector3f(-0.5f, -0.5f, -0.5f)).normalizeLocal());
+// sun.setColor(ColorRGBA.Gray);
+// rootNode.addLight(sun);
+
+
+ cam.setLocation(new Vector3f(0, 2, 0));
+ cam.lookAtDirection(Vector3f.UNIT_Z.negate(), Vector3f.UNIT_Y);
+ flyCam.setMoveSpeed(10.0f);
+
+
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+ int numSamples = context.getSettings().getSamples();
+ if (numSamples > 0) {
+ fpp.setNumSamples(numSamples);
+ }
+
+ fpp.addFilter(new ToneMapFilter(Vector3f.UNIT_XYZ.mult(1.5f)));
+ viewPort.addProcessor(fpp);
+ }
+
+ public static void main(String[] args) {
+ TestTileBasedDeferredShading testTileBasedDeferredShading = new TestTileBasedDeferredShading();
+ testTileBasedDeferredShading.start();
+ }
+}
From e5737dfb65a7a8115a972c1271747f46a3b7965b Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Tue, 10 Oct 2023 15:23:57 +0800
Subject: [PATCH 003/111] jme3-core:Improve deferred shading issues; Fix
flickering issues in tile based deferred shading;
---
.../DeferredSinglePassLightingLogic.java | 56 +++++++++----
...eBasedDeferredSinglePassLightingLogic.java | 84 ++++++++++++++++---
.../java/com/jme3/renderer/RenderManager.java | 14 ++++
.../src/main/java/com/jme3/util/TempVars.java | 1 +
.../TileBasedDeferredShading.frag | 5 +-
5 files changed, 132 insertions(+), 28 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java
index fbd592834e..440783c4be 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java
@@ -108,6 +108,18 @@ public DeferredSinglePassLightingLogic(TechniqueDef techniqueDef) {
nbSkyLightAndReflectionProbesDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_SKY_LIGHT_AND_REFLECTION_PROBES, VarType.Int);
}
+ private void cleanupLightData(){
+ if(this.lightData1 != null){
+ this.lightData1.getImage().dispose();
+ }
+ if(this.lightData2 != null){
+ this.lightData2.getImage().dispose();
+ }
+ if(this.lightData3 != null){
+ this.lightData3.getImage().dispose();
+ }
+ }
+
private void prepaLightData(int lightNum){
this.lightNum = lightNum;
// 1d texture
@@ -274,6 +286,16 @@ protected int updateLightListPackToTexture(Shader shader, Geometry g, LightList
throw new UnsupportedOperationException("Unknown type of light: " + l.getType());
}
}
+ temp.r = temp.g = temp.b = temp.a = 0;
+ // Since the drawing is sent within the loop branch, and actually before the actual glSwapBuffers, the gl commands actually reside at the graphics driver level. So in order to correctly branch within the loop, the size must be fixed here (while filling the number of light sources).
+ ColorRGBA temp2 = vars.color2;
+ for(;curIndex < this.lightNum;curIndex++){
+ temp2 = lightDataUpdateIO1.getPixel(curIndex, 0);
+ if(temp2.r == 0 && temp2.g == 0 && temp2.b == 0 && temp2.a == 0)break;
+ lightDataUpdateIO1.setPixel(curIndex, 0, temp);
+ lightDataUpdateIO2.setPixel(curIndex, 0, temp);
+ lightDataUpdateIO3.setPixel(curIndex, 0, temp);
+ }
vars.release();
lightData1.getImage().setUpdateNeeded();
lightData2.getImage().setUpdateNeeded();
@@ -406,24 +428,30 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry
if(geometry.getUserData(_S_LIGHT_CULL_DRAW_STAGE) != null){
isLightCullStageDraw = geometry.getUserData(_S_LIGHT_CULL_DRAW_STAGE);
}
- // todo:这里的一种优化方式是:
- // todo:使用uniform数组存储的方案:
- // todo:首先将lights分成DirectionalLights,PointLights,SpotLights三种列表
- // todo:然后首先绘制DirectionalLights和SpotLights,这两个都是用Rect绘制,一次提交SingleBatch指定的数量灯光
- // todo:然后使用Sphere(开启FrontFace剔除,避免相机进入球内光源着色消失)绘制点光源,根据SingleBatch一次绘制一组Sphere实例化
-
- // todo:另一种做法是,将lights分为全屏和非全屏,DirectionalLight和SpotLight按全屏处理,然后便利所有PointLight中属于无效半径的也归为全屏
- // todo:然后把剩下的PointLights作为非全屏光源,然后纹理中一次性存储所有光源信息,内存存放按全屏在前非全屏在后
- // todo:然后发起一个RectPass,在一个DC内绘制完所有全屏光,更新light_offset,然后使用SingleBatch预创建的SphereInstance绘制剩下的非全屏光
- // todo:这里将采用第二种方法
-
- // todo:关于light probes(暂时实现基于preCompute light probe),根据当前视锥体可见范围获取到light probe grid,按light probe grid执行multi pass
- // todo:关于reflection probes,使用textureArray(八面体投影,带mipmap),收集相机可见范围内的reflection probes,并限制当前视锥体内只能有多少个reflection probes
+ // todo: One optimization approach here is:
+ // todo: Use uniform array storage scheme:
+ // todo: First divide lights into DirectionalLights, PointLights, SpotLights three lists
+ // todo: Then first draw DirectionalLights and SpotLights, these two are drawn with Rect, submitting the number of lights specified by SingleBatch at a time
+ // todo: Then use Sphere (turn on FrontFace culling to avoid camera entering sphere and light source shading disappears) to draw point lights, drawing groups of Sphere instances based on SingleBatch at a time
+
+ // todo: Another approach is to divide lights into full-screen and non full-screen, handle DirectionalLight and SpotLight as full-screen, then traverse all PointLights with invalid radius also categorized as full-screen
+ // todo: Then take the remaining PointLights as non full-screen lights, then store all light source information in the texture at once, with full-screen in front and non full-screen behind in memory
+ // todo: Then initiate a RectPass, draw all full-screen lights in one DC, update light_offset, then use precreated SphereInstance with SingleBatch to draw the remaining non full-screen lights
+ // todo: The second method will be adopted here
+
+ // todo: For light probes (temporarily implemented based on preCompute light probe), get light probe grid based on current view frustum visible range, execute multi pass according to light probe grid
+ // todo: For reflection probes, use textureArray (cubemap projection, with mipmap), collect reflection probes visible to current camera view frustum, and limit the number of reflection probes allowed in the current view frustum
if(bUseTexturePackMode){
+ if(this.lightNum != renderManager.getCurMaxDeferredShadingLightNum()){
+ cleanupLightData();
+ prepaLightData(renderManager.getCurMaxDeferredShadingLightNum());
+ }
+ // todo:Currently, this texturePackMode is only suitable for scenes where there are a large number of light sources per frame. The number of light sources is submitted to the texture all at once, so lightNum can be pre-allocated, but light source information can also be submitted to the texture all at once here, and then drawn in multiple passes (drawing each time by the specified singlePassLightBatchSize)
Uniform lightCount = shader.getUniform("g_LightCount");
SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, true);
int count = lights.size();
- lightCount.setValue(VarType.Int, count);
+// lightCount.setValue(VarType.Int, count);
+ lightCount.setValue(VarType.Int, this.lightNum);
while (nbRenderedLights < count) {
// todo:采用第二种方法优化deferred,则这里使用当前类的geometrys(rect,sphere)进行绘制,而不使用这个传递进来的geometry(或者在外部传递两个geometry,一个rect一个sphereinstance)
nbRenderedLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, nbRenderedLights, isLightCullStageDraw, lastTexUnit);
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
index 7be6e4f810..387596379e 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
@@ -158,6 +158,19 @@ private void cleanupLightsIndexTexture(){
}
}
+ private void createLightsIndexTexture(int lightIndexWidth){
+ this.lightIndexWidth = lightIndexWidth;
+ lightsIndexData = new Texture2D(lightIndexWidth, lightIndexWidth, Image.Format.RGBA32F);
+ lightsIndexData.setMinFilter(Texture.MinFilter.NearestNoMipMaps);
+ lightsIndexData.setMagFilter(Texture.MagFilter.Nearest);
+ lightsIndexData.setWrap(Texture.WrapMode.EdgeClamp);
+ ByteBuffer dataT = BufferUtils.createByteBuffer( (int)Math.ceil(Image.Format.RGBA32F.getBitsPerPixel() / 8.0) * lightIndexWidth * lightIndexWidth);
+ Image convertedImageT = new Image(Image.Format.RGBA32F, lightIndexWidth, lightIndexWidth, dataT, null, ColorSpace.Linear);
+ lightsIndexData.setImage(convertedImageT);
+ lightsIndexData.getImage().setMipmapsGenerated(false);
+ lightsIndexDataUpdateIO = ImageRaster.create(lightsIndexData.getImage());
+ }
+
private void cleanupLightsDecodeTexture(){
if(lightsDecodeData != null){
lightsDecodeData.getImage().dispose();
@@ -180,16 +193,8 @@ private void reset(int tileWidth, int tileHeight, int tileNum){
_tileWidth = tileWidth;
_tileHeight = tileHeight;
- lightIndexWidth = (int)(Math.floor(Math.sqrt(1024)));
- lightsIndexData = new Texture2D(lightIndexWidth, lightIndexWidth, Image.Format.RGBA32F);
- lightsIndexData.setMinFilter(Texture.MinFilter.NearestNoMipMaps);
- lightsIndexData.setMagFilter(Texture.MagFilter.Nearest);
- lightsIndexData.setWrap(Texture.WrapMode.EdgeClamp);
- ByteBuffer dataT = BufferUtils.createByteBuffer( (int)Math.ceil(Image.Format.RGBA32F.getBitsPerPixel() / 8.0) * lightIndexWidth * lightIndexWidth);
- Image convertedImageT = new Image(Image.Format.RGBA32F, lightIndexWidth, lightIndexWidth, dataT, null, ColorSpace.Linear);
- lightsIndexData.setImage(convertedImageT);
- lightsIndexData.getImage().setMipmapsGenerated(false);
- lightsIndexDataUpdateIO = ImageRaster.create(lightsIndexData.getImage());
+// lightIndexWidth = (int)(Math.floor(Math.sqrt(1024)));
+ createLightsIndexTexture(lightIndexWidth);
lightsDecodeData = new Texture2D(_tileWidth, _tileHeight, Image.Format.RGBA32F);
@@ -380,6 +385,19 @@ private void tileLightDecode(int tileNum, ArrayList> tiles, i
}
// Calculate light sampling size
int lightIndexWidth = (int) Math.ceil(Math.sqrt(lightsIndex.size() / 3));
+ if(lightIndexWidth > this.lightIndexWidth){
+ // recreate
+ cleanupLightsIndexTexture();
+ createLightsIndexTexture(lightIndexWidth);
+ }
+ else{
+ // todo:Due to the unknown dynamic texture size causing tile flickering, the current fixed texture size is forced to be used each time here.
+ // todo:Adjust to dynamic texture size after finding the cause later, otherwise a lot of padding data needs to be filled each time.
+ lightIndexWidth = this.lightIndexWidth;
+ }
+// else{
+// lightIndexWidth = this.lightIndexWidth;
+// }
// int _lightIndexWidth = (int) Math.ceil(lightIndexWidth / 3);
// updateData
Uniform tileLightOffsetSizeUniform = shader.getUniform(TILE_LIGHT_OFFSET_SIZE);
@@ -408,6 +426,19 @@ private void tileLightDecode(int tileNum, ArrayList> tiles, i
lightsIndexDataUpdateIO.setPixel(j, i, temp);
}
}
+ // todo:Due to the unknown dynamic texture size causing tile flickering, the current fixed texture size is forced to be used each time here.
+ // todo:Adjust to dynamic texture size after finding the cause later, otherwise a lot of padding data needs to be filled each time.
+// lightsIndexData.getImage().setWidth(lightIndexWidth);
+// lightsIndexData.getImage().setHeight(lightIndexWidth);
+// for(int i = 0, x = 0, y = 0;i < lightsIndex.size();i+=3){
+// temp.r = lightsIndex.get(i);
+// temp.g = 0.0f;
+// lightsIndexDataUpdateIO.setPixel(x++, y, temp);
+// if(x >= this.lightIndexWidth){
+// x = 0;
+// y++;
+// }
+// }
for(int i = 0;i < tileHeight;i++){
for(int j = 0;j < tileWidth;j++){
temp.r = lightsDecode.get((j + i * tileWidth) * 3);
@@ -417,6 +448,7 @@ private void tileLightDecode(int tileNum, ArrayList> tiles, i
}
}
vars.release();
+
lightsIndexData.getImage().setUpdateNeeded();
lightsDecodeData.getImage().setUpdateNeeded();
g.getMaterial().setTexture(TILE_LIGHT_INDEX, lightsIndexData);
@@ -426,6 +458,7 @@ private void tileLightDecode(int tileNum, ArrayList> tiles, i
public TileBasedDeferredSinglePassLightingLogic(TechniqueDef techniqueDef) {
super(techniqueDef);
+ lightIndexWidth = (int)(Math.floor(Math.sqrt(1024)));
singlePassLightingDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_TILE_BASED_DEFERRED_SINGLE_PASS_LIGHTING, VarType.Boolean);
if(bUseTexturePackMode){
packNbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_PACK_NB_LIGHTS, VarType.Int);
@@ -438,6 +471,18 @@ public TileBasedDeferredSinglePassLightingLogic(TechniqueDef techniqueDef) {
nbSkyLightAndReflectionProbesDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_SKY_LIGHT_AND_REFLECTION_PROBES, VarType.Int);
}
+ private void cleanupLightData(){
+ if(this.lightData1 != null){
+ this.lightData1.getImage().dispose();
+ }
+ if(this.lightData2 != null){
+ this.lightData2.getImage().dispose();
+ }
+ if(this.lightData3 != null){
+ this.lightData3.getImage().dispose();
+ }
+ }
+
private void prepaLightData(int lightNum){
this.lightNum = lightNum;
// 1d texture
@@ -602,6 +647,16 @@ protected int updateLightListPackToTexture(Shader shader, Geometry g, LightList
throw new UnsupportedOperationException("Unknown type of light: " + l.getType());
}
}
+ temp.r = temp.g = temp.b = temp.a = 0;
+ // Since the drawing is sent within the loop branch, and actually before the actual glSwapBuffers, the gl commands actually reside at the graphics driver level. So in order to correctly branch within the loop, the size must be fixed here (while filling the number of light sources).
+ ColorRGBA temp2 = vars.color2;
+ for(;curIndex < this.lightNum;curIndex++){
+ temp2 = lightDataUpdateIO1.getPixel(curIndex, 0);
+ if(temp2.r == 0 && temp2.g == 0 && temp2.b == 0 && temp2.a == 0)break;
+ lightDataUpdateIO1.setPixel(curIndex, 0, temp);
+ lightDataUpdateIO2.setPixel(curIndex, 0, temp);
+ lightDataUpdateIO3.setPixel(curIndex, 0, temp);
+ }
vars.release();
lightData1.getImage().setUpdateNeeded();
lightData2.getImage().setUpdateNeeded();
@@ -736,9 +791,13 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry
}
if(bUseTexturePackMode){
Uniform lightCount = shader.getUniform("g_LightCount");
+ if(this.lightNum != renderManager.getCurMaxDeferredShadingLightNum()){
+ cleanupLightData();
+ prepaLightData(renderManager.getCurMaxDeferredShadingLightNum());
+ }
SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, true);
int count = lights.size();
- lightCount.setValue(VarType.Int, count);
+ lightCount.setValue(VarType.Int, this.lightNum);
// Divide lights into full screen lights and non-full screen lights. Currently only PointLights with radius are treated as non-full screen lights.
// The lights passed in here must be PointLights with valid radii. Another approach is to fill tiles with infinite range Lights.
if(count > 0){
@@ -765,11 +824,12 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry
_camLeft.set(_matArray1[0], _matArray1[1], _matArray1[2], -1.0f).multLocal(-1.0f);
_camUp.set(_matArray1[4], _matArray1[5], _matArray1[6], 1.0f);
}
+ // filterLights(remove ambientLight,lightprobe...)
// update tiles
for(int i = 0;i < count;i++){
_lightFrustum = lightClip(lights.get(i));
- if(_lightFrustum != null){
+ if(_lightFrustum != null && false){
tilesUpdate(tileSize, tileWidth, tileHeight, tileNum, tiles, _lightFrustum, i);
}
else{
diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
index 3539486dca..a7a496fc12 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
@@ -82,6 +82,8 @@
* @see Spatial
*/
public class RenderManager {
+ // Maximum total number of light sources for deferred rendering
+ private int curMaxDeferredShadingLightNum = 1024;
// TileInfo
private TileBasedDeferredSinglePassLightingLogic.TileInfo tileInfo;
// todo:Since glTexImage is not used to dynamically adjust lightIndex size currently, this tileSize needs to be set cautiously.
@@ -180,6 +182,18 @@ public final void enableFramegraph(boolean useFramegraph){
this.useFramegraph = useFramegraph;
}
+ /**
+ * For performance considerations, the engine will pre-allocate a texture memory block based on this tag for packing light source data. Therefore, please adjust this to a reasonable maximum value for the scene light sources based on scene needs.
+ * @param curMaxDeferredShadingLightNum default value 1024
+ */
+ public void setCurMaxDeferredShadingLightNum(int curMaxDeferredShadingLightNum) {
+ this.curMaxDeferredShadingLightNum = curMaxDeferredShadingLightNum;
+ }
+
+ public int getCurMaxDeferredShadingLightNum() {
+ return curMaxDeferredShadingLightNum;
+ }
+
/**
* SetTileBasedInfo.
* @param tileSize The current size of tiles for partitioning (default 32x32 pixels).
diff --git a/jme3-core/src/main/java/com/jme3/util/TempVars.java b/jme3-core/src/main/java/com/jme3/util/TempVars.java
index fcc8c8071d..42d195399f 100644
--- a/jme3-core/src/main/java/com/jme3/util/TempVars.java
+++ b/jme3-core/src/main/java/com/jme3/util/TempVars.java
@@ -164,6 +164,7 @@ public void release() {
* Color
*/
public final ColorRGBA color = new ColorRGBA();
+ public final ColorRGBA color2 = new ColorRGBA();
/**
* General vectors.
*/
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
index 88c72a2c10..283f01e451 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
@@ -90,8 +90,9 @@ void main(){
offset = 0;
if(temp >= g_TileLightOffsetSize){
- temp -= g_TileLightOffsetSize;
- offset++;
+ //temp -= g_TileLightOffsetSize;
+ offset += int(temp / float(g_TileLightOffsetSize));
+ temp = float(int(temp) % g_TileLightOffsetSize);
}
if(temp == g_TileLightOffsetSize){
temp = 0.0f;
From d69de2d492ff68ceb87141fcdf520619570c04c1 Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Tue, 10 Oct 2023 15:24:53 +0800
Subject: [PATCH 004/111] jme3-examples:Adjust deferred rendering test code
---
.../renderpath/TestDeferredShading.java | 2 ++
.../TestTileBasedDeferredShading.java | 36 ++++++++++++++++---
2 files changed, 33 insertions(+), 5 deletions(-)
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java
index a959f68375..645e6429cc 100644
--- a/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TestDeferredShading.java
@@ -27,7 +27,9 @@ public void simpleInitApp() {
// renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass);
// renderManager.setSinglePassLightBatchSize(30);
// renderManager.setRenderPath(RenderManager.RenderPath.Forward);
+ renderManager.setCurMaxDeferredShadingLightNum(1000);// Pre-allocate a maximum value for light sources to ensure the maximum number of light sources in the scene does not exceed this value.
renderManager.setRenderPath(RenderManager.RenderPath.Deferred);
+ renderManager.setSinglePassLightBatchSize(200);
Quad quad = new Quad(15, 15);
Geometry geo = new Geometry("Floor", quad);
material = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java
index 5c51cb46a8..69f531d051 100644
--- a/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java
@@ -8,12 +8,14 @@
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.BloomFilter;
import com.jme3.post.filters.ToneMapFilter;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.instancing.InstancedNode;
import com.jme3.scene.shape.Quad;
import com.jme3.scene.shape.Sphere;
+import com.jme3.system.AppSettings;
/**
* https://leifnode.com/2015/05/tiled-deferred-shading/
@@ -23,9 +25,11 @@ public class TestTileBasedDeferredShading extends SimpleApplication {
private Material material;
@Override
public void simpleInitApp() {
- renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass);
- renderManager.setSinglePassLightBatchSize(30);
- renderManager.setRenderPath(RenderManager.RenderPath.Forward);
+// renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass);
+// renderManager.setSinglePassLightBatchSize(30);
+// renderManager.setRenderPath(RenderManager.RenderPath.Forward);
+ renderManager.setCurMaxDeferredShadingLightNum(1000);
+ renderManager.setRenderPath(RenderManager.RenderPath.TiledDeferred);
Quad quad = new Quad(15, 15);
Geometry geo = new Geometry("Floor", quad);
material = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
@@ -59,6 +63,14 @@ public void simpleInitApp() {
pl.setColor(colors[i % colors.length]);
pl.setPosition(new Vector3f(FastMath.nextRandomFloat(-5.0f, 5.0f), 0.1f, FastMath.nextRandomFloat(-20.0f, -10.0f)));
// pl.setPosition(new Vector3f(0, 1, 0));
+// if(i % 2 == 0){
+// pl.setColor(ColorRGBA.Red);
+// pl.setPosition(new Vector3f(-5, 0.1f, -15.0f));
+// }
+// else{
+// pl.setColor(ColorRGBA.White);
+// pl.setPosition(new Vector3f(-4, 0.1f, -14.0f));
+// }
pl.setRadius(1.0f);
rootNode.addLight(pl);
Geometry g = sp.clone(false);
@@ -80,8 +92,11 @@ public void simpleInitApp() {
cam.setLocation(new Vector3f(0, 2, 0));
- cam.lookAtDirection(Vector3f.UNIT_Z.negate(), Vector3f.UNIT_Y);
+// cam.lookAtDirection(Vector3f.UNIT_Z.negate(), Vector3f.UNIT_Y);
+ cam.lookAtDirection(new Vector3f(-0.30149722f, 0.04880875f, -0.952217f), Vector3f.UNIT_Y);
+ cam.setFrustumPerspective(45.0f, cam.getWidth() * 1.0f / cam.getHeight(), 0.1f, 100.0f);
flyCam.setMoveSpeed(10.0f);
+// flyCam.setEnabled(false);
FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
@@ -90,12 +105,23 @@ public void simpleInitApp() {
fpp.setNumSamples(numSamples);
}
- fpp.addFilter(new ToneMapFilter(Vector3f.UNIT_XYZ.mult(1.5f)));
+ BloomFilter bloom=new BloomFilter();
+ bloom.setDownSamplingFactor(1);
+ bloom.setBlurScale(1.1f);
+ bloom.setExposurePower(1.30f);
+ bloom.setExposureCutOff(0.3f);
+ bloom.setBloomIntensity(1.15f);
+ fpp.addFilter(bloom);
+
+ fpp.addFilter(new ToneMapFilter(Vector3f.UNIT_XYZ.mult(2.5f)));
viewPort.addProcessor(fpp);
}
public static void main(String[] args) {
TestTileBasedDeferredShading testTileBasedDeferredShading = new TestTileBasedDeferredShading();
+ AppSettings appSettings = new AppSettings(true);
+ appSettings.setRenderer(AppSettings.LWJGL_OPENGL33);
+ testTileBasedDeferredShading.setSettings(appSettings);
testTileBasedDeferredShading.start();
}
}
From 6e75f0b3dc420f170a2683a11bab5f33340f5c44 Mon Sep 17 00:00:00 2001
From: chenliming
Date: Tue, 10 Oct 2023 15:44:30 +0800
Subject: [PATCH 005/111] jme3-core:Adjust GBuffer format, RT0(16F), RT1(16F),
RT2(16F), RT3(32F), DEPTH
---
.../main/java/com/jme3/renderer/renderPass/GBufferPass.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java
index 3fb84efae1..6c24da297d 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java
@@ -115,9 +115,9 @@ public void reshape(Renderer renderer, ViewPort vp, int w, int h){
if(recreate){
// recreate
// To ensure accurate results, 32bit is used here for generalization.
- gBufferData0 = new Texture2D(w, h, Image.Format.RGBA32F);
- gBufferData1 = new Texture2D(w, h, Image.Format.RGBA32F);
- gBufferData2 = new Texture2D(w, h, Image.Format.RGBA32F);
+ gBufferData0 = new Texture2D(w, h, Image.Format.RGBA16F);
+ gBufferData1 = new Texture2D(w, h, Image.Format.RGBA16F);
+ gBufferData2 = new Texture2D(w, h, Image.Format.RGBA16F);
gBufferData3 = new Texture2D(w, h, Image.Format.RGBA32F); // The third buffer provides 32-bit floating point to store high-precision information, such as normals
// todo:后续调整为Depth24Stencil8,然后使用一个SceneColorFBO用于渲染所有3D部分,然后将其color_attach_0复制到BackBuffer中
// todo:然后开启DepthTest绘制最后的所有GUI
From 0290dcdb96f8905e046c2e698a4d28642ec485d9 Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Tue, 10 Oct 2023 17:57:17 +0800
Subject: [PATCH 006/111] jme3-core:Delete test code
---
.../logic/TileBasedDeferredSinglePassLightingLogic.java | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
index 387596379e..acc366bef1 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
@@ -824,12 +824,13 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry
_camLeft.set(_matArray1[0], _matArray1[1], _matArray1[2], -1.0f).multLocal(-1.0f);
_camUp.set(_matArray1[4], _matArray1[5], _matArray1[6], 1.0f);
}
- // filterLights(remove ambientLight,lightprobe...)
// update tiles
for(int i = 0;i < count;i++){
+ // filterLights(remove ambientLight,lightprobe...)
+ if(lights.get(i).getType() == Light.Type.Ambient || lights.get(i).getType() == Light.Type.Probe)continue;
_lightFrustum = lightClip(lights.get(i));
- if(_lightFrustum != null && false){
+ if(_lightFrustum != null){
tilesUpdate(tileSize, tileWidth, tileHeight, tileNum, tiles, _lightFrustum, i);
}
else{
From 6a64da6859a521d5e4c165da6de4d24fda8a8e73 Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Tue, 10 Oct 2023 20:20:28 +0800
Subject: [PATCH 007/111] jme3-core:Fixed all known bugs in Tile-based
DeferredShading.
---
...eBasedDeferredSinglePassLightingLogic.java | 26 ++++++++++++++++++-
.../java/com/jme3/renderer/RenderManager.java | 4 +--
.../TileBasedDeferredShading.frag | 9 ++++++-
.../TileBasedDeferredShading.j3md | 1 +
4 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
index acc366bef1..8290293870 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
@@ -35,6 +35,9 @@
*/
public class TileBasedDeferredSinglePassLightingLogic extends DefaultTechniqueDefLogic{
private final static String _S_LIGHT_CULL_DRAW_STAGE = "Light_Cull_Draw_Stage";
+ private final static String _S_TILE_SIZE = "g_TileSize";
+ private final static String _S_TILE_WIDTH = "g_WidthTile";
+ private final static String _S_TILE_HEIGHT = "g_HeightTile";
private static final String DEFINE_TILE_BASED_DEFERRED_SINGLE_PASS_LIGHTING = "TILE_BASED_DEFERRED_SINGLE_PASS_LIGHTING";
private static final String DEFINE_NB_LIGHTS = "NB_LIGHTS";
private static final String DEFINE_USE_TEXTURE_PACK_MODE = "USE_TEXTURE_PACK_MODE";
@@ -388,7 +391,8 @@ private void tileLightDecode(int tileNum, ArrayList> tiles, i
if(lightIndexWidth > this.lightIndexWidth){
// recreate
cleanupLightsIndexTexture();
- createLightsIndexTexture(lightIndexWidth);
+ // Expanding the texture size by 1.5 times can avoid the flickering issue caused by repeatedly allocating new textures due to insufficient size in consecutive frames.
+ createLightsIndexTexture((int) (lightIndexWidth * 1.5));
}
else{
// todo:Due to the unknown dynamic texture size causing tile flickering, the current fixed texture size is forced to be used each time here.
@@ -515,6 +519,20 @@ private void prepaLightData(int lightNum){
lightData3.setImage(convertedImage3);
lightData3.getImage().setMipmapsGenerated(false);
lightDataUpdateIO3 = ImageRaster.create(lightData3.getImage());
+
+ TempVars vars = TempVars.get();
+ ColorRGBA temp = vars.color;
+ temp.r = temp.g = temp.b = temp.a = 0;
+ // Since the drawing is sent within the loop branch, and actually before the actual glSwapBuffers, the gl commands actually reside at the graphics driver level. So in order to correctly branch within the loop, the size must be fixed here (while filling the number of light sources).
+ ColorRGBA temp2 = vars.color2;
+ for(int curIndex = 0;curIndex < this.lightNum;curIndex++){
+ temp2 = lightDataUpdateIO1.getPixel(curIndex, 0);
+ if(temp2.r == 0 && temp2.g == 0 && temp2.b == 0 && temp2.a == 0)break;
+ lightDataUpdateIO1.setPixel(curIndex, 0, temp);
+ lightDataUpdateIO2.setPixel(curIndex, 0, temp);
+ lightDataUpdateIO3.setPixel(curIndex, 0, temp);
+ }
+ vars.release();
}
@Override
@@ -808,6 +826,12 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry
int tileWidth = tileInfo.tileWidth;
int tileHeight = tileInfo.tileHeight;
int tileNum = tileInfo.tileNum;
+ Uniform u_tileSize = shader.getUniform(_S_TILE_SIZE);
+ Uniform u_tileWidth = shader.getUniform(_S_TILE_WIDTH);
+ Uniform u_tileHeight = shader.getUniform(_S_TILE_HEIGHT);
+ u_tileSize.setValue(VarType.Int, tileSize);
+ u_tileWidth.setValue(VarType.Int, tileWidth);
+ u_tileHeight.setValue(VarType.Int, tileHeight);
reset(tileWidth, tileHeight, tileNum);
{
diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
index a7a496fc12..f855ad15af 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
@@ -1371,8 +1371,8 @@ public void renderViewPort(ViewPort vp, float tpf) {
}
else if(curRenderPath == RenderPath.TiledDeferred){
curTileSize = getCurrentCamera().getWidth() / 4;
- int tileWidth = (int)(Math.floor(viewWidth / curTileSize));
- int tileHeight = (int)(Math.floor(viewHeight / curTileSize));
+ int tileWidth = (int)(viewWidth / curTileSize);
+ int tileHeight = (int)(viewHeight / curTileSize);
setTileInfo(curTileSize, tileWidth, tileHeight, tileWidth * tileHeight);
frameGraph.addPass(gBufferPass);
tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_0, gBufferPass.getName() + "." + GBufferPass.S_RT_0);
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
index 283f01e451..0ea748bb90 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
@@ -31,6 +31,11 @@ uniform vec4 g_AmbientLightColor;
#else
uniform vec4 g_LightData[NB_LIGHTS];
#endif
+
+uniform vec2 g_Resolution;
+uniform int g_TileSize;
+uniform int g_WidthTile;
+uniform int g_HeightTile;
uniform int g_TileLightOffsetSize;
uniform sampler2D m_TileLightDecode;
uniform sampler2D m_TileLightIndex;
@@ -72,8 +77,10 @@ void main(){
#endif
// Tile Based Shading
+ // get the grid data index
+ vec2 gridIndex = vec2(((innerTexCoord.x*g_Resolution.x) / float(g_TileSize)) / float(g_WidthTile), ((innerTexCoord.y*g_Resolution.y) / float(g_TileSize)) / float(g_HeightTile));
// get tile info
- vec3 tile = texture2D(m_TileLightDecode, innerTexCoord).xyz;
+ vec3 tile = texture2D(m_TileLightDecode, gridIndex).xyz;
int uoffset = int(tile.x);
int voffset = int(tile.z);
int count = int(tile.y);
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md
index 06a2047c4a..f5c8e4ed28 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md
@@ -35,6 +35,7 @@ MaterialDef DeferredShading {
WorldViewProjectionMatrix
ViewProjectionMatrix
ResolutionInverse
+ Resolution
}
Defines {
From c8e7426b3d92c4e3fe09ca40c1b73d09d3707fce Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Tue, 10 Oct 2023 20:20:51 +0800
Subject: [PATCH 008/111] jme3-examples:update TestTileBasedDeferredShading
---
.../jme3test/renderpath/TestTileBasedDeferredShading.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java
index 69f531d051..159aa57d27 100644
--- a/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java
@@ -92,8 +92,8 @@ public void simpleInitApp() {
cam.setLocation(new Vector3f(0, 2, 0));
-// cam.lookAtDirection(Vector3f.UNIT_Z.negate(), Vector3f.UNIT_Y);
- cam.lookAtDirection(new Vector3f(-0.30149722f, 0.04880875f, -0.952217f), Vector3f.UNIT_Y);
+ cam.lookAtDirection(Vector3f.UNIT_Z.negate(), Vector3f.UNIT_Y);
+// cam.lookAtDirection(new Vector3f(-0.30149722f, 0.04880875f, -0.952217f), Vector3f.UNIT_Y);
cam.setFrustumPerspective(45.0f, cam.getWidth() * 1.0f / cam.getHeight(), 0.1f, 100.0f);
flyCam.setMoveSpeed(10.0f);
// flyCam.setEnabled(false);
From e5406012efd5d210bd875365784814927cd611a5 Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Tue, 10 Oct 2023 21:03:17 +0800
Subject: [PATCH 009/111] jme3-core:update GLSLCompat.glsllib
---
.../Common/ShaderLib/GLSLCompat.glsllib | 37 ++++++++++++++++---
1 file changed, 32 insertions(+), 5 deletions(-)
diff --git a/jme3-core/src/main/resources/Common/ShaderLib/GLSLCompat.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/GLSLCompat.glsllib
index 3bb8a0f629..6019886482 100644
--- a/jme3-core/src/main/resources/Common/ShaderLib/GLSLCompat.glsllib
+++ b/jme3-core/src/main/resources/Common/ShaderLib/GLSLCompat.glsllib
@@ -2,6 +2,20 @@
#extension GL_ARB_explicit_attrib_location : enable
#endif
+#ifdef FRAGMENT_SHADER
+ precision highp float;
+ precision highp int;
+ precision highp sampler2DArray;
+ precision highp sampler2DShadow;
+ precision highp samplerCube;
+ precision highp sampler3D;
+ precision highp sampler2D;
+ #if __VERSION__ >= 310
+ precision highp sampler2DMS;
+ #endif
+
+#endif
+
#if defined GL_ES
# define hfloat highp float
# define hvec2 highp vec2
@@ -23,11 +37,25 @@
#endif
#if __VERSION__ >= 130
-# ifdef GL_ES
-out highp vec4 outFragColor;
-# else
-out vec4 outFragColor;
+
+#ifdef FRAGMENT_SHADER
+ #ifdef GL_ES
+ #ifdef BOUND_DRAW_BUFFER
+ #for i=0..15 ( #if $i<=BOUND_DRAW_BUFFER $0 #endif )
+ #if BOUND_DRAW_BUFFER == $i
+ layout( location = $i ) out highp vec4 outFragColor;
+ #else
+ layout( location = $i ) out highp vec4 outNOP$i;
+ #endif
+ #endfor
+ #else
+ out highp vec4 outFragColor;
+ #endif
+ #else
+ out vec4 outFragColor;
+ #endif
#endif
+
# define texture1D texture
# define texture2D texture
# define texture3D texture
@@ -84,4 +112,3 @@ mat3 inverse(mat3 m) {
+ (m[0][0] * m[1][1] - m[1][0] * m[0][1])) / determinant(m);
}
#endif
-
From fdea4ccaa7687afc1d95077afb8e927c02d8fdfb Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Wed, 11 Oct 2023 10:28:25 +0800
Subject: [PATCH 010/111] jme3-core:Fix frameGraph assertion error
---
.../src/main/java/com/jme3/renderer/framegraph/FrameGraph.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
index c50a5354ab..a90d64087d 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
@@ -100,10 +100,11 @@ public void execute(){
for(FGPass nextPass : passes){
nextPass.execute(renderContext);
}
+ finalized = false;
}
public void reset(){
- assert finalized;
+ assert !finalized;
for(FGPass nextPass : passes){
nextPass.reset();
}
From f60a03b9caaa147f4c1e6f23edacddff7ff93b3f Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Wed, 11 Oct 2023 11:29:18 +0800
Subject: [PATCH 011/111] jme3-core:Add some core code comments, delete Chinese
code comments
---
.../DeferredSinglePassLightingLogic.java | 18 ++++-
...eBasedDeferredSinglePassLightingLogic.java | 14 +++-
.../java/com/jme3/renderer/RenderManager.java | 70 ++++++++++++++++++-
.../jme3/renderer/framegraph/FGBindable.java | 2 +-
.../renderer/framegraph/FGBindingPass.java | 4 +-
.../framegraph/FGContainerBindableSink.java | 2 +-
.../renderer/framegraph/FGRenderContext.java | 1 +
.../com/jme3/renderer/queue/RenderQueue.java | 3 +-
.../renderPass/DeferredShadingPass.java | 2 +-
.../jme3/renderer/renderPass/GBufferPass.java | 5 +-
10 files changed, 101 insertions(+), 20 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java
index 440783c4be..ef50d4cfbb 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java
@@ -60,6 +60,18 @@
import java.util.EnumSet;
import java.util.List;
+/**
+ * DeferredShading.
+ *
+ * This is a standard DeferredShading, without any optimizations, but it should be faster than Forward when there are complex scenes and lots of lights. It is suitable for deferred rendering scenarios with simple requirements. There are some ways to optimize it:
+ * A few involved drawing proxy geometry that approximated the bounds of each type of light and evaluating lighting by sampling from the G buffer for each fragment that the geometry touched. This can be implemented with varying complexity of proxy geometry.
+ * Some implementations just used billboarded quads with enough width and height in world space to approximate the bounds of the area that the light influences. For instance a point light would just have a quad with a width and height the same as the lights radius of influence.
+ * Other implementations actually draw 3D proxy geometry like spheres for point lights and cones for spotlights.
+ *
+ * These implementations have the issue that they require many additional samples of the G buffer. Each light still needs to sample the G buffer for each texture that it has; in my case 4 textures. So each fragment of the G buffer gets sampled 4 * the number of lights affecting that fragment.
+ * Additionally these techniques incur a lot of overdraw since many of the proxy geometry objects will overlap and cannot be culled most of the time.
+ * @author JohnKkk
+ */
public final class DeferredSinglePassLightingLogic extends DefaultTechniqueDefLogic {
private final static String _S_LIGHT_CULL_DRAW_STAGE = "Light_Cull_Draw_Stage";
private static final String DEFINE_DEFERRED_SINGLE_PASS_LIGHTING = "DEFERRED_SINGLE_PASS_LIGHTING";
@@ -69,9 +81,9 @@ public final class DeferredSinglePassLightingLogic extends DefaultTechniqueDefLo
private static final String DEFINE_NB_SKY_LIGHT_AND_REFLECTION_PROBES = "NB_SKY_LIGHT_AND_REFLECTION_PROBES";
private static final RenderState ADDITIVE_LIGHT = new RenderState();
private boolean bUseTexturePackMode = true;
- // 避免过多的光源
+ // Avoid too many lights
private static final int MAX_LIGHT_NUM = 9046;
- // 使用texture来一次性存储大量光源数据,避免多次绘制
+ // Use textures to store large amounts of light data at once, avoiding multiple draw calls
private Texture2D lightData1;
private Texture2D lightData2;
private Texture2D lightData3;
@@ -453,7 +465,7 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry
// lightCount.setValue(VarType.Int, count);
lightCount.setValue(VarType.Int, this.lightNum);
while (nbRenderedLights < count) {
- // todo:采用第二种方法优化deferred,则这里使用当前类的geometrys(rect,sphere)进行绘制,而不使用这个传递进来的geometry(或者在外部传递两个geometry,一个rect一个sphereinstance)
+ // todo:Optimize deferred using the second method, here use the geometrys (rect, sphere) of the current class for drawing, instead of using the geometry passed in (or pass two geometry externally, one rect one sphereinstance)
nbRenderedLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, nbRenderedLights, isLightCullStageDraw, lastTexUnit);
renderer.setShader(shader);
renderMeshFromGeometry(renderer, geometry);
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
index 8290293870..680d38d2ca 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
@@ -31,6 +31,14 @@
import java.util.List;
/**
+ * Tile-based DeferredShading.
+ *
+ * Tile-based deferred shading utilizes the overhead of one-sample MRT and efficient culling of lights to accelerate deferred rendering.
+ * The implementation details here separate the data into three main parts:
+ * 1.Global Light List contains light properties(lightData1+lightData2+lightData3).
+ * 2.The light index list contains light indices to the global light list(lightsIndexData).
+ * 3.Light grid contains an offset and size of the light list for each tile(lightsDecodeData).
+ * https://www.digipen.edu/sites/default/files/public/docs/theses/denis-ishmukhametov-master-of-science-in-computer-science-thesis-efficient-tile-based-deferred-shading-pipeline.pdf
* @author JohnKkk
*/
public class TileBasedDeferredSinglePassLightingLogic extends DefaultTechniqueDefLogic{
@@ -51,9 +59,9 @@ public class TileBasedDeferredSinglePassLightingLogic extends DefaultTechniqueDe
private static final String TILE_LIGHT_OFFSET_SIZE = "g_TileLightOffsetSize";
private static final RenderState ADDITIVE_LIGHT = new RenderState();
private boolean bUseTexturePackMode = true;
- // 避免过多的光源
+ // Avoid too many lights
private static final int MAX_LIGHT_NUM = 9046;
- // 使用texture来一次性存储大量光源数据,避免多次绘制
+ // Use textures to store large amounts of light data at once, avoiding multiple draw calls
private Texture2D lightData1;
private Texture2D lightData2;
private Texture2D lightData3;
@@ -820,7 +828,7 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry
// The lights passed in here must be PointLights with valid radii. Another approach is to fill tiles with infinite range Lights.
if(count > 0){
- // 从RenderManager获取tileInfo
+ // Get tileInfo from RenderManager
tileInfo = renderManager.getTileInfo();
int tileSize = tileInfo.tileSize;
int tileWidth = tileInfo.tileWidth;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
index f855ad15af..1e0d45f811 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
@@ -63,8 +63,10 @@
import com.jme3.shader.Shader;
import com.jme3.shader.UniformBinding;
import com.jme3.shader.UniformBindingManager;
+import com.jme3.shader.VarType;
import com.jme3.system.NullRenderer;
import com.jme3.system.Timer;
+import com.jme3.texture.FrameBuffer;
import com.jme3.util.SafeArrayList;
import java.util.ArrayList;
import java.util.Collections;
@@ -86,8 +88,10 @@ public class RenderManager {
private int curMaxDeferredShadingLightNum = 1024;
// TileInfo
private TileBasedDeferredSinglePassLightingLogic.TileInfo tileInfo;
- // todo:Since glTexImage is not used to dynamically adjust lightIndex size currently, this tileSize needs to be set cautiously.
- private int curTileSize = 64;
+ private int forceTileSize = 0;
+ // If ForceTileSize is not specified, curTileSize is calculated each frame by dividing viewport horizontal width by NumberTileDivisions.
+ private int curTileSize = -1;
+ private int numberTileDivisions = 4;
// frameGraph=============================================================================↓
private IRenderGeometry iRenderGeometry;
private boolean useFramegraph = true;
@@ -150,6 +154,7 @@ public String getInfo(){
private LightFilter lightFilter = new DefaultLightFilter();
private TechniqueDef.LightMode preferredLightMode = TechniqueDef.LightMode.MultiPass;
private int singlePassLightBatchSize = 1;
+ private MatParamOverride boundDrawBufferId=new MatParamOverride(VarType.Int,"BoundDrawBuffer",0);
/**
@@ -160,6 +165,7 @@ public String getInfo(){
*/
public RenderManager(Renderer renderer) {
this.renderer = renderer;
+ this.forcedOverrides.add(boundDrawBufferId);
if(useFramegraph){
frameGraph = new FrameGraph(new FGRenderContext(null, null, null));
gBufferPass = new GBufferPass();
@@ -174,6 +180,31 @@ public RenderManager(Renderer renderer) {
}
}
+ /**
+ * then the number of tiles per frame is dynamically calculated based on NumberTileDivisions and current viewport width.
+ * @param numberTileDivisions defaultValue is 4
+ */
+ public void setNumberTileDivisions(int numberTileDivisions) {
+ this.numberTileDivisions = numberTileDivisions;
+ }
+
+ public int getNumberTileDivisions() {
+ return numberTileDivisions;
+ }
+
+ /**
+ * Tile-based DeferredShading divides the screen into multiple tiles, then assigns lights to corresponding tiles for rendering. In theory, the number of tiles should be set as powers of 2, such as 32, 64 etc, but it can be set larger depending on usage.
+ * 0 means auto calculate, then the number of tiles per frame is dynamically calculated based on NumberTileDivisions and current viewport width.
+ * @param forceTileSize
+ */
+ public void setForceTileSize(int forceTileSize) {
+ this.forceTileSize = forceTileSize;
+ }
+
+ public int getForceTileSize() {
+ return forceTileSize;
+ }
+
/**
* EnableFrameGraph?
* @param useFramegraph
@@ -771,6 +802,12 @@ public void renderGeometry(Geometry geom) {
setWorldMatrix(geom.getWorldMatrix());
}
+ // Use material override to pass the current target index (used in api such as GL ES that do not support glDrawBuffer)
+ FrameBuffer currentFb = this.renderer.getCurrentFrameBuffer();
+ if (currentFb != null && !currentFb.isMultiTarget()) {
+ this.boundDrawBufferId.setValue(currentFb.getTargetIndex());
+ }
+
// Perform light filtering if we have a light filter.
LightList lightList = geom.getWorldLightList();
@@ -1370,7 +1407,7 @@ public void renderViewPort(ViewPort vp, float tpf) {
frameGraph.addPass(deferredShadingPass);
}
else if(curRenderPath == RenderPath.TiledDeferred){
- curTileSize = getCurrentCamera().getWidth() / 4;
+ curTileSize = forceTileSize > 0 ? forceTileSize : (getCurrentCamera().getWidth() / numberTileDivisions);
int tileWidth = (int)(viewWidth / curTileSize);
int tileHeight = (int)(viewHeight / curTileSize);
setTileInfo(curTileSize, tileWidth, tileHeight, tileWidth * tileHeight);
@@ -1548,4 +1585,31 @@ public void render(float tpf, boolean mainFrameBufferActive) {
}
}
}
+
+ /**
+ * Returns true if the draw buffer target id is passed to the shader.
+ *
+ * @return True if the draw buffer target id is passed to the shaders.
+ */
+ public boolean getPassDrawBufferTargetIdToShaders() {
+ return this.forcedOverrides.contains(boundDrawBufferId);
+ }
+
+ /**
+ * Enable or disable passing the draw buffer target id to the shaders. This
+ * is needed to handle FrameBuffer.setTargetIndex correctly in some
+ * backends.
+ *
+ * @param v
+ * True to enable, false to disable (default is true)
+ */
+ public void setPassDrawBufferTargetIdToShaders(boolean v) {
+ if (v) {
+ if (!this.forcedOverrides.contains(boundDrawBufferId)) {
+ this.forcedOverrides.add(boundDrawBufferId);
+ }
+ } else {
+ this.forcedOverrides.remove(boundDrawBufferId);
+ }
+ }
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java
index e58f0082f8..7fb23b2f38 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java
@@ -5,7 +5,7 @@
package com.jme3.renderer.framegraph;
/**
- *
+ *FGBindable can be any resource that needs binding (such as state machine, FBO, Texture, Paramater...)
* @author JohnKkk
*/
public abstract class FGBindable {
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java
index 35f165fbcb..38e9916c9b 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java
@@ -7,7 +7,7 @@
import java.util.ArrayList;
/**
- *
+ *A FGBindingPass represents a Pass that needs to perform state machine binding, ShaderResource binding, FrameBuffer binding and other operations.
* @author JohnKkk
*/
public class FGBindingPass extends FGPass{
@@ -30,7 +30,7 @@ public void addBindSink(String name){
}
public void bindAll(FGRenderContext renderContext){
- // 绑定所有对象
+ // Bind all objects
for(FGBindable bind : binds){
bind.bind(renderContext);
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java
index 9987fb5cd7..d015234fc3 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java
@@ -7,7 +7,7 @@
import java.util.ArrayList;
/**
- *
+ *FGContainerBindableSink is used to proxy a FGSink, and also has the role of FGBindable. Typically, a Sink needed by a Pass may be a Bindable object.
* @author JohnKkk
*/
public class FGContainerBindableSink extends FGSink{
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java
index 6bc35a3891..72c933e181 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java
@@ -5,6 +5,7 @@
import com.jme3.renderer.queue.RenderQueue;
/**
+ * In order to be compatible with existing logic, FGRenderContext is currently just a local proxy, and may gradually replace the existing state machine manager in the future.
* @author JohnKkk
*/
public class FGRenderContext {
diff --git a/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java b/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java
index 1952629d60..326c52da91 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java
@@ -284,13 +284,12 @@ private void renderGeometryList(GeometryList list, RenderManager rm, Camera cam,
}
if (clear) {
list.clear();
- // BEGIN-JME3@JohnKkk以便进行后续RendererPath渲染
+ // In order to perform subsequent RenderPath rendering
if(tempList.size() > 0){
for(int i = 0;i < tempList.size();i++){
list.add(tempList.get(i));
}
}
- // END-JME3
}
}
else{
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredShadingPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredShadingPass.java
index bb8f157817..5fc201093c 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredShadingPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredShadingPass.java
@@ -92,7 +92,7 @@ public void dispatchPassSetup(RenderQueue renderQueue) {
@Override
public boolean drawGeometry(RenderManager rm, Geometry geom) {
- // 不处理任何队列中的绘制
+ // Does not process any drawing in queues and always returns true, because we perform a RectDraw internally
return true;
}
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java
index 6c24da297d..8079b397a1 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java
@@ -119,8 +119,6 @@ public void reshape(Renderer renderer, ViewPort vp, int w, int h){
gBufferData1 = new Texture2D(w, h, Image.Format.RGBA16F);
gBufferData2 = new Texture2D(w, h, Image.Format.RGBA16F);
gBufferData3 = new Texture2D(w, h, Image.Format.RGBA32F); // The third buffer provides 32-bit floating point to store high-precision information, such as normals
- // todo:后续调整为Depth24Stencil8,然后使用一个SceneColorFBO用于渲染所有3D部分,然后将其color_attach_0复制到BackBuffer中
- // todo:然后开启DepthTest绘制最后的所有GUI
this.getSinks().clear();
// Depth16/Depth32/Depth32F provide higher precision to prevent clipping when camera gets close, but it seems some devices do not support copying Depth16/Depth32/Depth32F to default FrameBuffer.
gBufferData4 = new Texture2D(w, h, Image.Format.Depth);
@@ -153,7 +151,6 @@ public boolean drawGeometry(RenderManager rm, Geometry geom) {
if(material.getMaterialDef().getTechniqueDefs(rm.getForcedTechnique()) == null)return false;
rm.renderGeometry(geom);
if(material.getActiveTechnique() != null){
- // todo:应该使用一个统一的材质材质,其中根据shadingModeId分开着色
if(material.getMaterialDef().getTechniqueDefs(S_GBUFFER_PASS) != null){
LightList lights = geom.getFilterWorldLights();
for(Light light : lights){
@@ -161,7 +158,7 @@ public boolean drawGeometry(RenderManager rm, Geometry geom) {
tempLights.add(light);
}
}
- // todo:无论是否拥有lights,只要包含GBufferPass的材质物体都会执行DeferredShading,根据shadingModelId着色
+ // Whether it has lights or not, material objects containing GBufferPass will perform DeferredShading, and shade according to shadingModelId
bHasDraw = true;
return true;
}
From b7f0b5892246369dafb730ee9f21fe1e440b198c Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Thu, 12 Oct 2023 13:36:26 +0800
Subject: [PATCH 012/111] jme3-core:Fix bugs existed in shadingModel
---
.../DeferredSinglePassLightingLogic.java | 11 +++-
...eBasedDeferredSinglePassLightingLogic.java | 12 +++-
.../java/com/jme3/renderer/RenderManager.java | 12 ++--
.../jme3/renderer/framegraph/FGVarSource.java | 4 ++
.../jme3/renderer/renderPass/GBufferPass.java | 10 ++-
.../Common/MatDefs/Misc/ColoredTextured.j3md | 19 ++++++
.../Misc/ColoredTexturedGBufferPack.frag | 19 ++++++
.../Common/MatDefs/Misc/Unshaded.j3md | 35 ++++++++++
.../MatDefs/Misc/UnshadedGBufferPack.frag | 65 +++++++++++++++++++
.../ShadingCommon/DeferredShading.frag | 3 +-
.../TileBasedDeferredShading.frag | 3 +-
.../jme3test/renderpath/RenderPathHelper.java | 54 +++++++++++++++
12 files changed, 233 insertions(+), 14 deletions(-)
create mode 100644 jme3-core/src/main/resources/Common/MatDefs/Misc/ColoredTexturedGBufferPack.frag
create mode 100644 jme3-core/src/main/resources/Common/MatDefs/Misc/UnshadedGBufferPack.frag
create mode 100644 jme3-examples/src/main/java/jme3test/renderpath/RenderPathHelper.java
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java
index ef50d4cfbb..3bb9ea5472 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java
@@ -464,12 +464,19 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry
int count = lights.size();
// lightCount.setValue(VarType.Int, count);
lightCount.setValue(VarType.Int, this.lightNum);
- while (nbRenderedLights < count) {
- // todo:Optimize deferred using the second method, here use the geometrys (rect, sphere) of the current class for drawing, instead of using the geometry passed in (or pass two geometry externally, one rect one sphereinstance)
+ if(count == 0){
nbRenderedLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, nbRenderedLights, isLightCullStageDraw, lastTexUnit);
renderer.setShader(shader);
renderMeshFromGeometry(renderer, geometry);
}
+ else{
+ while (nbRenderedLights < count) {
+ // todo:Optimize deferred using the second method, here use the geometrys (rect, sphere) of the current class for drawing, instead of using the geometry passed in (or pass two geometry externally, one rect one sphereinstance)
+ nbRenderedLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, nbRenderedLights, isLightCullStageDraw, lastTexUnit);
+ renderer.setShader(shader);
+ renderMeshFromGeometry(renderer, geometry);
+ }
+ }
}
else{
int batchSize = renderManager.getSinglePassLightBatchSize();
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
index 680d38d2ca..d29350bb9c 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
@@ -858,12 +858,13 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry
}
// update tiles
+ LightFrustum lightFrustum = null;
for(int i = 0;i < count;i++){
// filterLights(remove ambientLight,lightprobe...)
if(lights.get(i).getType() == Light.Type.Ambient || lights.get(i).getType() == Light.Type.Probe)continue;
- _lightFrustum = lightClip(lights.get(i));
- if(_lightFrustum != null){
- tilesUpdate(tileSize, tileWidth, tileHeight, tileNum, tiles, _lightFrustum, i);
+ lightFrustum = lightClip(lights.get(i));
+ if(lightFrustum != null){
+ tilesUpdate(tileSize, tileWidth, tileHeight, tileNum, tiles, lightFrustum, i);
}
else{
// full tilesLight
@@ -880,6 +881,11 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry
renderMeshFromGeometry(renderer, geometry);
}
}
+ else{
+ nbRenderedLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, nbRenderedLights, isLightCullStageDraw, lastTexUnit);
+ renderer.setShader(shader);
+ renderMeshFromGeometry(renderer, geometry);
+ }
}
else{
// Do not use this branch, but keep it for possible future use
diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
index 1e0d45f811..f2f373d52e 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
@@ -1346,11 +1346,6 @@ public void renderViewPort(ViewPort vp, float tpf) {
if(useFramegraph){
RenderPath curRenderPath = vp.getRenderPath() == RenderPath.None ? renderPath : vp.getRenderPath();
- frameGraph.reset();
- frameGraph.getRenderContext().renderManager = this;
- frameGraph.getRenderContext().renderQueue = vp.getQueue();
- frameGraph.getRenderContext().viewPort = vp;
-
if (prof!=null) prof.vpStep(VpStep.BeginRender, vp, null);
SafeArrayList processors = vp.getProcessors();
@@ -1395,6 +1390,11 @@ public void renderViewPort(ViewPort vp, float tpf) {
}
}
+ frameGraph.reset();
+ frameGraph.getRenderContext().renderManager = this;
+ frameGraph.getRenderContext().renderQueue = vp.getQueue();
+ frameGraph.getRenderContext().viewPort = vp;
+
if(curRenderPath == RenderPath.Deferred){
frameGraph.addPass(gBufferPass);
deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_0, gBufferPass.getName() + "." + GBufferPass.S_RT_0);
@@ -1403,6 +1403,7 @@ public void renderViewPort(ViewPort vp, float tpf) {
deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_3, gBufferPass.getName() + "." + GBufferPass.S_RT_3);
deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_4, gBufferPass.getName() + "." + GBufferPass.S_RT_4);
deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_LIGHT_DATA, gBufferPass.getName() + "." + GBufferPass.S_LIGHT_DATA);
+ deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_EXECUTE_STATE, gBufferPass.getName() + "." + GBufferPass.S_EXECUTE_STATE);
deferredShadingPass.setSinkLinkage(FGGlobal.S_DEFAULT_FB, gBufferPass.getName() + "." + GBufferPass.S_FB);
frameGraph.addPass(deferredShadingPass);
}
@@ -1419,6 +1420,7 @@ else if(curRenderPath == RenderPath.TiledDeferred){
tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_4, gBufferPass.getName() + "." + GBufferPass.S_RT_4);
tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_LIGHT_DATA, gBufferPass.getName() + "." + GBufferPass.S_LIGHT_DATA);
tileDeferredShadingPass.setSinkLinkage(FGGlobal.S_DEFAULT_FB, gBufferPass.getName() + "." + GBufferPass.S_FB);
+ tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_EXECUTE_STATE, gBufferPass.getName() + "." + GBufferPass.S_EXECUTE_STATE);
frameGraph.addPass(tileDeferredShadingPass);
}
frameGraph.addPass(opaquePass);
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java
index 97fb197457..6b0723e307 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java
@@ -22,6 +22,10 @@ public FGVarSource(String name, T value) {
varBindableProxy = new FGVarBindableProxy(value);
}
+ public void setValue(T t){
+ varBindableProxy.value = t;
+ }
+
@Override
public void postLinkValidate() {
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java
index 8079b397a1..7ef1061068 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java
@@ -34,7 +34,8 @@ public class GBufferPass extends OpaquePass{
public final static String S_EXECUTE_STATE = "EXECUTE_STATE";
private final LightList lightData = new LightList(null);
private final List tempLights = new ArrayList();
- private boolean bHasDraw;
+ private Boolean bHasDraw = new Boolean(false);
+ private FGVarSource bHasDrawVarSource = null;
// gBuffer
private FrameBuffer gBuffer;
private Texture2D gBufferData0 = null;
@@ -78,6 +79,7 @@ public void executeDrawCommandList(FGRenderContext renderContext) {
vp.setOutputFrameBuffer(opfb);
renderContext.renderManager.getRenderer().setBackgroundColor(opClearColor);
renderContext.renderManager.getRenderer().setFrameBuffer(vp.getOutputFrameBuffer());
+ bHasDrawVarSource.setValue(bHasDraw);
if(bHasDraw){
for(Light light : tempLights){
lightData.add(light);
@@ -92,12 +94,15 @@ public void reset() {
super.reset();
tempLights.clear();
lightData.clear();
+ bHasDraw = false;
+ bHasDrawVarSource.setValue(bHasDraw);
}
public void reshape(Renderer renderer, ViewPort vp, int w, int h){
boolean recreate = false;
if(gBuffer != null){
if(frameBufferWidth != w || frameBufferHeight != h){
+ gBuffer.dispose();
gBuffer.deleteObject(renderer);
frameBufferWidth = w;
@@ -140,7 +145,8 @@ public void reshape(Renderer renderer, ViewPort vp, int w, int h){
registerSource(new FGRenderTargetSource(S_RT_3, rt3));
registerSource(new FGRenderTargetSource(S_RT_4, rt4));
registerSource(new DeferredLightDataSource(S_LIGHT_DATA, lightData));
- registerSource(new FGVarSource(S_EXECUTE_STATE, bHasDraw));
+ bHasDrawVarSource = new FGVarSource(S_EXECUTE_STATE, bHasDraw);
+ registerSource(bHasDrawVarSource);
registerSource(new FGFramebufferSource(S_FB, gBuffer));
}
}
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Misc/ColoredTextured.j3md b/jme3-core/src/main/resources/Common/MatDefs/Misc/ColoredTextured.j3md
index 86b1d8e212..87a294ef17 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Misc/ColoredTextured.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/Misc/ColoredTextured.j3md
@@ -5,6 +5,13 @@ MaterialDef Colored Textured {
Int BoundDrawBuffer
Texture2D ColorMap
Color Color (Color)
+
+ // Context GBuffer Data
+ Texture2D Context_InGBuff0
+ Texture2D Context_InGBuff1
+ Texture2D Context_InGBuff2
+ Texture2D Context_InGBuff3
+ Texture2D Context_InGBuff4
}
Technique {
@@ -19,5 +26,17 @@ MaterialDef Colored Textured {
}
}
+ Technique GBufferPass{
+ VertexShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Misc/ColoredTextured.vert
+ FragmentShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Misc/ColoredTexturedGBufferPack.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+ Defines {
+ BOUND_DRAW_BUFFER: BoundDrawBuffer
+ }
+ }
+
}
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Misc/ColoredTexturedGBufferPack.frag b/jme3-core/src/main/resources/Common/MatDefs/Misc/ColoredTexturedGBufferPack.frag
new file mode 100644
index 0000000000..bc0d0f7567
--- /dev/null
+++ b/jme3-core/src/main/resources/Common/MatDefs/Misc/ColoredTexturedGBufferPack.frag
@@ -0,0 +1,19 @@
+#import "Common/ShaderLib/Deferred.glsllib"
+// shading model
+#import "Common/ShaderLib/ShadingModel.glsllib"
+
+varying vec2 texCoord;
+
+uniform sampler2D m_ColorMap;
+uniform vec4 m_Color;
+
+void main(){
+ vec4 texColor = texture2D(m_ColorMap, texCoord);
+ vec4 color = vec4(mix(m_Color.rgb, texColor.rgb, texColor.a), 1.0);
+
+
+ Context_OutGBuff2.rgb = color.rgb;
+
+ // shading model id
+ Context_OutGBuff2.a = UNLIT + color.a * 0.1f;
+}
\ No newline at end of file
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md b/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md
index b5854c2a23..73c2658a1b 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md
@@ -63,6 +63,13 @@ MaterialDef Unshaded {
// 1.0 indicates 100% desaturation
Float DesaturationValue
+
+ // Context GBuffer Data
+ Texture2D Context_InGBuff0
+ Texture2D Context_InGBuff1
+ Texture2D Context_InGBuff2
+ Texture2D Context_InGBuff3
+ Texture2D Context_InGBuff4
}
Technique {
@@ -92,6 +99,34 @@ MaterialDef Unshaded {
}
}
+ Technique GBufferPass{
+ Pipeline Deferred
+ VertexShader GLSL310 GLSL300 GLSL150 GLSL100 : Common/MatDefs/Misc/Unshaded.vert
+ FragmentShader GLSL310 GLSL300 GLSL150 GLSL100 : Common/MatDefs/Misc/UnshadedGBufferPack.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ ViewProjectionMatrix
+ ViewMatrix
+ }
+
+ Defines {
+ BOUND_DRAW_BUFFER: BoundDrawBuffer
+ INSTANCING : UseInstancing
+ SEPARATE_TEXCOORD : SeparateTexCoord
+ HAS_COLORMAP : ColorMap
+ HAS_LIGHTMAP : LightMap
+ HAS_VERTEXCOLOR : VertexColor
+ HAS_POINTSIZE : PointSize
+ HAS_COLOR : Color
+ NUM_BONES : NumberOfBones
+ DISCARD_ALPHA : AlphaDiscardThreshold
+ NUM_MORPH_TARGETS: NumberOfMorphTargets
+ NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers
+ DESATURATION : DesaturationValue
+ }
+ }
+
Technique PreNormalPass {
VertexShader GLSL310 GLSL300 GLSL150 GLSL100: Common/MatDefs/SSAO/normal.vert
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Misc/UnshadedGBufferPack.frag b/jme3-core/src/main/resources/Common/MatDefs/Misc/UnshadedGBufferPack.frag
new file mode 100644
index 0000000000..0cbfdeb00c
--- /dev/null
+++ b/jme3-core/src/main/resources/Common/MatDefs/Misc/UnshadedGBufferPack.frag
@@ -0,0 +1,65 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+#import "Common/ShaderLib/Deferred.glsllib"
+// shading model
+#import "Common/ShaderLib/ShadingModel.glsllib"
+
+#if defined(HAS_GLOWMAP) || defined(HAS_COLORMAP) || (defined(HAS_LIGHTMAP) && !defined(SEPARATE_TEXCOORD))
+ #define NEED_TEXCOORD1
+#endif
+
+#if defined(DISCARD_ALPHA)
+ uniform float m_AlphaDiscardThreshold;
+#endif
+
+uniform vec4 m_Color;
+uniform sampler2D m_ColorMap;
+uniform sampler2D m_LightMap;
+
+#ifdef DESATURATION
+ uniform float m_DesaturationValue;
+#endif
+
+varying vec2 texCoord1;
+varying vec2 texCoord2;
+
+varying vec4 vertColor;
+
+void main(){
+ vec4 color = vec4(1.0);
+
+ #ifdef HAS_COLORMAP
+ color *= texture2D(m_ColorMap, texCoord1);
+ #endif
+
+ #ifdef HAS_VERTEXCOLOR
+ color *= vertColor;
+ #endif
+
+ #ifdef HAS_COLOR
+ color *= m_Color;
+ #endif
+
+ #ifdef HAS_LIGHTMAP
+ #ifdef SEPARATE_TEXCOORD
+ color.rgb *= texture2D(m_LightMap, texCoord2).rgb;
+ #else
+ color.rgb *= texture2D(m_LightMap, texCoord1).rgb;
+ #endif
+ #endif
+
+ #if defined(DISCARD_ALPHA)
+ if(color.a < m_AlphaDiscardThreshold){
+ discard;
+ }
+ #endif
+
+ #ifdef DESATURATION
+ vec3 gray = vec3(dot(vec3(0.2126,0.7152,0.0722), color.rgb));
+ color.rgb = vec3(mix(color.rgb, gray, m_DesaturationValue));
+ #endif
+
+ Context_OutGBuff2.rgb = color.rgb;
+
+ // shading model id
+ Context_OutGBuff2.a = UNLIT + color.a * 0.1f;
+}
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag
index 89746d1b2e..c6852b7532 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag
@@ -226,6 +226,7 @@ void main(){
}
}
else if(shadingModelId == UNLIT){
- // todo:
+ gl_FragColor.rgb = shadingInfo.rgb;
+ gl_FragColor.a = min(fract(shadingInfo.a) * 10.0f, 0.0f);
}
}
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
index 0ea748bb90..83b49f1d7d 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
@@ -359,6 +359,7 @@ void main(){
}
}
else if(shadingModelId == UNLIT){
- // todo:
+ gl_FragColor.rgb = shadingInfo.rgb;
+ gl_FragColor.a = min(fract(shadingInfo.a) * 10.0f, 0.0f);
}
}
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/RenderPathHelper.java b/jme3-examples/src/main/java/jme3test/renderpath/RenderPathHelper.java
new file mode 100644
index 0000000000..50280a9303
--- /dev/null
+++ b/jme3-examples/src/main/java/jme3test/renderpath/RenderPathHelper.java
@@ -0,0 +1,54 @@
+package jme3test.renderpath;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.font.BitmapFont;
+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.renderer.RenderManager;
+
+public class RenderPathHelper implements ActionListener {
+ private RenderManager.RenderPath currentRenderPath;
+ private BitmapText hitText;
+ private RenderManager renderManager;
+ public RenderPathHelper(SimpleApplication simpleApplication){
+ renderManager = simpleApplication.getRenderManager();
+ currentRenderPath = renderManager.getRenderPath();
+ makeHudText(simpleApplication);
+ simpleApplication.getInputManager().addListener(this, "toggleRenderPath");
+ simpleApplication.getInputManager().addMapping("toggleRenderPath", new KeyTrigger(KeyInput.KEY_SPACE));
+ }
+
+ private void makeHudText(SimpleApplication simpleApplication) {
+ BitmapFont guiFont = simpleApplication.getAssetManager().loadFont("Interface/Fonts/Default.fnt");
+ hitText = new BitmapText(guiFont, false);
+ hitText.setSize(guiFont.getCharSet().getRenderedSize());
+ hitText.setText("RendererPath : "+ currentRenderPath.getInfo());
+ hitText.setLocalTranslation(0, simpleApplication.getCamera().getHeight(), 0);
+ simpleApplication.getGuiNode().attachChild(hitText);
+
+ // hit text
+ BitmapText title = new BitmapText(guiFont, false);
+ title.setSize(guiFont.getCharSet().getRenderedSize());
+ title.setText("Please press the SPACE to toggle the render path");
+ title.setLocalTranslation(0, simpleApplication.getCamera().getHeight() - 20, 0);
+ simpleApplication.getGuiNode().attachChild(title);
+ }
+ @Override
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if(name.equals("toggleRenderPath") && !isPressed){
+ if(currentRenderPath == RenderManager.RenderPath.Deferred){
+ currentRenderPath = RenderManager.RenderPath.TiledDeferred;
+ }
+ else if(currentRenderPath == RenderManager.RenderPath.TiledDeferred){
+ currentRenderPath = RenderManager.RenderPath.Forward;
+ }
+ else{
+ currentRenderPath = RenderManager.RenderPath.Deferred;
+ }
+ renderManager.setRenderPath(currentRenderPath);
+ hitText.setText("RendererPath : "+ currentRenderPath.getInfo());
+ }
+ }
+}
From e4862a65aad90cdf30f58af8def97c0e3eec297c Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Thu, 12 Oct 2023 13:38:06 +0800
Subject: [PATCH 013/111] jme3-examples:Add test case
"TestShadingModel.java,TestRenderPathPointDirectionalAndSpotLightShadows.java"
---
...thPointDirectionalAndSpotLightShadows.java | 147 ++++++++++++++++++
.../jme3test/renderpath/TestShadingModel.java | 137 ++++++++++++++++
2 files changed, 284 insertions(+)
create mode 100644 jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java
create mode 100644 jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java b/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java
new file mode 100644
index 0000000000..71b01573af
--- /dev/null
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TestRenderPathPointDirectionalAndSpotLightShadows.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2009-2021 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.renderpath;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.PointLight;
+import com.jme3.light.SpotLight;
+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.post.FilterPostProcessor;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.shadow.*;
+import jme3test.light.ShadowTestUIManager;
+
+/**
+ * This example shows all shadow types, check rendering performance under different rendering paths
+ * @author JohnKkk
+ */
+public class TestRenderPathPointDirectionalAndSpotLightShadows extends SimpleApplication {
+ public static final int SHADOWMAP_SIZE = 512;
+
+ public static void main(String[] args) {
+ TestRenderPathPointDirectionalAndSpotLightShadows app = new TestRenderPathPointDirectionalAndSpotLightShadows();
+ app.start();
+ }
+ private Node lightNode;
+ private SpotLight spotLight;
+
+ @Override
+ public void simpleInitApp() {
+ // Note that for this j3o Cube model, the value of vLightDir passed from vs to ps in MultPass LightModel is different from using SinglePass. See the lightComputeDir() function, there will be some differences when this function calculates in world space and view space. It's an existing bug in JME, so here we set it to use SinglePass instead.
+ renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass);
+ flyCam.setMoveSpeed(10);
+ cam.setLocation(new Vector3f(0.040581334f, 1.7745866f, 6.155161f));
+ cam.setRotation(new Quaternion(4.3868728E-5f, 0.9999293f, -0.011230096f, 0.0039059948f));
+
+
+ Node scene = (Node) assetManager.loadModel("Models/Test/CornellBox.j3o");
+ scene.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
+ rootNode.attachChild(scene);
+ rootNode.getChild("Cube").setShadowMode(RenderQueue.ShadowMode.Receive);
+ lightNode = (Node) rootNode.getChild("Lamp");
+ Geometry lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));
+ //Geometry lightMdl = new Geometry("Light", new Box(.1f,.1f,.1f));
+ lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ lightMdl.setShadowMode(RenderQueue.ShadowMode.Off);
+ lightNode.attachChild(lightMdl);
+ //lightMdl.setLocalTranslation(lightNode.getLocalTranslation());
+
+
+ Geometry box = new Geometry("box", new Box(0.2f, 0.2f, 0.2f));
+ //Geometry lightMdl = new Geometry("Light", new Box(.1f,.1f,.1f));
+ box.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
+ box.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
+ rootNode.attachChild(box);
+ box.setLocalTranslation(-1f, 0.5f, -2);
+
+ scene.getLocalLightList().get(0).setColor(ColorRGBA.Red);
+
+ PointLightShadowFilter plsf
+ = new PointLightShadowFilter(assetManager, SHADOWMAP_SIZE);
+ plsf.setLight((PointLight) scene.getLocalLightList().get(0));
+ plsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
+
+ //DIRECTIONAL LIGHT
+ DirectionalLight directionalLight = new DirectionalLight();
+ rootNode.addLight(directionalLight);
+ directionalLight.setColor(ColorRGBA.Blue);
+ directionalLight.setDirection(new Vector3f(-1f, -.2f, 0f));
+
+ DirectionalLightShadowFilter dlsf
+ = new DirectionalLightShadowFilter(assetManager, SHADOWMAP_SIZE*2, 4);
+ dlsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
+ dlsf.setLight(directionalLight);
+
+ //SPOT LIGHT
+ spotLight = new SpotLight();
+ spotLight.setDirection(new Vector3f(1f,-1f,0f));
+ spotLight.setPosition(new Vector3f(-1f,3f,0f));
+ spotLight.setSpotOuterAngle(0.5f);
+ spotLight.setColor(ColorRGBA.Green);
+ Sphere sphere = new Sphere(8, 8, .1f);
+ Geometry sphereGeometry = new Geometry("Sphere", sphere);
+ sphereGeometry.setLocalTranslation(-1f, 3f, 0f);
+ sphereGeometry.setMaterial(assetManager.loadMaterial("Common/Materials/WhiteColor.j3m"));
+ rootNode.attachChild(sphereGeometry);
+ rootNode.addLight(spotLight);
+
+ SpotLightShadowFilter slsf
+ = new SpotLightShadowFilter(assetManager, SHADOWMAP_SIZE);
+ slsf.setLight(spotLight);
+ slsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
+
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+ fpp.addFilter(plsf);
+ fpp.addFilter(dlsf);
+ fpp.addFilter(slsf);
+ viewPort.addProcessor(fpp);
+
+ new RenderPathHelper(this);
+ }
+
+ private float timeElapsed = 0.0f;
+ @Override
+ public void simpleUpdate(float tpf) {
+ timeElapsed += tpf;
+ lightNode.setLocalTranslation(FastMath.cos(timeElapsed), lightNode.getLocalTranslation().y, FastMath.sin(timeElapsed));
+ spotLight.setDirection(new Vector3f(FastMath.cos(-timeElapsed*.7f), -1.0f, FastMath.sin(-timeElapsed*.7f)));
+ }
+}
\ No newline at end of file
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java
new file mode 100644
index 0000000000..bdba06efa7
--- /dev/null
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TestShadingModel.java
@@ -0,0 +1,137 @@
+package jme3test.renderpath;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.environment.EnvironmentCamera;
+import com.jme3.environment.LightProbeFactory;
+import com.jme3.environment.generation.JobProgressAdapter;
+import com.jme3.environment.util.EnvMapUtils;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.LightProbe;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.ToneMapFilter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.texture.plugins.ktx.KTXLoader;
+import com.jme3.util.SkyFactory;
+import com.jme3.util.TangentBinormalGenerator;
+import com.jme3.util.mikktspace.MikktspaceTangentGenerator;
+
+/**
+ * This example demonstrates unified handling of several built-in shading models under the same render path.
+ * @author JohnKkk
+ */
+public class TestShadingModel extends SimpleApplication {
+ private DirectionalLight dl;
+
+ private float roughness = 0.0f;
+
+ private Node modelNode;
+ private int frame = 0;
+ private Material pbrMat;
+ private Geometry model;
+ private Node tex;
+
+ @Override
+ public void simpleInitApp() {
+
+ // UNLIT
+ Material unlitMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ unlitMat.setTexture("ColorMap", assetManager.loadTexture("Textures/Terrain/Pond/Pond.jpg"));
+ Sphere sp = new Sphere(15, 15, 1.0f);
+ Geometry unlitSphere = new Geometry("unlitSphere", sp);
+ unlitSphere.setLocalTranslation(-5, 0, 0);
+ unlitSphere.setLocalRotation(new Quaternion(new float[]{(float) Math.toRadians(-90), 0, 0}));
+ unlitSphere.setMaterial(unlitMat);
+ rootNode.attachChild(unlitSphere);
+
+ // LEGACY_LIGHTING
+ Geometry lightSphere = unlitSphere.clone(false);
+ TangentBinormalGenerator.generate(lightSphere.getMesh());
+ Material lightMat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");
+ lightSphere.setLocalTranslation(5, 0, 0);
+ lightSphere.setMaterial(lightMat);
+ rootNode.attachChild(lightSphere);
+
+ // STANDARD_LIGHTING
+ roughness = 1.0f;
+ assetManager.registerLoader(KTXLoader.class, "ktx");
+
+ viewPort.setBackgroundColor(ColorRGBA.White);
+ modelNode = new Node("modelNode");
+ model = (Geometry) assetManager.loadModel("Models/Tank/tank.j3o");
+ MikktspaceTangentGenerator.generate(model);
+ modelNode.attachChild(model);
+
+ dl = new DirectionalLight();
+ dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
+ rootNode.addLight(dl);
+ dl.setColor(ColorRGBA.White);
+ modelNode.setLocalScale(0.3f);
+ rootNode.attachChild(modelNode);
+
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+ int numSamples = context.getSettings().getSamples();
+ if (numSamples > 0) {
+ fpp.setNumSamples(numSamples);
+ }
+
+// fpp.addFilter(new FXAAFilter());
+ fpp.addFilter(new ToneMapFilter(Vector3f.UNIT_XYZ.mult(1.0f)));
+// fpp.addFilter(new SSAOFilter(0.5f, 3, 0.2f, 0.2f));
+ viewPort.addProcessor(fpp);
+
+ //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Sky_Cloudy.hdr", SkyFactory.EnvMapType.EquirectMap);
+ Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Path.hdr", SkyFactory.EnvMapType.EquirectMap);
+ //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Bright/BrightSky.dds", SkyFactory.EnvMapType.CubeMap);
+ //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/road.hdr", SkyFactory.EnvMapType.EquirectMap);
+ rootNode.attachChild(sky);
+
+ pbrMat = assetManager.loadMaterial("Models/Tank/tank.j3m");
+ model.setMaterial(pbrMat);
+
+
+ final EnvironmentCamera envCam = new EnvironmentCamera(256, new Vector3f(0, 3f, 0));
+ stateManager.attach(envCam);
+
+ new RenderPathHelper(this);
+ flyCam.setMoveSpeed(10.0f);
+ }
+
+ @Override
+ public void simpleRender(RenderManager rm) {
+ super.simpleRender(rm);
+ frame++;
+
+ if (frame == 2) {
+ modelNode.removeFromParent();
+ final LightProbe probe = LightProbeFactory.makeProbe(stateManager.getState(EnvironmentCamera.class), rootNode, new JobProgressAdapter() {
+
+ @Override
+ public void done(LightProbe result) {
+ System.err.println("Done rendering env maps");
+ tex = EnvMapUtils.getCubeMapCrossDebugViewWithMipMaps(result.getPrefilteredEnvMap(), assetManager);
+ }
+ });
+ probe.getArea().setRadius(100);
+ rootNode.addLight(probe);
+ //getStateManager().getState(EnvironmentManager.class).addEnvProbe(probe);
+
+ }
+ if (frame > 10 && modelNode.getParent() == null) {
+ rootNode.attachChild(modelNode);
+ }
+ }
+
+ public static void main(String[] args) {
+ TestShadingModel testShadingModel = new TestShadingModel();
+ testShadingModel.start();
+ }
+}
From 2475337e7012e0c0a2edfb57e59c2fe2007f2cb3 Mon Sep 17 00:00:00 2001
From: chenliming
Date: Tue, 17 Oct 2023 20:59:16 +0800
Subject: [PATCH 014/111] jme3-core:GBuffer data packing for terrain rendering
compatibility (unlit, lighting)
---
.../ScreenSpaceSubsurfaceScatteringPass.java | 9 +
.../ShadingCommon/DeferredShading.frag | 14 -
.../HeightBasedTerrainGBufferPack.frag | 83 +++
.../GBufferPack/TerrainGBufferPack.frag | 70 ++
.../TerrainLightingGBufferPack.frag | 627 ++++++++++++++++++
.../TerrainLightingGBufferPack.vert | 57 ++
.../MatDefs/Terrain/HeightBasedTerrain.j3md | 23 +
.../Common/MatDefs/Terrain/Terrain.j3md | 37 +-
.../MatDefs/Terrain/TerrainLighting.j3md | 69 ++
9 files changed, 974 insertions(+), 15 deletions(-)
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/renderPass/ScreenSpaceSubsurfaceScatteringPass.java
create mode 100644 jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/HeightBasedTerrainGBufferPack.frag
create mode 100644 jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/TerrainGBufferPack.frag
create mode 100644 jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/TerrainLightingGBufferPack.frag
create mode 100644 jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/TerrainLightingGBufferPack.vert
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/ScreenSpaceSubsurfaceScatteringPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/ScreenSpaceSubsurfaceScatteringPass.java
new file mode 100644
index 0000000000..6e7134f84a
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/ScreenSpaceSubsurfaceScatteringPass.java
@@ -0,0 +1,9 @@
+package com.jme3.renderer.renderPass;
+
+/**
+ * Subsurface Scattering.
+ * http://www.iryoku.com/screen-space-subsurface-scattering
+ * @author JohnKkk
+ */
+public class ScreenSpaceSubsurfaceScatteringPass extends OpaquePass{
+}
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag
index c6852b7532..7462ac8453 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag
@@ -194,20 +194,6 @@ void main(){
vec3 directLighting = diffuseColor.rgb *directDiffuse + directSpecular;
- // Workaround, since it is not possible to modify varying variables
- // #ifdef USE_REFLECTION
- // // Interpolate light specularity toward reflection color
- // // Multiply result by specular map
- // specularColor = mix(specularColor * light.y, refColor, refVec.w) * specularColor;
- // light.y = 1.0;
- // #endif
- //
- // #ifdef COLORRAMP
- // diffuseColor.rgb *= texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb;
- // specularColor.rgb *= texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb;
- // light.xy = vec2(1.0);
- // #endif
-
gl_FragColor.rgb += directLighting * spotFallOff;
#if defined(USE_TEXTURE_PACK_MODE)
i++;
diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/HeightBasedTerrainGBufferPack.frag b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/HeightBasedTerrainGBufferPack.frag
new file mode 100644
index 0000000000..9fe9f347a2
--- /dev/null
+++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/HeightBasedTerrainGBufferPack.frag
@@ -0,0 +1,83 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+#import "Common/ShaderLib/Deferred.glsllib"
+// shading model
+#import "Common/ShaderLib/ShadingModel.glsllib"
+uniform vec3 m_region1;
+uniform vec3 m_region2;
+uniform vec3 m_region3;
+uniform vec3 m_region4;
+
+uniform sampler2D m_region1ColorMap;
+uniform sampler2D m_region2ColorMap;
+uniform sampler2D m_region3ColorMap;
+uniform sampler2D m_region4ColorMap;
+uniform sampler2D m_slopeColorMap;
+
+uniform float m_slopeTileFactor;
+uniform float m_terrainSize;
+
+varying vec3 normal;
+varying vec4 position;
+
+vec4 GenerateTerrainColor() {
+ float height = position.y;
+ vec4 p = position / m_terrainSize;
+
+ vec3 blend = abs( normal );
+ blend = (blend -0.2) * 0.7;
+ blend = normalize(max(blend, 0.00001)); // Force weights to sum to 1.0 (very important!)
+ float b = (blend.x + blend.y + blend.z);
+ blend /= vec3(b, b, b);
+
+ vec4 terrainColor = vec4(0.0, 0.0, 0.0, 1.0);
+
+ float m_regionMin = 0.0;
+ float m_regionMax = 0.0;
+ float m_regionRange = 0.0;
+ float m_regionWeight = 0.0;
+
+ vec4 slopeCol1 = texture2D(m_slopeColorMap, p.yz * m_slopeTileFactor);
+ vec4 slopeCol2 = texture2D(m_slopeColorMap, p.xy * m_slopeTileFactor);
+
+ // Terrain m_region 1.
+ m_regionMin = m_region1.x;
+ m_regionMax = m_region1.y;
+ m_regionRange = m_regionMax - m_regionMin;
+ m_regionWeight = (m_regionRange - abs(height - m_regionMax)) / m_regionRange;
+ m_regionWeight = max(0.0, m_regionWeight);
+ terrainColor += m_regionWeight * texture2D(m_region1ColorMap, p.xz * m_region1.z);
+
+ // Terrain m_region 2.
+ m_regionMin = m_region2.x;
+ m_regionMax = m_region2.y;
+ m_regionRange = m_regionMax - m_regionMin;
+ m_regionWeight = (m_regionRange - abs(height - m_regionMax)) / m_regionRange;
+ m_regionWeight = max(0.0, m_regionWeight);
+ terrainColor += m_regionWeight * (texture2D(m_region2ColorMap, p.xz * m_region2.z));
+
+ // Terrain m_region 3.
+ m_regionMin = m_region3.x;
+ m_regionMax = m_region3.y;
+ m_regionRange = m_regionMax - m_regionMin;
+ m_regionWeight = (m_regionRange - abs(height - m_regionMax)) / m_regionRange;
+ m_regionWeight = max(0.0, m_regionWeight);
+ terrainColor += m_regionWeight * texture2D(m_region3ColorMap, p.xz * m_region3.z);
+
+ // Terrain m_region 4.
+ m_regionMin = m_region4.x;
+ m_regionMax = m_region4.y;
+ m_regionRange = m_regionMax - m_regionMin;
+ m_regionWeight = (m_regionRange - abs(height - m_regionMax)) / m_regionRange;
+ m_regionWeight = max(0.0, m_regionWeight);
+ terrainColor += m_regionWeight * texture2D(m_region4ColorMap, p.xz * m_region4.z);
+
+ return (blend.y * terrainColor + blend.x * slopeCol1 + blend.z * slopeCol2);
+}
+
+void main() {
+ vec4 color = GenerateTerrainColor();
+ Context_OutGBuff2.rgb = color.rgb;
+
+ // shading model id
+ Context_OutGBuff2.a = UNLIT + color.a * 0.1f;
+}
diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/TerrainGBufferPack.frag b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/TerrainGBufferPack.frag
new file mode 100644
index 0000000000..9f29382c19
--- /dev/null
+++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/TerrainGBufferPack.frag
@@ -0,0 +1,70 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+#import "Common/ShaderLib/Deferred.glsllib"
+// shading model
+#import "Common/ShaderLib/ShadingModel.glsllib"
+uniform sampler2D m_Alpha;
+uniform sampler2D m_Tex1;
+uniform sampler2D m_Tex2;
+uniform sampler2D m_Tex3;
+uniform float m_Tex1Scale;
+uniform float m_Tex2Scale;
+uniform float m_Tex3Scale;
+
+varying vec2 texCoord;
+
+#ifdef TRI_PLANAR_MAPPING
+ varying vec4 vVertex;
+ varying vec3 vNormal;
+#endif
+
+void main(void)
+{
+
+ // get the alpha value at this 2D texture coord
+ vec4 alpha = texture2D( m_Alpha, texCoord.xy );
+
+#ifdef TRI_PLANAR_MAPPING
+ // tri-planar texture bending factor for this fragment's normal
+ vec3 blending = abs( vNormal );
+ 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 = vVertex;
+
+ vec4 col1 = texture2D( m_Tex1, coords.yz * m_Tex1Scale );
+ vec4 col2 = texture2D( m_Tex1, coords.xz * m_Tex1Scale );
+ vec4 col3 = texture2D( m_Tex1, coords.xy * m_Tex1Scale );
+ // blend the results of the 3 planar projections.
+ vec4 tex1 = col1 * blending.x + col2 * blending.y + col3 * blending.z;
+
+ col1 = texture2D( m_Tex2, coords.yz * m_Tex2Scale );
+ col2 = texture2D( m_Tex2, coords.xz * m_Tex2Scale );
+ col3 = texture2D( m_Tex2, coords.xy * m_Tex2Scale );
+ // blend the results of the 3 planar projections.
+ vec4 tex2 = col1 * blending.x + col2 * blending.y + col3 * blending.z;
+
+ col1 = texture2D( m_Tex3, coords.yz * m_Tex3Scale );
+ col2 = texture2D( m_Tex3, coords.xz * m_Tex3Scale );
+ col3 = texture2D( m_Tex3, coords.xy * m_Tex3Scale );
+ // blend the results of the 3 planar projections.
+ vec4 tex3 = col1 * blending.x + col2 * blending.y + col3 * blending.z;
+
+#else
+ vec4 tex1 = texture2D( m_Tex1, texCoord.xy * m_Tex1Scale ); // Tile
+ vec4 tex2 = texture2D( m_Tex2, texCoord.xy * m_Tex2Scale ); // Tile
+ vec4 tex3 = texture2D( m_Tex3, texCoord.xy * m_Tex3Scale ); // Tile
+
+#endif
+
+ vec4 outColor = tex1 * alpha.r; // Red channel
+ outColor = mix( outColor, tex2, alpha.g ); // Green channel
+ outColor = mix( outColor, tex3, alpha.b ); // Blue channel
+
+ Context_OutGBuff2.rgb = outColor.rgb;
+ // shading model id
+ Context_OutGBuff2.a = UNLIT + outColor.a * 0.1f;
+}
+
diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/TerrainLightingGBufferPack.frag b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/TerrainLightingGBufferPack.frag
new file mode 100644
index 0000000000..92f1e6f231
--- /dev/null
+++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/TerrainLightingGBufferPack.frag
@@ -0,0 +1,627 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+#import "Common/ShaderLib/BlinnPhongLighting.glsllib"
+#import "Common/ShaderLib/Lighting.glsllib"
+#import "Common/ShaderLib/Deferred.glsllib"
+// shading model
+#import "Common/ShaderLib/ShadingModel.glsllib"
+
+uniform float m_Shininess;
+
+varying vec4 AmbientSum;
+varying vec4 DiffuseSum;
+varying vec4 SpecularSum;
+
+varying vec3 wTangent;
+varying vec3 wBinormal;
+varying vec3 wNormal;
+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 );
+ vec4 diffuseColor = vec4(1.0);
+
+ #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 DIFFUSEMAP
+ diffuseColor = texture2D(m_DiffuseMap, texCoord * m_DiffuseMap_0_scale);
+ #ifdef USE_ALPHA
+ alphaBlend.r *= diffuseColor.a;
+ #endif
+ diffuseColor *= alphaBlend.r;
+ #endif
+ #ifdef DIFFUSEMAP_1
+ vec4 diffuseColor1 = texture2D(m_DiffuseMap_1, texCoord * m_DiffuseMap_1_scale);
+ #ifdef USE_ALPHA
+ alphaBlend.g *= diffuseColor1.a;
+ #endif
+ diffuseColor = mix( diffuseColor, diffuseColor1, alphaBlend.g );
+ #endif
+ #ifdef DIFFUSEMAP_2
+ vec4 diffuseColor2 = texture2D(m_DiffuseMap_2, texCoord * m_DiffuseMap_2_scale);
+ #ifdef USE_ALPHA
+ alphaBlend.b *= diffuseColor2.a;
+ #endif
+ diffuseColor = mix( diffuseColor, diffuseColor2, alphaBlend.b );
+ #endif
+ #ifdef DIFFUSEMAP_3
+ vec4 diffuseColor3 = texture2D(m_DiffuseMap_3, texCoord * m_DiffuseMap_3_scale);
+ #ifdef USE_ALPHA
+ alphaBlend.a *= diffuseColor3.a;
+ #endif
+ diffuseColor = mix( diffuseColor, diffuseColor3, alphaBlend.a );
+ #endif
+
+ #ifdef ALPHAMAP_1
+ #ifdef DIFFUSEMAP_4
+ vec4 diffuseColor4 = texture2D(m_DiffuseMap_4, texCoord * m_DiffuseMap_4_scale);
+ #ifdef USE_ALPHA
+ alphaBlend1.r *= diffuseColor4.a;
+ #endif
+ diffuseColor = mix( diffuseColor, diffuseColor4, alphaBlend1.r );
+ #endif
+ #ifdef DIFFUSEMAP_5
+ vec4 diffuseColor5 = texture2D(m_DiffuseMap_5, texCoord * m_DiffuseMap_5_scale);
+ #ifdef USE_ALPHA
+ alphaBlend1.g *= diffuseColor5.a;
+ #endif
+ diffuseColor = mix( diffuseColor, diffuseColor5, alphaBlend1.g );
+ #endif
+ #ifdef DIFFUSEMAP_6
+ vec4 diffuseColor6 = texture2D(m_DiffuseMap_6, texCoord * m_DiffuseMap_6_scale);
+ #ifdef USE_ALPHA
+ alphaBlend1.b *= diffuseColor6.a;
+ #endif
+ diffuseColor = mix( diffuseColor, diffuseColor6, alphaBlend1.b );
+ #endif
+ #ifdef DIFFUSEMAP_7
+ vec4 diffuseColor7 = texture2D(m_DiffuseMap_7, texCoord * m_DiffuseMap_7_scale);
+ #ifdef USE_ALPHA
+ alphaBlend1.a *= diffuseColor7.a;
+ #endif
+ 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);
+ #ifdef USE_ALPHA
+ alphaBlend2.r *= diffuseColor8.a;
+ #endif
+ diffuseColor = mix( diffuseColor, diffuseColor8, alphaBlend2.r );
+ #endif
+ #ifdef DIFFUSEMAP_9
+ vec4 diffuseColor9 = texture2D(m_DiffuseMap_9, texCoord * m_DiffuseMap_9_scale);
+ #ifdef USE_ALPHA
+ alphaBlend2.g *= diffuseColor9.a;
+ #endif
+ diffuseColor = mix( diffuseColor, diffuseColor9, alphaBlend2.g );
+ #endif
+ #ifdef DIFFUSEMAP_10
+ vec4 diffuseColor10 = texture2D(m_DiffuseMap_10, texCoord * m_DiffuseMap_10_scale);
+ #ifdef USE_ALPHA
+ alphaBlend2.b *= diffuseColor10.a;
+ #endif
+ diffuseColor = mix( diffuseColor, diffuseColor10, alphaBlend2.b );
+ #endif
+ #ifdef DIFFUSEMAP_11
+ vec4 diffuseColor11 = texture2D(m_DiffuseMap_11, texCoord * m_DiffuseMap_11_scale);
+ #ifdef USE_ALPHA
+ alphaBlend2.a *= diffuseColor11.a;
+ #endif
+ 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(wTangent.xyz) , normalize(wBinormal.xyz) , normalize(wNormal.xyz));
+ normal = tbnMat * normal;
+ #else
+ vec3 normal = wNormal;
+ #endif
+
+ //-------------------------------
+ // pack phongLighting parameters
+ //-------------------------------
+ Context_OutGBuff3.xyz = normal;
+ Context_OutGBuff0 = diffuseColor * DiffuseSum;
+ Context_OutGBuff1.rgb = SpecularSum.rgb * 100.0f + AmbientSum.rgb * 0.01f;
+ Context_OutGBuff1.a = m_Shininess;
+ // shading model id
+ Context_OutGBuff2.a = LEGACY_LIGHTING;
+}
diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/TerrainLightingGBufferPack.vert b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/TerrainLightingGBufferPack.vert
new file mode 100644
index 0000000000..b1284d28f3
--- /dev/null
+++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/TerrainLightingGBufferPack.vert
@@ -0,0 +1,57 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+uniform mat4 g_WorldViewProjectionMatrix;
+uniform mat3 g_WorldNormalMatrix;
+
+uniform vec4 g_AmbientLightColor;
+
+attribute vec3 inPosition;
+attribute vec3 inNormal;
+attribute vec2 inTexCoord;
+attribute vec4 inTangent;
+
+varying vec3 wNormal;
+varying vec2 texCoord;
+varying vec3 wTangent;
+varying vec3 wBinormal;
+
+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
+
+ wNormal = normalize(g_WorldNormalMatrix * 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)
+ wTangent = g_WorldNormalMatrix * inTangent.xyz;
+ wBinormal = cross(wNormal, wTangent)* inTangent.w;
+ #endif
+
+ AmbientSum = g_AmbientLightColor;
+ DiffuseSum = vec4(1.0);
+ SpecularSum = vec4(0.0);
+
+
+#ifdef TRI_PLANAR_MAPPING
+ wVertex = vec4(inPosition,0.0);
+ wNormal = inNormal;
+#endif
+
+}
\ No newline at end of file
diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/HeightBasedTerrain.j3md b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/HeightBasedTerrain.j3md
index d2bfa0c01d..9be9124757 100644
--- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/HeightBasedTerrain.j3md
+++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/HeightBasedTerrain.j3md
@@ -23,6 +23,13 @@ MaterialDef Terrain {
Vector3 region2
Vector3 region3
Vector3 region4
+
+ // Context GBuffer Data
+ Texture2D Context_InGBuff0
+ Texture2D Context_InGBuff1
+ Texture2D Context_InGBuff2
+ Texture2D Context_InGBuff3
+ Texture2D Context_InGBuff4
}
Technique {
@@ -40,6 +47,22 @@ MaterialDef Terrain {
}
}
+ Technique GBufferPass{
+ Pipeline Deferred
+ VertexShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Terrain/HeightBasedTerrain.vert
+ FragmentShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Terrain/GBufferPack/HeightBasedTerrainGBufferPack.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ WorldMatrix
+ NormalMatrix
+ }
+
+ Defines {
+ BOUND_DRAW_BUFFER: BoundDrawBuffer
+ }
+ }
+
Technique {
}
}
\ No newline at end of file
diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/Terrain.j3md b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/Terrain.j3md
index 1ac3b21dc1..4841cd8105 100644
--- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/Terrain.j3md
+++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/Terrain.j3md
@@ -13,12 +13,19 @@ MaterialDef Terrain {
Float Tex1Scale
Float Tex2Scale
Float Tex3Scale
+
+ // Context GBuffer Data
+ Texture2D Context_InGBuff0
+ Texture2D Context_InGBuff1
+ Texture2D Context_InGBuff2
+ Texture2D Context_InGBuff3
+ Texture2D Context_InGBuff4
}
Technique {
VertexShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Terrain/Terrain.vert
FragmentShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Terrain/Terrain.frag
-
+
WorldParameters {
WorldViewProjectionMatrix
}
@@ -28,6 +35,34 @@ MaterialDef Terrain {
TRI_PLANAR_MAPPING : useTriPlanarMapping
}
}
+
+ Technique GBufferPass{
+ Pipeline Deferred
+ VertexShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Terrain/Terrain.vert
+ FragmentShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Terrain/GBufferPack/TerrainGBufferPack.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ ViewProjectionMatrix
+ ViewMatrix
+ }
+
+ Defines {
+ BOUND_DRAW_BUFFER: BoundDrawBuffer
+ INSTANCING : UseInstancing
+ SEPARATE_TEXCOORD : SeparateTexCoord
+ HAS_COLORMAP : ColorMap
+ HAS_LIGHTMAP : LightMap
+ HAS_VERTEXCOLOR : VertexColor
+ HAS_POINTSIZE : PointSize
+ HAS_COLOR : Color
+ NUM_BONES : NumberOfBones
+ DISCARD_ALPHA : AlphaDiscardThreshold
+ NUM_MORPH_TARGETS: NumberOfMorphTargets
+ NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers
+ DESATURATION : DesaturationValue
+ }
+ }
Technique {
}
diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.j3md b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.j3md
index 341ef1c683..ea31874abb 100644
--- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.j3md
+++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/TerrainLighting.j3md
@@ -103,6 +103,13 @@ MaterialDef Terrain Lighting {
// The glow color of the object
Color GlowColor
+
+ // Context GBuffer Data
+ Texture2D Context_InGBuff0
+ Texture2D Context_InGBuff1
+ Texture2D Context_InGBuff2
+ Texture2D Context_InGBuff3
+ Texture2D Context_InGBuff4
}
Technique {
@@ -236,6 +243,68 @@ MaterialDef Terrain Lighting {
}
}
+ Technique GBufferPass{
+
+ Pipeline Deferred
+
+ VertexShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Terrain/GBufferPack/TerrainLightingGBufferPack.vert
+ FragmentShader GLSL300 GLSL150 GLSL100: Common/MatDefs/Terrain/GBufferPack/TerrainLightingGBufferPack.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ WorldNormalMatrix
+ }
+
+ Defines {
+ BOUND_DRAW_BUFFER: BoundDrawBuffer
+ 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
+
+ USE_ALPHA : useDiffuseAlpha
+ }
+ }
Technique PreShadow {
From 81c1362c1b590820e937558a17aacf10a18bcfee Mon Sep 17 00:00:00 2001
From: chenliming
Date: Tue, 17 Oct 2023 21:00:45 +0800
Subject: [PATCH 015/111] jme3-examples: Added two renderPath sample codes.
Added terrain unlit shading model test code; Added terrain lighting shading
model test code;
---
.../jme3test/renderpath/RenderPathHelper.java | 25 +-
.../TerrainTestAdvancedRenderPath.java | 344 ++++++++++++++++++
.../TerrainTestAndroidRenderPath.java | 199 ++++++++++
3 files changed, 564 insertions(+), 4 deletions(-)
create mode 100644 jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAdvancedRenderPath.java
create mode 100644 jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAndroidRenderPath.java
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/RenderPathHelper.java b/jme3-examples/src/main/java/jme3test/renderpath/RenderPathHelper.java
index 50280a9303..9ace9b4e13 100644
--- a/jme3-examples/src/main/java/jme3test/renderpath/RenderPathHelper.java
+++ b/jme3-examples/src/main/java/jme3test/renderpath/RenderPathHelper.java
@@ -6,18 +6,34 @@
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
+import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
public class RenderPathHelper implements ActionListener {
private RenderManager.RenderPath currentRenderPath;
private BitmapText hitText;
private RenderManager renderManager;
+ private Vector3f hitLocation = new Vector3f(0, 0, 0);
+ private String keyHit = "SPACE";
+ private int keyInput = KeyInput.KEY_SPACE;
public RenderPathHelper(SimpleApplication simpleApplication){
renderManager = simpleApplication.getRenderManager();
currentRenderPath = renderManager.getRenderPath();
makeHudText(simpleApplication);
+ hitLocation.set(0, simpleApplication.getCamera().getHeight(), 0);
simpleApplication.getInputManager().addListener(this, "toggleRenderPath");
- simpleApplication.getInputManager().addMapping("toggleRenderPath", new KeyTrigger(KeyInput.KEY_SPACE));
+ simpleApplication.getInputManager().addMapping("toggleRenderPath", new KeyTrigger(keyInput));
+ }
+
+ public RenderPathHelper(SimpleApplication simpleApplication, Vector3f hitLocation, int keyInput, String keyHit){
+ renderManager = simpleApplication.getRenderManager();
+ currentRenderPath = renderManager.getRenderPath();
+ this.hitLocation.set(hitLocation);
+ this.keyInput = keyInput;
+ this.keyHit = keyHit;
+ makeHudText(simpleApplication);
+ simpleApplication.getInputManager().addListener(this, "toggleRenderPath");
+ simpleApplication.getInputManager().addMapping("toggleRenderPath", new KeyTrigger(keyInput));
}
private void makeHudText(SimpleApplication simpleApplication) {
@@ -25,14 +41,15 @@ private void makeHudText(SimpleApplication simpleApplication) {
hitText = new BitmapText(guiFont, false);
hitText.setSize(guiFont.getCharSet().getRenderedSize());
hitText.setText("RendererPath : "+ currentRenderPath.getInfo());
- hitText.setLocalTranslation(0, simpleApplication.getCamera().getHeight(), 0);
+ hitText.setLocalTranslation(hitLocation);
simpleApplication.getGuiNode().attachChild(hitText);
// hit text
BitmapText title = new BitmapText(guiFont, false);
title.setSize(guiFont.getCharSet().getRenderedSize());
- title.setText("Please press the SPACE to toggle the render path");
- title.setLocalTranslation(0, simpleApplication.getCamera().getHeight() - 20, 0);
+ title.setText("Please press the " + keyHit + " to toggle the render path");
+ title.setLocalTranslation(hitLocation);
+ title.getLocalTranslation().y -= 20;
simpleApplication.getGuiNode().attachChild(title);
}
@Override
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAdvancedRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAdvancedRenderPath.java
new file mode 100644
index 0000000000..c40353608c
--- /dev/null
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAdvancedRenderPath.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2009-2021 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.renderpath;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.asset.TextureKey;
+import com.jme3.bounding.BoundingBox;
+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.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.material.TechniqueDef;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.debug.Arrow;
+import com.jme3.terrain.geomipmap.TerrainLodControl;
+import com.jme3.terrain.geomipmap.TerrainQuad;
+import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;
+import com.jme3.terrain.heightmap.AbstractHeightMap;
+import com.jme3.terrain.heightmap.ImageBasedHeightMap;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture.WrapMode;
+import com.jme3.util.SkyFactory;
+
+/**
+ * Uses the terrain's lighting texture with normal maps and lights.
+ *
+ * @author bowens,johnKkk
+ */
+public class TerrainTestAdvancedRenderPath extends SimpleApplication {
+
+ private TerrainQuad terrain;
+ private Material matTerrain;
+ private Material matWire;
+ private boolean wireframe = false;
+ private boolean triPlanar = false;
+ private float dirtScale = 16;
+ private float darkRockScale = 32;
+ private float pinkRockScale = 32;
+ private float riverRockScale = 80;
+ private float grassScale = 32;
+ private float brickScale = 128;
+ private float roadScale = 200;
+
+
+ public static void main(String[] args) {
+ TerrainTestAdvancedRenderPath app = new TerrainTestAdvancedRenderPath();
+ app.start();
+ }
+
+ @Override
+ public void initialize() {
+ super.initialize();
+
+ loadHintText();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ setupKeys();
+
+ // First, we load up our textures and the heightmap texture for the terrain
+
+ // TERRAIN TEXTURE material
+ matTerrain = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md");
+ matTerrain.setBoolean("useTriPlanarMapping", false);
+ matTerrain.setFloat("Shininess", 0.0f);
+
+ // ALPHA map (for splat textures)
+ matTerrain.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alpha1.png"));
+ matTerrain.setTexture("AlphaMap_1", assetManager.loadTexture("Textures/Terrain/splat/alpha2.png"));
+ // this material also supports 'AlphaMap_2', so you can get up to 12 diffuse textures
+
+ // HEIGHTMAP image (for the terrain heightmap)
+ TextureKey hmKey = new TextureKey("Textures/Terrain/splat/mountains512.png", false);
+ Texture heightMapImage = assetManager.loadTexture(hmKey);
+
+ // DIRT texture, Diffuse textures 0 to 3 use the first AlphaMap
+ Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");
+ dirt.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("DiffuseMap", dirt);
+ matTerrain.setFloat("DiffuseMap_0_scale", dirtScale);
+
+ // DARK ROCK texture
+ Texture darkRock = assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg");
+ darkRock.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("DiffuseMap_1", darkRock);
+ matTerrain.setFloat("DiffuseMap_1_scale", darkRockScale);
+
+ // PINK ROCK texture
+ Texture pinkRock = assetManager.loadTexture("Textures/Terrain/Rock/Rock.PNG");
+ pinkRock.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("DiffuseMap_2", pinkRock);
+ matTerrain.setFloat("DiffuseMap_2_scale", pinkRockScale);
+
+ // RIVER ROCK texture, this texture will use the next alphaMap: AlphaMap_1
+ Texture riverRock = assetManager.loadTexture("Textures/Terrain/Pond/Pond.jpg");
+ riverRock.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("DiffuseMap_3", riverRock);
+ matTerrain.setFloat("DiffuseMap_3_scale", riverRockScale);
+
+ // GRASS texture
+ Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
+ grass.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("DiffuseMap_4", grass);
+ matTerrain.setFloat("DiffuseMap_4_scale", grassScale);
+
+ // BRICK texture
+ Texture brick = assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg");
+ brick.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("DiffuseMap_5", brick);
+ matTerrain.setFloat("DiffuseMap_5_scale", brickScale);
+
+ // ROAD texture
+ Texture road = assetManager.loadTexture("Textures/Terrain/splat/road.jpg");
+ road.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("DiffuseMap_6", road);
+ matTerrain.setFloat("DiffuseMap_6_scale", roadScale);
+
+
+ // diffuse textures 0 to 3 use AlphaMap
+ // diffuse textures 4 to 7 use AlphaMap_1
+ // diffuse textures 8 to 11 use AlphaMap_2
+
+
+ // NORMAL MAPS
+ Texture normalMapDirt = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png");
+ normalMapDirt.setWrap(WrapMode.Repeat);
+ Texture normalMapPinkRock = assetManager.loadTexture("Textures/Terrain/Rock/Rock_normal.png");
+ normalMapPinkRock.setWrap(WrapMode.Repeat);
+ Texture normalMapGrass = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg");
+ normalMapGrass.setWrap(WrapMode.Repeat);
+ Texture normalMapRoad = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png");
+ normalMapRoad.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("NormalMap", normalMapDirt);
+ matTerrain.setTexture("NormalMap_1", normalMapPinkRock);
+ matTerrain.setTexture("NormalMap_2", normalMapPinkRock);
+ matTerrain.setTexture("NormalMap_4", normalMapGrass);
+ matTerrain.setTexture("NormalMap_6", normalMapRoad);
+
+
+ // WIREFRAME material (used to debug the terrain, only useful for this test case)
+ matWire = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ matWire.getAdditionalRenderState().setWireframe(true);
+ matWire.setColor("Color", ColorRGBA.Green);
+
+ createSky();
+
+ // CREATE HEIGHTMAP
+ AbstractHeightMap heightmap = null;
+ try {
+ heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.3f);
+ heightmap.load();
+ heightmap.smooth(0.9f, 1);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ /*
+ * Here we create the actual terrain. The tiles will be 65x65, and the total size of the
+ * terrain will be 513x513. It uses the heightmap we created to generate the height values.
+ */
+ /*
+ * Optimal terrain patch size is 65 (64x64).
+ * The total size is up to you. At 1025, it ran fine for me (200+FPS), however at
+ * size=2049 it got really slow. But that is a jump from 2 million to 8 million triangles...
+ */
+ terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap());//, new LodPerspectiveCalculatorFactory(getCamera(), 4)); // add this in to see it use entropy for LOD calculations
+ TerrainLodControl control = new TerrainLodControl(terrain, getCamera());
+ control.setLodCalculator( new DistanceLodCalculator(65, 2.7f) ); // patch size, and a multiplier
+ terrain.addControl(control);
+ terrain.setMaterial(matTerrain);
+ terrain.setModelBound(new BoundingBox());
+ terrain.updateModelBound();
+ terrain.setLocalTranslation(0, -100, 0);
+ terrain.setLocalScale(1f, 1f, 1f);
+ rootNode.attachChild(terrain);
+
+ //Material debugMat = assetManager.loadMaterial("Common/Materials/VertexColor.j3m");
+ //terrain.generateDebugTangents(debugMat);
+
+ DirectionalLight light = new DirectionalLight();
+ light.setDirection((new Vector3f(-0.1f, -0.1f, -0.1f)).normalize());
+ rootNode.addLight(light);
+
+ cam.setLocation(new Vector3f(0, 10, -10));
+ cam.lookAtDirection(new Vector3f(0, -1.5f, -1).normalizeLocal(), Vector3f.UNIT_Y);
+ flyCam.setMoveSpeed(400);
+
+ rootNode.attachChild(createAxisMarker(20));
+
+ new RenderPathHelper(this, new Vector3f(0, cam.getHeight() / 2, 0), KeyInput.KEY_K, "K");
+ renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass);
+ }
+
+ public void loadHintText() {
+ BitmapText hintText = new BitmapText(guiFont);
+ hintText.setSize(guiFont.getCharSet().getRenderedSize());
+ hintText.setLocalTranslation(0, getCamera().getHeight(), 0);
+ hintText.setText("Press T to toggle wireframe, P to toggle tri-planar texturing");
+ guiNode.attachChild(hintText);
+ }
+
+ private void setupKeys() {
+ flyCam.setMoveSpeed(50);
+ inputManager.addMapping("wireframe", new KeyTrigger(KeyInput.KEY_T));
+ inputManager.addListener(actionListener, "wireframe");
+ inputManager.addMapping("triPlanar", new KeyTrigger(KeyInput.KEY_P));
+ inputManager.addListener(actionListener, "triPlanar");
+ inputManager.addMapping("WardIso", new KeyTrigger(KeyInput.KEY_9));
+ inputManager.addListener(actionListener, "WardIso");
+ inputManager.addMapping("DetachControl", new KeyTrigger(KeyInput.KEY_0));
+ inputManager.addListener(actionListener, "DetachControl");
+ }
+ final private ActionListener actionListener = new ActionListener() {
+
+ @Override
+ public void onAction(String name, boolean pressed, float tpf) {
+ if (name.equals("wireframe") && !pressed) {
+ wireframe = !wireframe;
+ if (wireframe) {
+ terrain.setMaterial(matWire);
+ } else {
+ terrain.setMaterial(matTerrain);
+ }
+ } else if (name.equals("triPlanar") && !pressed) {
+ triPlanar = !triPlanar;
+ if (triPlanar) {
+ matTerrain.setBoolean("useTriPlanarMapping", true);
+ // Planar textures don't use the mesh's texture coordinates but real-world coordinates,
+ // so we need to convert these texture coordinate scales into real-world scales, so it looks
+ // the same when we switch to/from tri-planar mode. (1024 is the alphamap size.)
+ matTerrain.setFloat("DiffuseMap_0_scale", 1f / (1024f / dirtScale));
+ matTerrain.setFloat("DiffuseMap_1_scale", 1f / (1024f / darkRockScale));
+ matTerrain.setFloat("DiffuseMap_2_scale", 1f / (1024f / pinkRockScale));
+ matTerrain.setFloat("DiffuseMap_3_scale", 1f / (1024f / riverRockScale));
+ matTerrain.setFloat("DiffuseMap_4_scale", 1f / (1024f / grassScale));
+ matTerrain.setFloat("DiffuseMap_5_scale", 1f / (1024f / brickScale));
+ matTerrain.setFloat("DiffuseMap_6_scale", 1f / (1024f / roadScale));
+ } else {
+ matTerrain.setBoolean("useTriPlanarMapping", false);
+
+ matTerrain.setFloat("DiffuseMap_0_scale", dirtScale);
+ matTerrain.setFloat("DiffuseMap_1_scale", darkRockScale);
+ matTerrain.setFloat("DiffuseMap_2_scale", pinkRockScale);
+ matTerrain.setFloat("DiffuseMap_3_scale", riverRockScale);
+ matTerrain.setFloat("DiffuseMap_4_scale", grassScale);
+ matTerrain.setFloat("DiffuseMap_5_scale", brickScale);
+ matTerrain.setFloat("DiffuseMap_6_scale", roadScale);
+
+
+
+ }
+ } if (name.equals("DetachControl") && !pressed) {
+ TerrainLodControl control = terrain.getControl(TerrainLodControl.class);
+ if (control != null)
+ control.detachAndCleanUpControl();
+ else {
+ control = new TerrainLodControl(terrain, cam);
+ terrain.addControl(control);
+ }
+
+ }
+ }
+ };
+
+ private void createSky() {
+ Texture west = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_west.jpg");
+ Texture east = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_east.jpg");
+ Texture north = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_north.jpg");
+ Texture south = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_south.jpg");
+ Texture up = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_up.jpg");
+ Texture down = assetManager.loadTexture("Textures/Sky/Lagoon/lagoon_down.jpg");
+
+ Spatial sky = SkyFactory.createSky(assetManager, west, east, north, south, up, down);
+ rootNode.attachChild(sky);
+ }
+
+ protected Node createAxisMarker(float arrowSize) {
+
+ Material redMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ redMat.getAdditionalRenderState().setWireframe(true);
+ redMat.setColor("Color", ColorRGBA.Red);
+
+ Material greenMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ greenMat.getAdditionalRenderState().setWireframe(true);
+ greenMat.setColor("Color", ColorRGBA.Green);
+
+ Material blueMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ blueMat.getAdditionalRenderState().setWireframe(true);
+ blueMat.setColor("Color", ColorRGBA.Blue);
+
+ Node axis = new Node();
+
+ // create arrows
+ Geometry arrowX = new Geometry("arrowX", new Arrow(new Vector3f(arrowSize, 0, 0)));
+ arrowX.setMaterial(redMat);
+ Geometry arrowY = new Geometry("arrowY", new Arrow(new Vector3f(0, arrowSize, 0)));
+ arrowY.setMaterial(greenMat);
+ Geometry arrowZ = new Geometry("arrowZ", new Arrow(new Vector3f(0, 0, arrowSize)));
+ arrowZ.setMaterial(blueMat);
+ axis.attachChild(arrowX);
+ axis.attachChild(arrowY);
+ axis.attachChild(arrowZ);
+
+ //axis.setModelBound(new BoundingBox());
+ return axis;
+ }
+}
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAndroidRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAndroidRenderPath.java
new file mode 100644
index 0000000000..6e455689dd
--- /dev/null
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TerrainTestAndroidRenderPath.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2009-2021 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.renderpath;
+
+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.DirectionalLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.terrain.geomipmap.TerrainLodControl;
+import com.jme3.terrain.geomipmap.TerrainQuad;
+import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;
+import com.jme3.terrain.heightmap.AbstractHeightMap;
+import com.jme3.terrain.heightmap.ImageBasedHeightMap;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture.WrapMode;
+
+/**
+ * Demonstrates how to use terrain on Android.
+ * The only difference is it uses a much smaller heightmap, so it won't use
+ * all the device's memory.
+ *
+ * @author bowens,johnKkk
+ */
+public class TerrainTestAndroidRenderPath extends SimpleApplication {
+
+ private TerrainQuad terrain;
+ private Material matRock;
+ private Material matWire;
+ private boolean wireframe = false;
+ private boolean triPlanar = false;
+ private float grassScale = 64;
+ private float dirtScale = 16;
+ private float rockScale = 128;
+
+ public static void main(String[] args) {
+ TerrainTestAndroidRenderPath app = new TerrainTestAndroidRenderPath();
+ app.start();
+ }
+
+ @Override
+ public void initialize() {
+ super.initialize();
+
+ loadHintText();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ setupKeys();
+
+ // First, we load up our textures and the heightmap texture for the terrain
+
+ // TERRAIN TEXTURE material
+ matRock = new Material(assetManager, "Common/MatDefs/Terrain/Terrain.j3md");
+ matRock.setBoolean("useTriPlanarMapping", false);
+
+ // ALPHA map (for splat textures)
+ matRock.setTexture("Alpha", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png"));
+
+ // HEIGHTMAP image (for the terrain heightmap)
+ Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains128.png");
+
+ // GRASS texture
+ Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
+ grass.setWrap(WrapMode.Repeat);
+ matRock.setTexture("Tex1", grass);
+ matRock.setFloat("Tex1Scale", grassScale);
+
+ // DIRT texture
+ Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");
+ dirt.setWrap(WrapMode.Repeat);
+ matRock.setTexture("Tex2", dirt);
+ matRock.setFloat("Tex2Scale", dirtScale);
+
+ // ROCK texture
+ Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg");
+ rock.setWrap(WrapMode.Repeat);
+ matRock.setTexture("Tex3", rock);
+ matRock.setFloat("Tex3Scale", rockScale);
+
+ // WIREFRAME material
+ matWire = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ matWire.getAdditionalRenderState().setWireframe(true);
+ matWire.setColor("Color", ColorRGBA.Green);
+
+ // CREATE HEIGHTMAP
+ AbstractHeightMap heightmap = null;
+ try {
+ heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 1f);
+ heightmap.load();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ /*
+ * Here we create the actual terrain. The tiles will be 33x33, and the total size of the
+ * terrain will be 129x129. It uses the heightmap we created to generate the height values.
+ */
+ terrain = new TerrainQuad("terrain", 33, 129, heightmap.getHeightMap());
+ TerrainLodControl control = new TerrainLodControl(terrain, getCamera());
+ control.setLodCalculator( new DistanceLodCalculator(33, 2.7f) ); // patch size, and a multiplier
+ terrain.addControl(control);
+ terrain.setMaterial(matRock);
+ terrain.setLocalTranslation(0, -100, 0);
+ terrain.setLocalScale(8f, 0.5f, 8f);
+ rootNode.attachChild(terrain);
+
+ DirectionalLight light = new DirectionalLight();
+ light.setDirection((new Vector3f(-0.5f, -1f, -0.5f)).normalize());
+ rootNode.addLight(light);
+
+ cam.setLocation(new Vector3f(0, 10, -10));
+ cam.setRotation(new Quaternion(0.01f, 0.964871f, -0.25966f, 0.0387f));
+
+ new RenderPathHelper(this, new Vector3f(0, cam.getHeight() / 2, 0), KeyInput.KEY_K, "K");
+ }
+
+ public void loadHintText() {
+ BitmapText hintText = new BitmapText(guiFont);
+ hintText.setSize(guiFont.getCharSet().getRenderedSize());
+ hintText.setLocalTranslation(0, getCamera().getHeight(), 0);
+ hintText.setText("Press T to toggle wireframe, P to toggle tri-planar texturing");
+ guiNode.attachChild(hintText);
+ }
+
+ private void setupKeys() {
+ flyCam.setMoveSpeed(50);
+ inputManager.addMapping("wireframe", new KeyTrigger(KeyInput.KEY_T));
+ inputManager.addListener(actionListener, "wireframe");
+ inputManager.addMapping("triPlanar", new KeyTrigger(KeyInput.KEY_P));
+ inputManager.addListener(actionListener, "triPlanar");
+ }
+ final private ActionListener actionListener = new ActionListener() {
+
+ @Override
+ public void onAction(String name, boolean pressed, float tpf) {
+ if (name.equals("wireframe") && !pressed) {
+ wireframe = !wireframe;
+ if (wireframe) {
+ terrain.setMaterial(matWire);
+ } else {
+ terrain.setMaterial(matRock);
+ }
+ } else if (name.equals("triPlanar") && !pressed) {
+ triPlanar = !triPlanar;
+ if (triPlanar) {
+ matRock.setBoolean("useTriPlanarMapping", true);
+ // Planar textures don't use the mesh's texture coordinates but real-world coordinates,
+ // so we need to convert these texture-coordinate scales into real-world scales so it looks
+ // the same when we switch to tri-planar mode.
+ matRock.setFloat("Tex1Scale", 1f / (512f / grassScale));
+ matRock.setFloat("Tex2Scale", 1f / (512f / dirtScale));
+ matRock.setFloat("Tex3Scale", 1f / (512f / rockScale));
+ } else {
+ matRock.setBoolean("useTriPlanarMapping", false);
+ matRock.setFloat("Tex1Scale", grassScale);
+ matRock.setFloat("Tex2Scale", dirtScale);
+ matRock.setFloat("Tex3Scale", rockScale);
+ }
+ }
+ }
+ };
+}
From 05eb006d50c85b16dfc2165dd4fb72147f209351 Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Wed, 18 Oct 2023 16:05:11 +0800
Subject: [PATCH 016/111] jme3-core:Add rendering path support for
AdvancedPBRTerrain
---
.../MatDefs/Light/PBRLightingGBufferPack.frag | 4 +-
.../ShadingCommon/DeferredShading.frag | 3 +-
.../TileBasedDeferredShading.frag | 3 +-
.../ShaderLib/SkyLightReflectionProbe.glsllib | 5 +-
.../TestPBRTerrainAdvancedRenderPath.java | 457 ++++++++++++++++
.../MatDefs/Terrain/AdvancedPBRTerrain.j3md | 82 +++
.../AdvancedPBRTerrainGBufferPack.frag | 516 ++++++++++++++++++
7 files changed, 1065 insertions(+), 5 deletions(-)
create mode 100644 jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java
create mode 100644 jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/AdvancedPBRTerrainGBufferPack.frag
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLightingGBufferPack.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLightingGBufferPack.frag
index 6784362a83..e3079c696b 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLightingGBufferPack.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLightingGBufferPack.frag
@@ -233,7 +233,7 @@ void main(){
ao = aoRoughnessMetallicValue.rrr;
#endif
- float ndotv = max( dot( normal, viewDir ),0.0);
+ //float ndotv = max( dot( normal, viewDir ),0.0);
#if defined(EMISSIVE) || defined (EMISSIVEMAP)
#ifdef EMISSIVEMAP
@@ -254,5 +254,5 @@ void main(){
Context_OutGBuff0.a = alpha;
// shading model id
- Context_OutGBuff2.a = STANDARD_LIGHTING;
+ Context_OutGBuff2.a = STANDARD_LIGHTING + 0.01f;
}
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag
index 7462ac8453..ee0de9c81b 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag
@@ -136,6 +136,7 @@ void main(){
vec3 ao = min(fract(buff0.rgb) * 10.0f, vec3(1.0f));
vec3 fZero = min(fract(buff1.rgb) * 10.0f, vec3(0.5f));
float Roughness = buff1.a;
+ float indoorSunLightExposure = fract(shadingInfo.a) * 100.0f;
float alpha = buff0.a;
vec4 n1n2 = texture2D(Context_InGBuff3, innerTexCoord);
vec3 normal = octDecode(n1n2.xy);
@@ -202,7 +203,7 @@ void main(){
#endif
}
// skyLight and reflectionProbe
- vec3 skyLightAndReflection = renderSkyLightAndReflectionProbes(viewDir, vPos, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao);
+ vec3 skyLightAndReflection = renderSkyLightAndReflectionProbes(indoorSunLightExposure, viewDir, vPos, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao);
gl_FragColor.rgb += skyLightAndReflection;
gl_FragColor.rgb += emissive;
gl_FragColor.a = alpha;
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
index 83b49f1d7d..915c99fa53 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
@@ -238,6 +238,7 @@ void main(){
vec3 ao = min(fract(buff0.rgb) * 10.0f, vec3(1.0f));
vec3 fZero = min(fract(buff1.rgb) * 10.0f, vec3(0.5f));
float Roughness = buff1.a;
+ float indoorSunLightExposure = fract(shadingInfo.a) * 100.0f;
float alpha = buff0.a;
vec4 n1n2 = texture2D(Context_InGBuff3, innerTexCoord);
vec3 normal = octDecode(n1n2.xy);
@@ -349,7 +350,7 @@ void main(){
}
}
// skyLight and reflectionProbe
- vec3 skyLightAndReflection = renderSkyLightAndReflectionProbes(viewDir, vPos, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao);
+ vec3 skyLightAndReflection = renderSkyLightAndReflectionProbes(indoorSunLightExposure, viewDir, vPos, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao);
gl_FragColor.rgb += skyLightAndReflection;
gl_FragColor.rgb += emissive;
gl_FragColor.a = alpha;
diff --git a/jme3-core/src/main/resources/Common/ShaderLib/SkyLightReflectionProbe.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/SkyLightReflectionProbe.glsllib
index 4063da45a7..54a103f869 100644
--- a/jme3-core/src/main/resources/Common/ShaderLib/SkyLightReflectionProbe.glsllib
+++ b/jme3-core/src/main/resources/Common/ShaderLib/SkyLightReflectionProbe.glsllib
@@ -15,7 +15,7 @@ uniform samplerCube g_ReflectionEnvMap3;
uniform vec3 g_ShCoeffs3[9];
uniform mat4 g_SkyLightData3;
#endif
-vec3 renderSkyLightAndReflectionProbes(in vec3 viewDir, in vec3 wPosition, in vec3 normal, in vec3 norm, in float Roughness, in vec3 diffuseColor, in vec3 specularColor, in float ndotv, in vec3 ao){
+vec3 renderSkyLightAndReflectionProbes(in float indoorSunLightExposure, in vec3 viewDir, in vec3 wPosition, in vec3 normal, in vec3 norm, in float Roughness, in vec3 diffuseColor, in vec3 specularColor, in float ndotv, in vec3 ao){
vec3 result = vec3(0);
vec4 difColor = vec4(diffuseColor, 1.0f);
vec4 specColor = vec4(specularColor, 1.0f);
@@ -62,6 +62,9 @@ vec3 renderSkyLightAndReflectionProbes(in vec3 viewDir, in vec3 wPosition, in ve
color2.rgb *= g_AmbientLightColor.rgb;
color3.rgb *= g_AmbientLightColor.rgb;
#endif
+ color1.rgb *= indoorSunLightExposure;
+ color2.rgb *= indoorSunLightExposure;
+ color3.rgb *= indoorSunLightExposure;
result.rgb += color1 * clamp(weight1,0.0,1.0) + color2 * clamp(weight2,0.0,1.0) + color3 * clamp(weight3,0.0,1.0);
#endif
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java
new file mode 100644
index 0000000000..8375db317a
--- /dev/null
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2009-2021 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.terrain;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.asset.TextureKey;
+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.LightProbe;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Vector3f;
+import com.jme3.shader.VarType;
+import com.jme3.terrain.geomipmap.TerrainLodControl;
+import com.jme3.terrain.geomipmap.TerrainQuad;
+import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;
+import com.jme3.terrain.heightmap.AbstractHeightMap;
+import com.jme3.terrain.heightmap.ImageBasedHeightMap;
+import com.jme3.texture.Image;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture.WrapMode;
+import com.jme3.texture.TextureArray;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This test uses 'AdvancedPBRTerrain.j3md' to create a terrain Material with
+ * more textures than 'PBRTerrain.j3md' can handle.
+ *
+ * Upon running the app, the user should see a mountainous, terrain-based
+ * landscape with some grassy areas, some snowy areas, and some tiled roads and
+ * gravel paths weaving between the valleys. Snow should be slightly
+ * shiny/reflective, and marble texture should be even shinier. If you would
+ * like to know what each texture is supposed to look like, you can find the
+ * textures used for this test case located in jme3-testdata. (Screenshots
+ * showing how this test-case should look will also be available soon so you can
+ * compare your results, and I will replace this comment with a link to their
+ * location as soon as they are posted.)
+ *
+ * Press 'p' to toggle tri-planar mode. Enabling tri-planar mode should prevent
+ * stretching of textures in steep areas of the terrain.
+ *
+ * Press 'n' to toggle between night and day. Pressing 'n' will cause the light
+ * to gradually fade darker/brighter until the min/max lighting levels are
+ * reached. At night the scene should be noticeably darker, and the marble and
+ * tiled-road texture should be noticeably glowing from the emissiveColors and
+ * the emissiveIntensity map that is packed into the alpha channel of the
+ * MetallicRoughness maps.
+ *
+ * The MetallicRoughness map stores:
+ *
+ * - AmbientOcclusion in the Red channel
+ * - Roughness in the Green channel
+ * - Metallic in the Blue channel
+ * - EmissiveIntensity in the Alpha channel
+ *
+ *
+ * The shaders are still subject to the GLSL max limit of 16 textures, however
+ * each TextureArray counts as a single texture, and each TextureArray can store
+ * multiple images. For more information on texture arrays see:
+ * https://www.khronos.org/opengl/wiki/Array_Texture
+ *
+ * Uses assets from CC0Textures.com, licensed under CC0 1.0 Universal. For more
+ * information on the textures this test case uses, view the license.txt file
+ * located in the jme3-testdata directory where these textures are located:
+ * jme3-testdata/src/main/resources/Textures/Terrain/PBR
+ *
+ *
+ * Notes: (as of 12 April 2021)
+ *
+ * -
+ * The results look better with anti-aliasing, especially from a distance. This
+ * may be due to the way that the terrain is generated from a heightmap, as
+ * these same textures do not have this issue in my other project.
+ *
+ * -
+ * The number of images per texture array may still be limited by
+ * GL_MAX_ARRAY_TEXTURE_LAYERS, however this value should be high enough that
+ * users will likely run into issues with extremely low FPS from too many
+ * texture-reads long before you surpass the limit of texture-layers per
+ * textureArray. If this ever becomes an issue, a secondary set of
+ * Albedo/Normal/MetallicRoughness texture arrays could be added to the shader
+ * to store any textures that surpass the limit of the primary textureArrays.
+ *
+ *
+ *
+ * @author yaRnMcDonuts
+ */
+public class PBRTerrainAdvancedTest extends SimpleApplication {
+
+ private TerrainQuad terrain;
+ private Material matTerrain;
+ private boolean triPlanar = false;
+
+ private final int terrainSize = 512;
+ private final int patchSize = 256;
+ private final float dirtScale = 24;
+ private final float darkRockScale = 24;
+ private final float snowScale = 64;
+ private final float tileRoadScale = 64;
+ private final float grassScale = 24;
+ private final float marbleScale = 64;
+ private final float gravelScale = 64;
+
+ private final ColorRGBA tilesEmissiveColor = new ColorRGBA(0.12f, 0.02f, 0.23f, 0.85f); //dim magenta emission
+ private final ColorRGBA marbleEmissiveColor = new ColorRGBA(0.0f, 0.0f, 1.0f, 1.0f); //fully saturated blue emission
+
+ private AmbientLight ambientLight;
+ private DirectionalLight directionalLight;
+ private boolean isNight = false;
+
+ private final float dayLightIntensity = 1.0f;
+ private final float nightLightIntensity = 0.03f;
+
+ private BitmapText keybindingsText;
+
+ private final float camMoveSpeed = 50f;
+
+ public static void main(String[] args) {
+ PBRTerrainAdvancedTest app = new PBRTerrainAdvancedTest();
+ app.start();
+ }
+
+ private final ActionListener actionListener = new ActionListener() {
+ @Override
+ public void onAction(String name, boolean pressed, float tpf) {
+ if (name.equals("triPlanar") && !pressed) {
+ triPlanar = !triPlanar;
+ if (triPlanar) {
+ matTerrain.setBoolean("useTriPlanarMapping", true);
+ // Tri-planar textures don't use the mesh's texture coordinates but real world coordinates,
+ // so we need to convert these texture coordinate scales into real world scales so it looks
+ // the same when we switch to/from tri-planar mode.
+ matTerrain.setFloat("AlbedoMap_0_scale", (dirtScale / terrainSize));
+ matTerrain.setFloat("AlbedoMap_1_scale", (darkRockScale / terrainSize));
+ matTerrain.setFloat("AlbedoMap_2_scale", (snowScale / terrainSize));
+ matTerrain.setFloat("AlbedoMap_3_scale", (tileRoadScale / terrainSize));
+ matTerrain.setFloat("AlbedoMap_4_scale", (grassScale / terrainSize));
+ matTerrain.setFloat("AlbedoMap_5_scale", (marbleScale / terrainSize));
+ matTerrain.setFloat("AlbedoMap_6_scale", (gravelScale / terrainSize));
+ } else {
+ matTerrain.setBoolean("useTriPlanarMapping", false);
+
+ matTerrain.setFloat("AlbedoMap_0_scale", dirtScale);
+ matTerrain.setFloat("AlbedoMap_1_scale", darkRockScale);
+ matTerrain.setFloat("AlbedoMap_2_scale", snowScale);
+ matTerrain.setFloat("AlbedoMap_3_scale", tileRoadScale);
+ matTerrain.setFloat("AlbedoMap_4_scale", grassScale);
+ matTerrain.setFloat("AlbedoMap_5_scale", marbleScale);
+ matTerrain.setFloat("AlbedoMap_6_scale", gravelScale);
+ }
+ }
+ if (name.equals("toggleNight") && !pressed) {
+ isNight = !isNight;
+ // Ambient and directional light are faded smoothly in update loop below.
+ }
+ }
+ };
+
+ @Override
+ public void simpleInitApp() {
+ setupKeys();
+ setUpTerrain();
+ setUpTerrainMaterial(); // <- This method contains the important info about using 'AdvancedPBRTerrain.j3md'
+ setUpLights();
+ setUpCamera();
+ }
+
+ private void setUpTerrainMaterial() {
+ // advanced PBR terrain matdef
+ matTerrain = new Material(assetManager, "Common/MatDefs/Terrain/AdvancedPBRTerrain.j3md");
+
+ matTerrain.setBoolean("useTriPlanarMapping", false);
+
+ // ALPHA map (for splat textures)
+ matTerrain.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alpha1.png"));
+ matTerrain.setTexture("AlphaMap_1", assetManager.loadTexture("Textures/Terrain/splat/alpha2.png"));
+ // this material also supports 'AlphaMap_2', so you can get up to 12 texture slots
+
+ // load textures for texture arrays
+ // These MUST all have the same dimensions and format in order to be put into a texture array.
+ //ALBEDO MAPS
+ Texture dirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png");
+ Texture darkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Color.png");
+ Texture snow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Color.png");
+ Texture tileRoad = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Color.png");
+ Texture grass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png");
+ Texture marble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Color.png");
+ Texture gravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Color.png");
+
+ // NORMAL MAPS
+ Texture normalMapDirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground036_1K_Normal.png");
+ Texture normalMapDarkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Normal.png");
+ Texture normalMapSnow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Normal.png");
+ Texture normalMapGravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Normal.png");
+ Texture normalMapGrass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Normal.png");
+ Texture normalMapMarble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Normal.png");
+ Texture normalMapRoad = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Normal.png");
+
+ //PACKED METALLIC/ROUGHNESS / AMBIENT OCCLUSION / EMISSIVE INTENSITY MAPS
+ Texture metallicRoughnessAoEiMapDirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground036_PackedMetallicRoughnessMap.png");
+ Texture metallicRoughnessAoEiMapDarkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_PackedMetallicRoughnessMap.png");
+ Texture metallicRoughnessAoEiMapSnow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_PackedMetallicRoughnessMap.png");
+ Texture metallicRoughnessAoEiMapGravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel_015_PackedMetallicRoughnessMap.png");
+ Texture metallicRoughnessAoEiMapGrass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_PackedMetallicRoughnessMap.png");
+ Texture metallicRoughnessAoEiMapMarble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_PackedMetallicRoughnessMap.png");
+ Texture metallicRoughnessAoEiMapRoad = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_PackedMetallicRoughnessMap.png");
+
+ // put all images into lists to create texture arrays.
+ //
+ // The index of each image in its list will be
+ // sent to the material to tell the shader to choose that texture from
+ // the textureArray when setting up a texture slot's mat params.
+ //
+ List albedoImages = new ArrayList<>();
+ List normalMapImages = new ArrayList<>();
+ List metallicRoughnessAoEiMapImages = new ArrayList<>();
+
+ albedoImages.add(dirt.getImage()); //0
+ albedoImages.add(darkRock.getImage()); //1
+ albedoImages.add(snow.getImage()); //2
+ albedoImages.add(tileRoad.getImage()); //3
+ albedoImages.add(grass.getImage()); //4
+ albedoImages.add(marble.getImage()); //5
+ albedoImages.add(gravel.getImage()); //6
+
+ normalMapImages.add(normalMapDirt.getImage()); //0
+ normalMapImages.add(normalMapDarkRock.getImage()); //1
+ normalMapImages.add(normalMapSnow.getImage()); //2
+ normalMapImages.add(normalMapRoad.getImage()); //3
+ normalMapImages.add(normalMapGrass.getImage()); //4
+ normalMapImages.add(normalMapMarble.getImage()); //5
+ normalMapImages.add(normalMapGravel.getImage()); //6
+
+ metallicRoughnessAoEiMapImages.add(metallicRoughnessAoEiMapDirt.getImage()); //0
+ metallicRoughnessAoEiMapImages.add(metallicRoughnessAoEiMapDarkRock.getImage()); //1
+ metallicRoughnessAoEiMapImages.add(metallicRoughnessAoEiMapSnow.getImage()); //2
+ metallicRoughnessAoEiMapImages.add(metallicRoughnessAoEiMapRoad.getImage()); //3
+ metallicRoughnessAoEiMapImages.add(metallicRoughnessAoEiMapGrass.getImage()); //4
+ metallicRoughnessAoEiMapImages.add(metallicRoughnessAoEiMapMarble.getImage()); //5
+ metallicRoughnessAoEiMapImages.add(metallicRoughnessAoEiMapGravel.getImage()); //6
+
+ //initiate texture arrays
+ TextureArray albedoTextureArray = new TextureArray(albedoImages);
+ TextureArray normalParallaxTextureArray = new TextureArray(normalMapImages); // parallax is not used currently
+ TextureArray metallicRoughnessAoEiTextureArray = new TextureArray(metallicRoughnessAoEiMapImages);
+
+ //apply wrapMode to the whole texture array, rather than each individual texture in the array
+ albedoTextureArray.setWrap(WrapMode.Repeat);
+ normalParallaxTextureArray.setWrap(WrapMode.Repeat);
+ metallicRoughnessAoEiTextureArray.setWrap(WrapMode.Repeat);
+
+ //assign texture array to materials
+ matTerrain.setParam("AlbedoTextureArray", VarType.TextureArray, albedoTextureArray);
+ matTerrain.setParam("NormalParallaxTextureArray", VarType.TextureArray, normalParallaxTextureArray);
+ matTerrain.setParam("MetallicRoughnessAoEiTextureArray", VarType.TextureArray, metallicRoughnessAoEiTextureArray);
+
+ //set up texture slots:
+ matTerrain.setInt("AlbedoMap_0", 0); // dirt is index 0 in the albedo image list
+ matTerrain.setFloat("AlbedoMap_0_scale", dirtScale);
+ matTerrain.setFloat("Roughness_0", 1);
+ matTerrain.setFloat("Metallic_0", 0.02f);
+
+ matTerrain.setInt("AlbedoMap_1", 1); // darkRock is index 1 in the albedo image list
+ matTerrain.setFloat("AlbedoMap_1_scale", darkRockScale);
+ matTerrain.setFloat("Roughness_1", 1);
+ matTerrain.setFloat("Metallic_1", 0.04f);
+
+ matTerrain.setInt("AlbedoMap_2", 2);
+ matTerrain.setFloat("AlbedoMap_2_scale", snowScale);
+ matTerrain.setFloat("Roughness_2", 0.72f);
+ matTerrain.setFloat("Metallic_2", 0.12f);
+
+ matTerrain.setInt("AlbedoMap_3", 3);
+ matTerrain.setFloat("AlbedoMap_3_scale", tileRoadScale);
+ matTerrain.setFloat("Roughness_3", 1);
+ matTerrain.setFloat("Metallic_3", 0.04f);
+
+ matTerrain.setInt("AlbedoMap_4", 4);
+ matTerrain.setFloat("AlbedoMap_4_scale", grassScale);
+ matTerrain.setFloat("Roughness_4", 1);
+ matTerrain.setFloat("Metallic_4", 0);
+
+ matTerrain.setInt("AlbedoMap_5", 5);
+ matTerrain.setFloat("AlbedoMap_5_scale", marbleScale);
+ matTerrain.setFloat("Roughness_5", 1);
+ matTerrain.setFloat("Metallic_5", 0.2f);
+
+ matTerrain.setInt("AlbedoMap_6", 6);
+ matTerrain.setFloat("AlbedoMap_6_scale", gravelScale);
+ matTerrain.setFloat("Roughness_6", 1);
+ matTerrain.setFloat("Metallic_6", 0.01f);
+
+ // NORMAL MAPS
+ // int being passed to shader corresponds to the index of the texture's
+ // image in the List of images used to create its texture array
+ matTerrain.setInt("NormalMap_0", 0);
+ matTerrain.setInt("NormalMap_1", 1);
+ matTerrain.setInt("NormalMap_2", 2);
+ matTerrain.setInt("NormalMap_3", 3);
+ matTerrain.setInt("NormalMap_4", 4);
+ matTerrain.setInt("NormalMap_5", 5);
+ matTerrain.setInt("NormalMap_6", 6);
+
+ //METALLIC/ROUGHNESS/AO/EI MAPS
+ matTerrain.setInt("MetallicRoughnessMap_0", 0);
+ matTerrain.setInt("MetallicRoughnessMap_1", 1);
+ matTerrain.setInt("MetallicRoughnessMap_2", 2);
+ matTerrain.setInt("MetallicRoughnessMap_3", 3);
+ matTerrain.setInt("MetallicRoughnessMap_4", 4);
+ matTerrain.setInt("MetallicRoughnessMap_5", 5);
+ matTerrain.setInt("MetallicRoughnessMap_6", 6);
+
+ //EMISSIVE
+ matTerrain.setColor("EmissiveColor_5", marbleEmissiveColor);
+ matTerrain.setColor("EmissiveColor_3", tilesEmissiveColor);
+ //these two texture slots (marble & tiledRoad, indexed in each texture array at 5 and 3 respectively) both
+ // have packed MRAoEi maps with an emissiveTexture packed into the alpha channel
+
+// matTerrain.setColor("EmissiveColor_1", new ColorRGBA(0.08f, 0.01f, 0.1f, 0.4f));
+//this texture slot does not have a unique emissiveIntensityMap packed into its MRAoEi map,
+ // so setting an emissiveColor will apply equal intensity to every pixel
+
+ terrain.setMaterial(matTerrain);
+ }
+
+ private void setupKeys() {
+ flyCam.setMoveSpeed(50);
+ inputManager.addMapping("triPlanar", new KeyTrigger(KeyInput.KEY_P));
+ inputManager.addMapping("toggleNight", new KeyTrigger(KeyInput.KEY_N));
+
+ inputManager.addListener(actionListener, "triPlanar");
+ inputManager.addListener(actionListener, "toggleNight");
+
+ keybindingsText = new BitmapText(assetManager.loadFont("Interface/Fonts/Default.fnt"));
+ keybindingsText.setText("Press 'N' to toggle day/night fade (takes a moment) \nPress 'P' to toggle tri-planar mode");
+
+ getGuiNode().attachChild(keybindingsText);
+ keybindingsText.move(new Vector3f(200, 120, 0));
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ super.simpleUpdate(tpf);
+
+ //smoothly transition from day to night
+ float currentLightIntensity = ambientLight.getColor().getRed();
+ float incrementPerFrame = tpf * 0.3f;
+
+ if (isNight) {
+ if (ambientLight.getColor().getRed() > nightLightIntensity) {
+ currentLightIntensity -= incrementPerFrame;
+ if (currentLightIntensity < nightLightIntensity) {
+ currentLightIntensity = nightLightIntensity;
+ }
+
+ ambientLight.getColor().set(currentLightIntensity, currentLightIntensity, currentLightIntensity, 1.0f);
+ directionalLight.getColor().set(currentLightIntensity, currentLightIntensity, currentLightIntensity, 1.0f);
+ }
+ } else {
+ if (ambientLight.getColor().getRed() < dayLightIntensity) {
+ currentLightIntensity += incrementPerFrame;
+ if (currentLightIntensity > dayLightIntensity) {
+ currentLightIntensity = dayLightIntensity;
+ }
+
+ ambientLight.getColor().set(currentLightIntensity, currentLightIntensity, currentLightIntensity, 1.0f);
+ directionalLight.getColor().set(currentLightIntensity, currentLightIntensity, currentLightIntensity, 1.0f);
+ }
+ }
+ }
+
+ private void setUpTerrain() {
+ // HEIGHTMAP image (for the terrain heightmap)
+ TextureKey hmKey = new TextureKey("Textures/Terrain/splat/mountains512.png", false);
+ Texture heightMapImage = assetManager.loadTexture(hmKey);
+
+ // CREATE HEIGHTMAP
+ AbstractHeightMap heightmap = null;
+ try {
+ heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.3f);
+ heightmap.load();
+ heightmap.smooth(0.9f, 1);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ terrain = new TerrainQuad("terrain", patchSize + 1, terrainSize + 1, heightmap.getHeightMap());
+//, new LodPerspectiveCalculatorFactory(getCamera(), 4)); // add this in to see it use entropy for LOD calculations
+ TerrainLodControl control = new TerrainLodControl(terrain, getCamera());
+ control.setLodCalculator(new DistanceLodCalculator(patchSize + 1, 2.7f)); // patch size, and a multiplier
+ terrain.addControl(control);
+ terrain.setMaterial(matTerrain);
+ terrain.setLocalTranslation(0, -100, 0);
+ terrain.setLocalScale(1f, 1f, 1f);
+ rootNode.attachChild(terrain);
+ }
+
+ private void setUpLights() {
+ LightProbe probe = (LightProbe) assetManager.loadAsset("Scenes/LightProbes/quarry_Probe.j3o");
+
+ probe.setAreaType(LightProbe.AreaType.Spherical);
+ probe.getArea().setRadius(2000);
+ probe.getArea().setCenter(new Vector3f(0, 0, 0));
+ rootNode.addLight(probe);
+
+ directionalLight = new DirectionalLight();
+ directionalLight.setDirection((new Vector3f(-0.3f, -0.5f, -0.3f)).normalize());
+ directionalLight.setColor(ColorRGBA.White);
+ rootNode.addLight(directionalLight);
+
+ ambientLight = new AmbientLight();
+ directionalLight.setColor(ColorRGBA.White);
+ rootNode.addLight(ambientLight);
+ }
+
+ private void setUpCamera() {
+ cam.setLocation(new Vector3f(0, 10, -10));
+ cam.lookAtDirection(new Vector3f(0, -1.5f, -1).normalizeLocal(), Vector3f.UNIT_Y);
+
+ getFlyByCamera().setMoveSpeed(camMoveSpeed);
+ }
+}
diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/AdvancedPBRTerrain.j3md b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/AdvancedPBRTerrain.j3md
index fe0680482b..7bd7350498 100644
--- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/AdvancedPBRTerrain.j3md
+++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/AdvancedPBRTerrain.j3md
@@ -250,6 +250,12 @@ MaterialDef Advanced PBR Terrain {
// Alpha threshold for fragment discarding
Float AlphaDiscardThreshold (AlphaTestFallOff)
+ // Context GBuffer Data
+ Texture2D Context_InGBuff0
+ Texture2D Context_InGBuff1
+ Texture2D Context_InGBuff2
+ Texture2D Context_InGBuff3
+ Texture2D Context_InGBuff4
}
Technique {
@@ -339,6 +345,82 @@ MaterialDef Advanced PBR Terrain {
}
}
+ Technique GBufferPass{
+ Pipeline Deferred
+ VertexShader GLSL300 GLSL150 : Common/MatDefs/Terrain/PBRTerrain.vert
+ FragmentShader GLSL300 GLSL150 : Common/MatDefs/Terrain/GBufferPack/AdvancedPBRTerrainGBufferPack.frag
+ WorldParameters {
+ WorldViewProjectionMatrix
+ CameraPosition
+ WorldMatrix
+ WorldNormalMatrix
+ ViewProjectionMatrix
+ ViewMatrix
+ Time
+ }
+ Defines {
+ BOUND_DRAW_BUFFER: BoundDrawBuffer
+
+ AFFLICTIONTEXTURE : AfflictionAlphaMap
+ AFFLICTIONALBEDOMAP: SplatAlbedoMap
+ AFFLICTIONNORMALMAP : SplatNormalMap
+ AFFLICTIONROUGHNESSMETALLICMAP : SplatRoughnessMetallicMap
+ AFFLICTIONEMISSIVEMAP : SplatEmissiveMap
+ USE_SPLAT_NOISE : SplatNoiseVar
+
+ TRI_PLANAR_MAPPING : useTriPlanarMapping
+
+ DISCARD_ALPHA : AlphaDiscardThreshold
+
+ ALPHAMAP : AlphaMap
+ ALPHAMAP_1 : AlphaMap_1
+ ALPHAMAP_2 : AlphaMap_2
+
+ USE_FOG : UseFog
+ FOG_LINEAR : LinearFog
+ FOG_EXP : ExpFog
+ FOG_EXPSQ : ExpSqFog
+
+ ALBEDOMAP_0 : AlbedoMap_0
+ ALBEDOMAP_1 : AlbedoMap_1
+ ALBEDOMAP_2 : AlbedoMap_2
+ ALBEDOMAP_3 : AlbedoMap_3
+ ALBEDOMAP_4 : AlbedoMap_4
+ ALBEDOMAP_5 : AlbedoMap_5
+ ALBEDOMAP_6 : AlbedoMap_6
+ ALBEDOMAP_7 : AlbedoMap_7
+ ALBEDOMAP_8 : AlbedoMap_8
+ ALBEDOMAP_9 : AlbedoMap_9
+ ALBEDOMAP_10 : AlbedoMap_10
+ ALBEDOMAP_11 : AlbedoMap_11
+
+ NORMALMAP_0 : NormalMap_0
+ 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
+
+ METALLICROUGHNESSMAP_0 : MetallicRoughnessMap_0
+ METALLICROUGHNESSMAP_1 : MetallicRoughnessMap_1
+ METALLICROUGHNESSMAP_2 : MetallicRoughnessMap_2
+ METALLICROUGHNESSMAP_3 : MetallicRoughnessMap_3
+ METALLICROUGHNESSMAP_4 : MetallicRoughnessMap_4
+ METALLICROUGHNESSMAP_5 : MetallicRoughnessMap_5
+ METALLICROUGHNESSMAP_6 : MetallicRoughnessMap_6
+ METALLICROUGHNESSMAP_7 : MetallicRoughnessMap_7
+ METALLICROUGHNESSMAP_8 : MetallicRoughnessMap_8
+ METALLICROUGHNESSMAP_9 : MetallicRoughnessMap_9
+ METALLICROUGHNESSMAP_10 : MetallicRoughnessMap_10
+ METALLICROUGHNESSMAP_11 : MetallicRoughnessMap_11
+ }
+ }
Technique PreShadow {
diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/AdvancedPBRTerrainGBufferPack.frag b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/AdvancedPBRTerrainGBufferPack.frag
new file mode 100644
index 0000000000..90feef10b5
--- /dev/null
+++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/AdvancedPBRTerrainGBufferPack.frag
@@ -0,0 +1,516 @@
+#extension GL_EXT_texture_array : enable
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+#import "Common/ShaderLib/PBR.glsllib"
+#import "Common/ShaderLib/Lighting.glsllib"
+#import "Common/MatDefs/Terrain/AfflictionLib.glsllib"
+#import "Common/ShaderLib/Deferred.glsllib"
+
+// shading model
+#import "Common/ShaderLib/ShadingModel.glsllib"
+// octahedral
+#import "Common/ShaderLib/Octahedral.glsllib"
+
+varying vec3 wPosition;
+varying vec3 vNormal;
+varying vec2 texCoord;
+uniform vec3 g_CameraPosition;
+varying vec3 vPosition;
+varying vec3 vnPosition;
+varying vec3 vViewDir;
+varying vec4 vLightDir;
+varying vec4 vnLightDir;
+varying vec3 lightVec;
+varying vec3 inNormal;
+varying vec3 wNormal;
+
+#ifdef TRI_PLANAR_MAPPING
+ varying vec4 wVertex;
+#endif
+
+//texture arrays:
+uniform sampler2DArray m_AlbedoTextureArray;
+uniform sampler2DArray m_NormalParallaxTextureArray;
+uniform sampler2DArray m_MetallicRoughnessAoEiTextureArray;
+
+//texture-slot params for 12 unique texture slots (0-11) where the integer value points to the desired texture's index in the corresponding texture array:
+#for i=0..12 ( $0 )
+ uniform int m_AfflictionMode_$i;
+ uniform float m_Roughness_$i;
+ uniform float m_Metallic_$i;
+ uniform float m_AlbedoMap_$i_scale;
+ uniform vec4 m_EmissiveColor_$i;
+
+ #ifdef ALBEDOMAP_$i
+ uniform int m_AlbedoMap_$i;
+ #endif
+ #ifdef NORMALMAP_$i
+ uniform int m_NormalMap_$i;
+ #endif
+ #ifdef METALLICROUGHNESSMAP_$i
+ uniform int m_MetallicRoughnessMap_$i;
+ #endif
+#endfor
+
+//3 alpha maps :
+#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 DISCARD_ALPHA
+ uniform float m_AlphaDiscardThreshold;
+#endif
+
+//fog vars for basic fog :
+#ifdef USE_FOG
+#import "Common/ShaderLib/MaterialFog.glsllib"
+ uniform vec4 m_FogColor;
+ float fogDistance;
+
+ uniform vec2 m_LinearFog;
+#endif
+#ifdef FOG_EXP
+ uniform float m_ExpFog;
+#endif
+#ifdef FOG_EXPSQ
+ uniform float m_ExpSqFog;
+#endif
+
+//sun intensity is a secondary AO value that can be painted per-vertex in the red channel of the
+// vertex colors, or it can be set as a static value for an entire material with the StaticSunIntensity float param
+#if defined(USE_VERTEX_COLORS_AS_SUN_INTENSITY)
+ varying vec4 vertColors;
+#endif
+
+#ifdef STATIC_SUN_INTENSITY
+ uniform float m_StaticSunIntensity;
+#endif
+//sun intensity AO value is only applied to the directional light, not to point lights, so it is important to track if the
+//sun is more/less bright than the brightest point light for each fragment to determine how the light probe's ambient light should be scaled later on in light calculation code
+float brightestPointLight = 0.0;
+
+//optional affliction paramaters that use the AfflictionAlphaMap's green channel for splatting m_SplatAlbedoMap and the red channel for splatting desaturation :
+#ifdef AFFLICTIONTEXTURE
+ uniform sampler2D m_AfflictionAlphaMap;
+#endif
+#ifdef USE_SPLAT_NOISE
+ uniform float m_SplatNoiseVar;
+#endif
+//only defined for non-terrain geoemtries and terrains that are not positioned nor sized in correlation to the 2d array of AfflictionAlphaMaps used for splatting accross large tile based scenes in a grid
+#ifdef TILELOCATION
+ uniform float m_TileWidth;
+ uniform vec3 m_TileLocation;
+#endif
+#ifdef AFFLICTIONALBEDOMAP
+ uniform sampler2D m_SplatAlbedoMap;
+#endif
+#ifdef AFFLICTIONNORMALMAP
+ uniform sampler2D m_SplatNormalMap;
+#endif
+#ifdef AFFLICTIONROUGHNESSMETALLICMAP
+ uniform sampler2D m_SplatRoughnessMetallicMap;
+#endif
+#ifdef AFFLICTIONEMISSIVEMAP
+ uniform sampler2D m_SplatEmissiveMap;
+#endif
+
+uniform int m_AfflictionSplatScale;
+uniform float m_AfflictionRoughnessValue;
+uniform float m_AfflictionMetallicValue;
+uniform float m_AfflictionEmissiveValue;
+uniform vec4 m_AfflictionEmissiveColor;
+
+vec4 afflictionVector;
+float noiseHash;
+float livelinessValue;
+float afflictionValue;
+int afflictionMode = 1;
+
+//general temp vars :
+vec4 tempAlbedo, tempNormal, tempEmissiveColor;
+float tempParallax, tempMetallic, tempRoughness, tempAo, tempEmissiveIntensity;
+
+vec3 viewDir;
+vec2 coord;
+vec4 albedo = vec4(1.0);
+vec3 normal = vec3(0.5,0.5,1);
+vec3 norm;
+float Metallic;
+float Roughness;
+float packedAoValue = 1.0;
+vec4 emissive;
+float emissiveIntensity = 1.0;
+float indoorSunLightExposure = 1.0;
+
+vec4 packedMetallicRoughnessAoEiVec;
+vec4 packedNormalParallaxVec;
+
+
+void main(){
+
+ #ifdef USE_FOG
+ fogDistance = distance(g_CameraPosition, wPosition.xyz);
+ #endif
+
+ float indoorSunLightExposure = 1.0;
+
+ viewDir = normalize(g_CameraPosition - wPosition);
+
+ norm = normalize(wNormal);
+ normal = norm;
+
+
+ afflictionVector = vec4(1.0, 0.0, 1.0, 0.0); //r channel is sturation, g channel is affliction splat texture intensity, b and a unused (might use b channel for wetness eventually)
+
+ #ifdef AFFLICTIONTEXTURE
+
+ #ifdef TILELOCATION
+ //subterrains that are not centred in tile or equal to tile width in total size need to have m_TileWidth pre-set. (tileWidth is the x,z dimesnions that the AfflictionAlphaMap represents)..
+ vec2 tileCoords;
+ float xPos, zPos;
+
+ vec3 locInTile = (wPosition - m_TileLocation);
+
+ locInTile += vec3(m_TileWidth/2, 0, m_TileWidth/2);
+
+ xPos = (locInTile.x / m_TileWidth);
+ zPos = 1 - (locInTile.z / m_TileWidth);
+
+ tileCoords = vec2(xPos, zPos);
+
+ afflictionVector = texture2D(m_AfflictionAlphaMap, tileCoords).rgba;
+
+
+
+ #else
+ // ..othrewise when terrain size matches tileWidth, the terrain's texCoords can be used for simple texel fetching of the AfflictionAlphaMap
+ afflictionVector = texture2D(m_AfflictionAlphaMap, texCoord.xy).rgba;
+ #endif
+ #endif
+
+ livelinessValue = afflictionVector.r;
+ afflictionValue = afflictionVector.g;
+
+
+ #ifdef ALBEDOMAP_0
+ #ifdef ALPHAMAP
+
+ vec4 alphaBlend;
+ vec4 alphaBlend_0, alphaBlend_1, alphaBlend_2;
+ int texChannelForAlphaBlending;
+
+ alphaBlend_0 = texture2D( m_AlphaMap, texCoord.xy );
+
+ #ifdef ALPHAMAP_1
+ alphaBlend_1 = texture2D( m_AlphaMap_1, texCoord.xy );
+ #endif
+ #ifdef ALPHAMAP_2
+ alphaBlend_2 = texture2D( m_AlphaMap_2, texCoord.xy );
+ #endif
+
+ vec2 texSlotCoords;
+
+ float finalAlphaBlendForLayer = 1.0;
+
+ vec3 blending = abs( norm );
+ 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);
+
+ #for i=0..12 (#ifdef ALBEDOMAP_$i $0 #endif)
+
+ //assign texture slot's blending from index's correct alpha map
+ if($i <= 3){
+ alphaBlend = alphaBlend_0;
+ }else if($i <= 7){
+ alphaBlend = alphaBlend_1;
+ }else if($i <= 11){
+ alphaBlend = alphaBlend_2;
+ }
+
+ texChannelForAlphaBlending = int(mod($i, 4.0)); //pick the correct channel (r g b or a) based on the layer's index
+ switch(texChannelForAlphaBlending) {
+ case 0:
+ finalAlphaBlendForLayer = alphaBlend.r;
+ break;
+ case 1:
+ finalAlphaBlendForLayer = alphaBlend.g;
+ break;
+ case 2:
+ finalAlphaBlendForLayer = alphaBlend.b;
+ break;
+ case 3:
+ finalAlphaBlendForLayer = alphaBlend.a;
+ break;
+ }
+
+ afflictionMode = m_AfflictionMode_$i;
+ tempEmissiveColor = m_EmissiveColor_$i;
+
+ #ifdef TRI_PLANAR_MAPPING
+ //tri planar
+ tempAlbedo = getTriPlanarBlendFromTexArray(wVertex, blending, m_AlbedoMap_$i, m_AlbedoMap_$i_scale, m_AlbedoTextureArray);
+
+ #ifdef NORMALMAP_$i
+ packedNormalParallaxVec.rgba = getTriPlanarBlendFromTexArray(wVertex, blending, m_NormalMap_$i, m_AlbedoMap_$i_scale, m_NormalParallaxTextureArray).rgba;
+ tempNormal.xyz = calculateTangentsAndApplyToNormals(packedNormalParallaxVec.xyz, wNormal);// this gets rid of the need for pre-generating tangents for TerrainPatches, since doing so doesn't seem to work (tbnMat is always blank for terrains even with tangents pre-generated, not sure why...)
+ tempParallax = packedNormalParallaxVec.w;
+
+ #ifdef PARALLAXHEIGHT_0
+ //wip
+ #endif
+ #else
+ tempNormal.rgb = wNormal.rgb;
+ #endif
+ #ifdef METALLICROUGHNESSMAP_$i
+ packedMetallicRoughnessAoEiVec = getTriPlanarBlendFromTexArray(wVertex, blending, m_MetallicRoughnessMap_$i, m_AlbedoMap_$i_scale, m_MetallicRoughnessAoEiTextureArray).rgba;
+ tempRoughness = packedMetallicRoughnessAoEiVec.g * m_Roughness_$i;
+ tempMetallic = packedMetallicRoughnessAoEiVec.b * m_Metallic_$i;
+ tempAo = packedMetallicRoughnessAoEiVec.r;
+ tempEmissiveIntensity = packedMetallicRoughnessAoEiVec.a;
+ #endif
+ #else
+
+ // non triplanar
+ texSlotCoords = texCoord * m_AlbedoMap_$i_scale;
+
+ tempAlbedo = texture2DArray(m_AlbedoTextureArray, vec3(texSlotCoords, m_AlbedoMap_$i));
+
+ #ifdef NORMALMAP_$i
+ packedNormalParallaxVec = texture2DArray(m_NormalParallaxTextureArray, vec3(texSlotCoords, m_NormalMap_$i));
+ tempNormal.xyz = calculateTangentsAndApplyToNormals(packedNormalParallaxVec.xyz, wNormal);
+ tempParallax = packedNormalParallaxVec.w;
+
+ #ifdef PARALLAXHEIGHT_0
+ //eventually add parallax code here if a PARALLAXHEIGHT_$i float is defined. but this shader is at the define limit currently,
+ // so to do that will require removing defines around scale to use that for enabling parallax per layer instead, since there's no reason for define around basic float scale anyways
+ #endif
+ #else
+ tempNormal.rgb = wNormal.rgb;
+ #endif
+
+ #ifdef METALLICROUGHNESSMAP_$i
+ packedMetallicRoughnessAoEiVec = texture2DArray(m_MetallicRoughnessAoEiTextureArray, vec3(texSlotCoords, m_MetallicRoughnessMap_$i));
+ tempRoughness = packedMetallicRoughnessAoEiVec.g * m_Roughness_$i;
+ tempMetallic = packedMetallicRoughnessAoEiVec.b * m_Metallic_$i;
+ tempAo = packedMetallicRoughnessAoEiVec.r;
+ tempEmissiveIntensity = packedMetallicRoughnessAoEiVec.a;
+ #endif
+ #endif
+
+
+ //blend to float values if no texture value for mrao map exists
+ #if !defined(METALLICROUGHNESSMAP_$i)
+ tempRoughness = m_Roughness_$i;
+ tempMetallic = m_Metallic_$i;
+ tempAo = 1.0;
+ #endif
+
+ //note: most of these functions can be found in AfflictionLib.glslib
+ tempAlbedo.rgb = alterLiveliness(tempAlbedo.rgb, livelinessValue, afflictionMode); //changes saturation of albedo for this layer; does nothing if not using AfflictionAlphaMap for affliction splatting
+
+ tempEmissiveColor *= tempEmissiveIntensity;
+
+ //mix values from this index layer to final output values based on finalAlphaBlendForLayer
+ albedo.rgb = mix(albedo.rgb, tempAlbedo.rgb , finalAlphaBlendForLayer);
+ normal.rgb = mix(normal.rgb, tempNormal.rgb, finalAlphaBlendForLayer);
+ Metallic = mix(Metallic, tempMetallic, finalAlphaBlendForLayer);
+ Roughness = mix(Roughness, tempRoughness, finalAlphaBlendForLayer);
+ packedAoValue = mix(packedAoValue, tempAo, finalAlphaBlendForLayer);
+ emissiveIntensity = mix(emissiveIntensity, tempEmissiveIntensity, finalAlphaBlendForLayer);
+ emissive = mix(emissive, tempEmissiveColor, finalAlphaBlendForLayer);
+
+ #endfor
+ #else
+ albedo = texture2D(m_AlbedoMap_0, texCoord);
+ #endif
+ #endif
+
+ float alpha = albedo.a;
+ #ifdef DISCARD_ALPHA
+ if(alpha < m_AlphaDiscardThreshold){
+ discard;
+ }
+ #endif
+
+ //APPLY AFFLICTIONN TO THE PIXEL
+ #ifdef AFFLICTIONTEXTURE
+ vec4 afflictionAlbedo;
+
+
+ float newAfflictionScale = m_AfflictionSplatScale;
+ vec2 newScaledCoords;
+
+
+ #ifdef AFFLICTIONALBEDOMAP
+ #ifdef TRI_PLANAR_MAPPING
+ newAfflictionScale = newAfflictionScale / 256;
+ afflictionAlbedo = getTriPlanarBlend(wVertex, blending, m_SplatAlbedoMap , newAfflictionScale);
+ #else
+ newScaledCoords = mod(wPosition.xz / m_AfflictionSplatScale, 0.985);
+ afflictionAlbedo = texture2D(m_SplatAlbedoMap , newScaledCoords);
+ #endif
+
+ #else
+ afflictionAlbedo = vec4(1.0, 1.0, 1.0, 1.0);
+ #endif
+
+ vec3 afflictionNormal;
+ #ifdef AFFLICTIONNORMALMAP
+ #ifdef TRI_PLANAR_MAPPING
+
+ afflictionNormal = getTriPlanarBlend(wVertex, blending, m_SplatNormalMap , newAfflictionScale).rgb;
+
+ #else
+ afflictionNormal = texture2D(m_SplatNormalMap , newScaledCoords).rgb;
+ #endif
+
+ #else
+ afflictionNormal = norm;
+
+ #endif
+ float afflictionMetallic = m_AfflictionMetallicValue;
+ float afflictionRoughness = m_AfflictionRoughnessValue;
+ float afflictionAo = 1.0;
+
+
+ vec4 afflictionEmissive = m_AfflictionEmissiveColor;
+ float afflictionEmissiveIntensity = m_AfflictionEmissiveValue;
+
+ #ifdef AFFLICTIONROUGHNESSMETALLICMAP
+ vec4 metallicRoughnessAoEiVec;
+ #ifdef TRI_PLANAR_MAPPING
+ metallicRoughnessAoEiVec = texture2D(m_SplatRoughnessMetallicMap, newScaledCoords);
+ #else
+ metallicRoughnessAoEiVec = getTriPlanarBlend(wVertex, blending, m_SplatRoughnessMetallicMap, newAfflictionScale);
+ #endif
+
+ afflictionRoughness *= metallicRoughnessAoEiVec.g;
+ afflictionMetallic *= metallicRoughnessAoEiVec.b;
+ afflictionAo = metallicRoughnessAoEiVec.r;
+ afflictionEmissiveIntensity *= metallicRoughnessAoEiVec.a; //important not to leave this channel all black by accident when creating the mraoei map if using affliction emissiveness
+
+ #endif
+
+ #ifdef AFFLICTIONEMISSIVEMAP
+ vec4 emissiveMapColor;
+ #ifdef TRI_PLANAR_MAPPING
+ emissiveMapColor = texture2D(m_SplatEmissiveMap, newScaledCoords);
+ #else
+ emissiveMapColor = getTriPlanarBlend(wVertex, blending, m_SplatEmissiveMap, newAfflictionScale);
+ #endif
+ afflictionEmissive *= emissiveMapColor;
+ #endif
+
+ float adjustedAfflictionValue = afflictionValue;
+ #ifdef USE_SPLAT_NOISE
+ noiseHash = getStaticNoiseVar0(wPosition, afflictionValue * m_SplatNoiseVar); //VERY IMPORTANT to replace this with a noiseMap texture, as calculating noise per pixel in-shader like this does lower framerate a lot
+
+ adjustedAfflictionValue = getAdjustedAfflictionVar(afflictionValue);
+ if(afflictionValue >= 0.99){
+ adjustedAfflictionValue = afflictionValue;
+ }
+ #else
+ noiseHash = 1.0;
+ #endif
+
+ Roughness = alterAfflictionRoughness(adjustedAfflictionValue, Roughness, afflictionRoughness, noiseHash);
+ Metallic = alterAfflictionMetallic(adjustedAfflictionValue, Metallic, afflictionMetallic, noiseHash);
+ albedo = alterAfflictionColor(adjustedAfflictionValue, albedo, afflictionAlbedo, noiseHash );
+ normal = alterAfflictionNormalsForTerrain(adjustedAfflictionValue, normal, afflictionNormal, noiseHash , wNormal);
+ emissive = alterAfflictionGlow(adjustedAfflictionValue, emissive, afflictionEmissive, noiseHash);
+ emissiveIntensity = alterAfflictionEmissiveIntensity(adjustedAfflictionValue, emissiveIntensity, afflictionEmissiveIntensity, noiseHash);
+ emissiveIntensity *= afflictionEmissive.a;
+ //affliction ao value blended below after specular calculation
+
+ #endif
+
+ // spec gloss pipeline code would go here if supported, but likely will not be for terrain shaders as defines are limited and heavily used
+
+ float specular = 0.5;
+ float nonMetalSpec = 0.08 * specular;
+ vec4 specularColor = (nonMetalSpec - nonMetalSpec * Metallic) + albedo * Metallic;
+ vec4 diffuseColor = albedo - albedo * Metallic;
+ vec3 fZero = vec3(specular);
+
+ //gl_FragColor.rgb = vec3(0.0);
+
+//simple ao calculation, no support for lightmaps like stock pbr shader.. (probably could add lightmap support with another texture array, but
+// that would add another texture read per slot and require removing 12 other defines to make room...)
+ vec3 ao = vec3(packedAoValue);
+
+ #ifdef AFFLICTIONTEXTURE
+ ao = alterAfflictionAo(afflictionValue, ao, vec3(afflictionAo), noiseHash); // alter the AO map for affliction values
+ #endif
+ ao.rgb = ao.rrr;
+ specularColor.rgb *= ao;
+
+
+
+ #ifdef STATIC_SUN_INTENSITY
+ indoorSunLightExposure = m_StaticSunIntensity; //single float value to indicate percentage of
+ //sunlight hitting the model (only works for small models or models with 100% consistent sunlighting accross every pixel)
+ #endif
+ #ifdef USE_VERTEX_COLORS_AS_SUN_INTENSITY
+ indoorSunLightExposure = vertColors.r * indoorSunLightExposure; //use R channel of vertexColors for..
+ #endif
+ // similar purpose as above...
+ //but uses r channel vert colors like an AO map specifically
+ //for sunlight (solution for scaling lighting for indoor
+ // and shadey/dimly lit models, especially big ones with)
+ brightestPointLight = 0.0;
+
+ // pack
+ vec2 n1 = octEncode(normal);
+ vec2 n2 = octEncode(norm);
+ Context_OutGBuff3.xy = n1;
+ Context_OutGBuff3.zw = n2;
+ Context_OutGBuff0.rgb = floor(diffuseColor.rgb * 100.0f) + ao * 0.1f;
+ Context_OutGBuff1.rgb = floor(specularColor.rgb * 100.0f) + fZero * 0.1f;
+ Context_OutGBuff1.a = Roughness;
+ Context_OutGBuff0.a = alpha;
+
+
+
+
+ float minVertLighting;
+ #ifdef BRIGHTEN_INDOOR_SHADOWS
+ minVertLighting = 0.0833; //brighten shadows so that caves which are naturally covered from the DL shadows are not way too dark compared to when shadows are off (mostly only necessary for naturally dark scenes, or dark areas when using the sun intensity code above)
+ #else
+ minVertLighting = 0.0533;
+
+ #endif
+
+ indoorSunLightExposure = max(indoorSunLightExposure, brightestPointLight);
+ indoorSunLightExposure = max(indoorSunLightExposure, minVertLighting); //scale the indoorSunLightExposure back up to account for the brightest point light nearby before scaling light probes by this value below
+
+ // shading model id
+ Context_OutGBuff2.a = STANDARD_LIGHTING + indoorSunLightExposure * 0.01f;
+
+ if(emissive.a > 0){
+ emissive = emissive * pow(emissive.a * 5, emissiveIntensity) * emissiveIntensity * 20 * emissive.a;
+ }
+ // emissive = emissive * pow(emissiveIntensity * 2.3, emissive.a);
+
+ Context_OutGBuff2.rgb = emissive.rgb;
+
+ // add fog after the lighting because shadows will cause the fog to darken
+ // which just results in the geometry looking like it's changed color
+ //#ifdef USE_FOG
+ // #ifdef FOG_LINEAR
+ // gl_FragColor = getFogLinear(gl_FragColor, m_FogColor, m_LinearFog.x, m_LinearFog.y, fogDistance);
+ // #endif
+ // #ifdef FOG_EXP
+ // gl_FragColor = getFogExp(gl_FragColor, m_FogColor, m_ExpFog, fogDistance);
+ // #endif
+ // #ifdef FOG_EXPSQ
+ // gl_FragColor = getFogExpSquare(gl_FragColor, m_FogColor, m_ExpSqFog, fogDistance);
+ // #endif
+ //#endif
+}
From e327316c87bec348c4c1ead864ff3dc583d82695 Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Wed, 18 Oct 2023 16:05:44 +0800
Subject: [PATCH 017/111] jme3-examples:Add a test code
---
.../renderpath/TestPBRTerrainAdvancedRenderPath.java | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java
index 8375db317a..0ae44506c2 100644
--- a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java
@@ -29,7 +29,7 @@
* 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.terrain;
+package jme3test.renderpath;
import com.jme3.app.SimpleApplication;
import com.jme3.asset.TextureKey;
@@ -53,6 +53,7 @@
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;
import com.jme3.texture.TextureArray;
+
import java.util.ArrayList;
import java.util.List;
@@ -117,9 +118,9 @@
*
*
*
- * @author yaRnMcDonuts
+ * @author yaRnMcDonuts,johnKkk
*/
-public class PBRTerrainAdvancedTest extends SimpleApplication {
+public class TestPBRTerrainAdvancedRenderPath extends SimpleApplication {
private TerrainQuad terrain;
private Material matTerrain;
@@ -150,7 +151,7 @@ public class PBRTerrainAdvancedTest extends SimpleApplication {
private final float camMoveSpeed = 50f;
public static void main(String[] args) {
- PBRTerrainAdvancedTest app = new PBRTerrainAdvancedTest();
+ TestPBRTerrainAdvancedRenderPath app = new TestPBRTerrainAdvancedRenderPath();
app.start();
}
@@ -355,6 +356,7 @@ private void setUpTerrainMaterial() {
// so setting an emissiveColor will apply equal intensity to every pixel
terrain.setMaterial(matTerrain);
+ new RenderPathHelper(this, new Vector3f(0, cam.getHeight() / 2, 0), KeyInput.KEY_K, "K");
}
private void setupKeys() {
From 63222d6d5196474d396d9041ee32e15b0ba8d62e Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Thu, 19 Oct 2023 17:11:55 +0800
Subject: [PATCH 018/111] jme3-core:Supplement core code comments, add full JME
license to each java file, fix a few minor issues
---
.../DeferredSinglePassLightingLogic.java | 55 ++++--
.../SkyLightAndReflectionProbeRender.java | 53 ++++-
...eBasedDeferredSinglePassLightingLogic.java | 185 +++++++++++++++---
.../src/main/java/com/jme3/math/FastMath.java | 5 +-
.../jme3/renderer/framegraph/FGBindable.java | 31 ++-
.../renderer/framegraph/FGBindingPass.java | 31 ++-
.../renderer/framegraph/FGCallbackPass.java | 31 ++-
.../renderer/framegraph/FGComputePass.java | 31 ++-
.../framegraph/FGContainerBindableSink.java | 31 ++-
.../FGFramebufferCopyBindableSink.java | 31 +++
.../framegraph/FGFramebufferSource.java | 31 +++
.../jme3/renderer/framegraph/FGGlobal.java | 31 ++-
.../com/jme3/renderer/framegraph/FGPass.java | 31 ++-
.../renderer/framegraph/FGRenderContext.java | 31 +++
.../framegraph/FGRenderQueuePass.java | 43 +++-
.../framegraph/FGRenderTargetSource.java | 31 +++
.../com/jme3/renderer/framegraph/FGSink.java | 31 ++-
.../jme3/renderer/framegraph/FGSource.java | 31 ++-
.../framegraph/FGTextureBindableSink.java | 31 +++
.../framegraph/FGVarBindableSink.java | 31 +++
.../jme3/renderer/framegraph/FGVarSource.java | 31 +++
.../jme3/renderer/framegraph/FrameGraph.java | 111 ++++++++++-
.../renderPass/DeferredLightDataSink.java | 31 +++
.../renderPass/DeferredLightDataSource.java | 31 +++
.../renderPass/DeferredShadingPass.java | 31 +++
.../jme3/renderer/renderPass/ForwardPass.java | 31 +++
.../jme3/renderer/renderPass/GBufferPass.java | 31 +++
.../com/jme3/renderer/renderPass/GuiPass.java | 31 +++
.../renderer/renderPass/IRenderGeometry.java | 31 +++
.../jme3/renderer/renderPass/OpaquePass.java | 31 +++
.../renderPass/PostProcessorPass.java | 31 +++
.../renderPass/ResolveSceneColorPass.java | 31 +++
.../jme3/renderer/renderPass/ScreenPass.java | 31 +++
.../com/jme3/renderer/renderPass/SkyPass.java | 31 +++
.../renderPass/TileDeferredShadingPass.java | 31 +++
.../renderer/renderPass/TranslucentPass.java | 31 +++
.../renderer/renderPass/TransparentPass.java | 31 +++
.../main/java/com/jme3/shader/DefineList.java | 2 +-
.../Common/MatDefs/Light/Lighting.j3md | 7 -
.../Common/MatDefs/Light/PBRLighting.j3md | 7 -
.../Common/MatDefs/Misc/Unshaded.j3md | 7 -
.../ShadingCommon/DeferredShading.frag | 5 +-
.../ShadingCommon/DeferredShading.j3md | 1 +
.../TileBasedDeferredShading.frag | 5 +-
.../TileBasedDeferredShading.j3md | 1 +
45 files changed, 1342 insertions(+), 106 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java
index 3bb9ea5472..8c4beecb78 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2021 jMonkeyEngine
+ * Copyright (c) 2009-2023 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -112,7 +112,7 @@ public DeferredSinglePassLightingLogic(TechniqueDef techniqueDef) {
if(bUseTexturePackMode){
packNbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_PACK_NB_LIGHTS, VarType.Int);
packTextureModeDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_USE_TEXTURE_PACK_MODE, VarType.Boolean);
- prepaLightData(1024);
+ prepareLightData(1024);
}
else{
nbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_LIGHTS, VarType.Int);
@@ -132,7 +132,7 @@ private void cleanupLightData(){
}
}
- private void prepaLightData(int lightNum){
+ private void prepareLightData(int lightNum){
this.lightNum = lightNum;
// 1d texture
lightData1 = new Texture2D(lightNum, 1, Image.Format.RGBA32F);
@@ -187,6 +187,27 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager
return super.makeCurrent(assetManager, renderManager, rendererCaps, lights, defines);
}
+ /**
+ * It seems the lighting information is encoded into 3 1D textures that are updated each frame with the currently visible lights:
+ * lightData1:
+ * - rgb stores lightColor
+ * - a stores lightTypeId
+ * lightData2:
+ * - directionalLightDirection
+ * - pointLightPosition + invRadius
+ * - spotLightPosition + invRadius
+ * lightData3:
+ * - spotLightDirection
+ * @param shader Current shader used for rendering (a global shader)
+ * @param g Current geometry used for rendering (a rect)
+ * @param lightList Information about all visible lights this frame
+ * @param numLights numLights
+ * @param rm renderManager
+ * @param startIndex first light start offset
+ * @param isLightCullStageDraw cullMode
+ * @param lastTexUnit lastTexUnit the index of the most recently-used texture unit
+ * @return the next starting index in the LightList
+ */
protected int updateLightListPackToTexture(Shader shader, Geometry g, LightList lightList, int numLights, RenderManager rm, int startIndex, boolean isLightCullStageDraw, int lastTexUnit) {
if (numLights == 0) { // this shader does not do lighting, ignore.
return 0;
@@ -298,16 +319,16 @@ protected int updateLightListPackToTexture(Shader shader, Geometry g, LightList
throw new UnsupportedOperationException("Unknown type of light: " + l.getType());
}
}
- temp.r = temp.g = temp.b = temp.a = 0;
- // Since the drawing is sent within the loop branch, and actually before the actual glSwapBuffers, the gl commands actually reside at the graphics driver level. So in order to correctly branch within the loop, the size must be fixed here (while filling the number of light sources).
- ColorRGBA temp2 = vars.color2;
- for(;curIndex < this.lightNum;curIndex++){
- temp2 = lightDataUpdateIO1.getPixel(curIndex, 0);
- if(temp2.r == 0 && temp2.g == 0 && temp2.b == 0 && temp2.a == 0)break;
- lightDataUpdateIO1.setPixel(curIndex, 0, temp);
- lightDataUpdateIO2.setPixel(curIndex, 0, temp);
- lightDataUpdateIO3.setPixel(curIndex, 0, temp);
- }
+// temp.r = temp.g = temp.b = temp.a = 0;
+// // Since the drawing is sent within the loop branch, and actually before the actual glSwapBuffers, the gl commands actually reside at the graphics driver level. So in order to correctly branch within the loop, the size must be fixed here (while filling the number of light sources).
+// ColorRGBA temp2 = vars.color2;
+// for(;curIndex < this.lightNum;curIndex++){
+// temp2 = lightDataUpdateIO1.getPixel(curIndex, 0);
+// if(temp2.r == 0 && temp2.g == 0 && temp2.b == 0 && temp2.a == 0)break;
+// lightDataUpdateIO1.setPixel(curIndex, 0, temp);
+// lightDataUpdateIO2.setPixel(curIndex, 0, temp);
+// lightDataUpdateIO3.setPixel(curIndex, 0, temp);
+// }
vars.release();
lightData1.getImage().setUpdateNeeded();
lightData2.getImage().setUpdateNeeded();
@@ -456,14 +477,16 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry
if(bUseTexturePackMode){
if(this.lightNum != renderManager.getCurMaxDeferredShadingLightNum()){
cleanupLightData();
- prepaLightData(renderManager.getCurMaxDeferredShadingLightNum());
+ prepareLightData(renderManager.getCurMaxDeferredShadingLightNum());
}
// todo:Currently, this texturePackMode is only suitable for scenes where there are a large number of light sources per frame. The number of light sources is submitted to the texture all at once, so lightNum can be pre-allocated, but light source information can also be submitted to the texture all at once here, and then drawn in multiple passes (drawing each time by the specified singlePassLightBatchSize)
- Uniform lightCount = shader.getUniform("g_LightCount");
SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, true);
int count = lights.size();
+ // FIXME:Setting uniform variables this way will take effect immediately in the current frame, however lightData is set through geometry.getMaterial().setTexture(XXX) which will take effect next frame, so here I changed to use geometry.getMaterial().setParam() uniformly to update all parameters, to keep the frequency consistent.
+// Uniform lightCount = shader.getUniform("g_LightCount");
// lightCount.setValue(VarType.Int, count);
- lightCount.setValue(VarType.Int, this.lightNum);
+// lightCount.setValue(VarType.Int, this.lightNum);
+ geometry.getMaterial().setInt("NBLight", count);
if(count == 0){
nbRenderedLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, nbRenderedLights, isLightCullStageDraw, lastTexUnit);
renderer.setShader(shader);
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/SkyLightAndReflectionProbeRender.java b/jme3-core/src/main/java/com/jme3/material/logic/SkyLightAndReflectionProbeRender.java
index f402c32a85..9ba78a20e1 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/SkyLightAndReflectionProbeRender.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/SkyLightAndReflectionProbeRender.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.material.logic;
import com.jme3.light.AmbientLight;
@@ -16,10 +47,21 @@
/**
* Rendering logic for handling SkyLight and ReflectionProbe.
+ * todo:The functionality of this tool class is not yet complete, because LightProbe has not yet been split into SkyLight and ReflectionProbe. So the code here is just to be compatible with the extraction of LightProbe and lay the groundwork for subsequent work.
* @author JohnKkk
*/
public class SkyLightAndReflectionProbeRender {
+ /**
+ * Update lightProbe data to current shader (currently data comes from lightProbe, later this method will be used for skyLight and reflectionProbe)
+ * @param rm
+ * @param lastTexUnit
+ * @param lightProbeData
+ * @param shCoeffs
+ * @param lightProbePemMap
+ * @param lightProbe
+ * @return
+ */
public static int setSkyLightAndReflectionProbeData(RenderManager rm, int lastTexUnit, Uniform lightProbeData, Uniform shCoeffs, Uniform lightProbePemMap, LightProbe lightProbe) {
lightProbeData.setValue(VarType.Matrix4, lightProbe.getUniformMatrix());
@@ -42,6 +84,13 @@ public static int setSkyLightAndReflectionProbeData(RenderManager rm, int lastTe
return lastTexUnit;
}
+ /**
+ * Extract which lightProbes should affect the currently rendered object. Currently, this method is only used in deferredPath and only works for the first three collected lightProbes, so it is problematic, but I put it here to prepare for future functionality (and compatibilty with current lightProbes).
+ * @param lightList
+ * @param ambientLightColor
+ * @param skyLightAndReflectionProbes
+ * @param removeLights
+ */
public static void extractSkyLightAndReflectionProbes(LightList lightList, ColorRGBA ambientLightColor, List skyLightAndReflectionProbes, boolean removeLights) {
ambientLightColor.set(0, 0, 0, 1);
skyLightAndReflectionProbes.clear();
@@ -50,14 +99,14 @@ public static void extractSkyLightAndReflectionProbes(LightList lightList, Color
if (l instanceof AmbientLight) {
ambientLightColor.addLocal(l.getColor());
if(removeLights){
- lightList.remove(l);
+ lightList.remove(j);
j--;
}
}
if (l instanceof LightProbe) {
skyLightAndReflectionProbes.add((LightProbe) l);
if(removeLights){
- lightList.remove(l);
+ lightList.remove(j);
j--;
}
}
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
index d29350bb9c..90b41d86ae 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.material.logic;
import com.jme3.asset.AssetManager;
@@ -126,6 +157,8 @@ public class TileBasedDeferredSinglePassLightingLogic extends DefaultTechniqueDe
/**
* TileInfo
+ * This is a structure representing Tile information, including how many tiles the screen is divided into, how many tiles in horizontal and vertical directions, the size of each tile, etc.
+ * @author JohnKkk
*/
public static class TileInfo{
int tileSize = 0;
@@ -147,6 +180,8 @@ public void updateTileSize(int tileSize){
/**
* LightFrustum
+ * This is an internal helper class to determine the on-screen Rect for the current PointLight. It's called Frustum because it may be expanded to 3D Cluster in space in the future.
+ * @author JohnKkk
*/
private static class LightFrustum{
float left;
@@ -162,6 +197,9 @@ public LightFrustum(float left, float right, float top, float bottom) {
}
}
+ /**
+ * Clear the lightsIndex cache texture for rebuilding.
+ */
private void cleanupLightsIndexTexture(){
if(lightsIndexData != null){
lightsIndexData.getImage().dispose();
@@ -169,6 +207,11 @@ private void cleanupLightsIndexTexture(){
}
}
+ /**
+ * Rebuild the lightsIndex cache texture.
+ * The square root of the total number of lights that need to be queried. Note that the total number of lights to be queried is different from the total number of visible lights in the current view frustum. One tile may contain 100 lights, another tile may also contain 100 lights, then the total lights to query is 200, while the total lights in the current view frustum may only be 100!
+ * @param lightIndexWidth
+ */
private void createLightsIndexTexture(int lightIndexWidth){
this.lightIndexWidth = lightIndexWidth;
lightsIndexData = new Texture2D(lightIndexWidth, lightIndexWidth, Image.Format.RGBA32F);
@@ -182,6 +225,9 @@ private void createLightsIndexTexture(int lightIndexWidth){
lightsIndexDataUpdateIO = ImageRaster.create(lightsIndexData.getImage());
}
+ /**
+ * Clear the lightsDecode cache texture for rebuilding.
+ */
private void cleanupLightsDecodeTexture(){
if(lightsDecodeData != null){
lightsDecodeData.getImage().dispose();
@@ -189,14 +235,19 @@ private void cleanupLightsDecodeTexture(){
}
}
+ /**
+ * Clear the lightsIndex and lightsDecode cache texture for rebuilding.
+ */
private void cleanupTileTexture(){
cleanupLightsIndexTexture();
cleanupLightsDecodeTexture();
}
/**
- * reset.
- * @param tileNum
+ * Reallocate texture memory for the query texture for the specified tile size. This detection is performed every frame to ensure the cache textures lightsDecode and lightsIndex are recreated when screen changes or tiles change dynamically.
+ * @param tileWidth Number of tiles in horizontal direction
+ * @param tileHeight Number of tiles in vertical direction
+ * @param tileNum tileWidth * tileHeight
*/
private void reset(int tileWidth, int tileHeight, int tileNum){
if(tileWidth != _tileWidth || tileHeight != _tileHeight){
@@ -238,6 +289,15 @@ private void reset(int tileWidth, int tileHeight, int tileNum){
}
lightsIndex.clear();
}
+
+ /**
+ * Some lights affect the whole screen, such as DirectionalLight, PointLight with infinite radius, and SpotLight. These lights will affect all tiles, so they are passed to all tiles in this method.
+ * @param tileWidth
+ * @param tileHeight
+ * @param tileNum
+ * @param tiles
+ * @param lightId
+ */
private void tilesFullUpdate(int tileWidth, int tileHeight, int tileNum, ArrayList> tiles, int lightId){
// calc tiles
int tileId = 0;
@@ -251,6 +311,16 @@ private void tilesFullUpdate(int tileWidth, int tileHeight, int tileNum, ArrayLi
}
}
+ /**
+ * Assigns the given light source to affected tiles based on its screen space view frustum.
+ * @param tileSize
+ * @param tileWidth
+ * @param tileHeight
+ * @param tileNum
+ * @param tiles
+ * @param lightFrustum screen space lightFrustum(rect)
+ * @param lightId targetLightId
+ */
private void tilesUpdate(int tileSize, int tileWidth, int tileHeight, int tileNum, ArrayList> tiles, LightFrustum lightFrustum, int lightId){
// tile built on
//⬆
@@ -274,6 +344,14 @@ private void tilesUpdate(int tileSize, int tileWidth, int tileHeight, int tileNu
}
}
}
+
+ /**
+ * Keep the method but don't use it.
+ * @param camera
+ * @param light
+ * @return
+ */
+ @Deprecated
private final LightFrustum lightClip(Camera camera, Light light){
if(light instanceof PointLight){
PointLight pl = (PointLight)light;
@@ -308,6 +386,11 @@ private final LightFrustum lightClip(Camera camera, Light light){
return null;
}
+ /**
+ * Find out the view frustum (currently 2D so it's Rect) of the given light source in screen space. Once the screen-space view frustum of the light is determined, it can be assigned to associated tiles so that the tiles can use it for lighting shading.
+ * @param light targetLight
+ * @return Returns the screen space view frustum of the light, used to find associated tiles
+ */
private final LightFrustum lightClip(Light light){
// todo:Currently, only point light sources are processed
if(light instanceof PointLight){
@@ -374,6 +457,19 @@ private final LightFrustum lightClip(Light light){
return null;
}
+ /**
+ * Encode light information for each tile, which contains two parts:
+ * 1. The light offset and total number of lights to draw for each tile
+ * 2. The encoded list of light ids
+ * This method is called every frame, and the texture is dynamically sized (although jme3's encapsulation of dynamic texture sizes is a bit problematic, so it's currently a fixed-size dynamic texture).
+ * @param tileNum Total number of tiles
+ * @param tiles List of light ids for each tile
+ * @param tileWidth Number of tiles in horizontal direction
+ * @param tileHeight Number of tiles in vertical direction
+ * @param shader Current shader used for rendering (a global shader)
+ * @param g Current geometry used for rendering (a rect)
+ * @param lights Information about all visible lights this frame
+ */
private void tileLightDecode(int tileNum, ArrayList> tiles, int tileWidth, int tileHeight, Shader shader, Geometry g, LightList lights){
int len = lights.size();
@@ -475,7 +571,7 @@ public TileBasedDeferredSinglePassLightingLogic(TechniqueDef techniqueDef) {
if(bUseTexturePackMode){
packNbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_PACK_NB_LIGHTS, VarType.Int);
packTextureModeDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_USE_TEXTURE_PACK_MODE, VarType.Boolean);
- prepaLightData(1024);
+ prepareLightData(1024);
}
else{
nbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_LIGHTS, VarType.Int);
@@ -495,7 +591,14 @@ private void cleanupLightData(){
}
}
- private void prepaLightData(int lightNum){
+ /**
+ * Try reallocating textures to accommodate enough light data.
+ * Currently, a large amount of light information is stored in textures, divided into three texture1d,
+ * lightData1 stores lightColor (rgb stores lightColor, a stores lightType), lightData2 stores lightPosition +
+ * invRange/lightDir, lightData3 stores dir and spotAngleCos about SpotLight.
+ * @param lightNum By preallocating texture memory for the known number of lights, dynamic reallocation at runtime can be prevented.
+ */
+ private void prepareLightData(int lightNum){
this.lightNum = lightNum;
// 1d texture
lightData1 = new Texture2D(lightNum, 1, Image.Format.RGBA32F);
@@ -528,19 +631,19 @@ private void prepaLightData(int lightNum){
lightData3.getImage().setMipmapsGenerated(false);
lightDataUpdateIO3 = ImageRaster.create(lightData3.getImage());
- TempVars vars = TempVars.get();
- ColorRGBA temp = vars.color;
- temp.r = temp.g = temp.b = temp.a = 0;
- // Since the drawing is sent within the loop branch, and actually before the actual glSwapBuffers, the gl commands actually reside at the graphics driver level. So in order to correctly branch within the loop, the size must be fixed here (while filling the number of light sources).
- ColorRGBA temp2 = vars.color2;
- for(int curIndex = 0;curIndex < this.lightNum;curIndex++){
- temp2 = lightDataUpdateIO1.getPixel(curIndex, 0);
- if(temp2.r == 0 && temp2.g == 0 && temp2.b == 0 && temp2.a == 0)break;
- lightDataUpdateIO1.setPixel(curIndex, 0, temp);
- lightDataUpdateIO2.setPixel(curIndex, 0, temp);
- lightDataUpdateIO3.setPixel(curIndex, 0, temp);
- }
- vars.release();
+// TempVars vars = TempVars.get();
+// ColorRGBA temp = vars.color;
+// temp.r = temp.g = temp.b = temp.a = 0;
+// // Since the drawing is sent within the loop branch, and actually before the actual glSwapBuffers, the gl commands actually reside at the graphics driver level. So in order to correctly branch within the loop, the size must be fixed here (while filling the number of light sources).
+// ColorRGBA temp2 = vars.color2;
+// for(int curIndex = 0;curIndex < this.lightNum;curIndex++){
+// temp2 = lightDataUpdateIO1.getPixel(curIndex, 0);
+// if(temp2.r == 0 && temp2.g == 0 && temp2.b == 0 && temp2.a == 0)break;
+// lightDataUpdateIO1.setPixel(curIndex, 0, temp);
+// lightDataUpdateIO2.setPixel(curIndex, 0, temp);
+// lightDataUpdateIO3.setPixel(curIndex, 0, temp);
+// }
+// vars.release();
}
@Override
@@ -564,6 +667,27 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager
return super.makeCurrent(assetManager, renderManager, rendererCaps, lights, defines);
}
+ /**
+ * It seems the lighting information is encoded into 3 1D textures that are updated each frame with the currently visible lights:
+ * lightData1:
+ * - rgb stores lightColor
+ * - a stores lightTypeId
+ * lightData2:
+ * - directionalLightDirection
+ * - pointLightPosition + invRadius
+ * - spotLightPosition + invRadius
+ * lightData3:
+ * - spotLightDirection
+ * @param shader Current shader used for rendering (a global shader)
+ * @param g Current geometry used for rendering (a rect)
+ * @param lightList Information about all visible lights this frame
+ * @param numLights numLights
+ * @param rm renderManager
+ * @param startIndex first light start offset
+ * @param isLightCullStageDraw cullMode
+ * @param lastTexUnit lastTexUnit the index of the most recently-used texture unit
+ * @return the next starting index in the LightList
+ */
protected int updateLightListPackToTexture(Shader shader, Geometry g, LightList lightList, int numLights, RenderManager rm, int startIndex, boolean isLightCullStageDraw, int lastTexUnit) {
if (numLights == 0) { // this shader does not do lighting, ignore.
return 0;
@@ -675,14 +799,14 @@ protected int updateLightListPackToTexture(Shader shader, Geometry g, LightList
}
temp.r = temp.g = temp.b = temp.a = 0;
// Since the drawing is sent within the loop branch, and actually before the actual glSwapBuffers, the gl commands actually reside at the graphics driver level. So in order to correctly branch within the loop, the size must be fixed here (while filling the number of light sources).
- ColorRGBA temp2 = vars.color2;
- for(;curIndex < this.lightNum;curIndex++){
- temp2 = lightDataUpdateIO1.getPixel(curIndex, 0);
- if(temp2.r == 0 && temp2.g == 0 && temp2.b == 0 && temp2.a == 0)break;
- lightDataUpdateIO1.setPixel(curIndex, 0, temp);
- lightDataUpdateIO2.setPixel(curIndex, 0, temp);
- lightDataUpdateIO3.setPixel(curIndex, 0, temp);
- }
+// ColorRGBA temp2 = vars.color2;
+// for(;curIndex < this.lightNum;curIndex++){
+// temp2 = lightDataUpdateIO1.getPixel(curIndex, 0);
+// if(temp2.r == 0 && temp2.g == 0 && temp2.b == 0 && temp2.a == 0)break;
+// lightDataUpdateIO1.setPixel(curIndex, 0, temp);
+// lightDataUpdateIO2.setPixel(curIndex, 0, temp);
+// lightDataUpdateIO3.setPixel(curIndex, 0, temp);
+// }
vars.release();
lightData1.getImage().setUpdateNeeded();
lightData2.getImage().setUpdateNeeded();
@@ -816,14 +940,15 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry
isLightCullStageDraw = geometry.getUserData(_S_LIGHT_CULL_DRAW_STAGE);
}
if(bUseTexturePackMode){
- Uniform lightCount = shader.getUniform("g_LightCount");
if(this.lightNum != renderManager.getCurMaxDeferredShadingLightNum()){
cleanupLightData();
- prepaLightData(renderManager.getCurMaxDeferredShadingLightNum());
+ prepareLightData(renderManager.getCurMaxDeferredShadingLightNum());
}
SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, true);
int count = lights.size();
- lightCount.setValue(VarType.Int, this.lightNum);
+ // FIXME:Setting uniform variables this way will take effect immediately in the current frame, however lightData is set through geometry.getMaterial().setTexture(XXX) which will take effect next frame, so here I changed to use geometry.getMaterial().setParam() uniformly to update all parameters, to keep the frequency consistent.
+// Uniform lightCount = shader.getUniform("g_LightCount");
+// lightCount.setValue(VarType.Int, count);
// Divide lights into full screen lights and non-full screen lights. Currently only PointLights with radius are treated as non-full screen lights.
// The lights passed in here must be PointLights with valid radii. Another approach is to fill tiles with infinite range Lights.
if(count > 0){
@@ -873,7 +998,8 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry
}
// Encode light source information
- lightCount.setValue(VarType.Int, count);
+// lightCount.setValue(VarType.Int, count);
+// geometry.getMaterial().setInt("NBLight", count);
tileLightDecode(tileNum, tiles, tileWidth, tileHeight, shader, geometry, lights);
while (nbRenderedLights < count) {
nbRenderedLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, nbRenderedLights, isLightCullStageDraw, lastTexUnit);
@@ -882,6 +1008,7 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry
}
}
else{
+// geometry.getMaterial().setInt("NBLight", 0);
nbRenderedLights = updateLightListPackToTexture(shader, geometry, lights, count, renderManager, nbRenderedLights, isLightCullStageDraw, lastTexUnit);
renderer.setShader(shader);
renderMeshFromGeometry(renderer, geometry);
diff --git a/jme3-core/src/main/java/com/jme3/math/FastMath.java b/jme3-core/src/main/java/com/jme3/math/FastMath.java
index 1f482585a2..1a65918fb9 100644
--- a/jme3-core/src/main/java/com/jme3/math/FastMath.java
+++ b/jme3-core/src/main/java/com/jme3/math/FastMath.java
@@ -844,7 +844,7 @@ public static float determinant(double m00, double m01, double m02,
}
/**
- * Returns a random integer between min and max.
+ * Returns a random float between min and max.
*
* @param min the desired minimum value
* @param max the desired maximum value
@@ -852,7 +852,8 @@ public static float determinant(double m00, double m01, double m02,
* max (inclusive).
*/
public static float nextRandomFloat(float min, float max) {
- return (nextRandomFloat() * (max - min + 1.0f)) + min;
+ float f = (nextRandomFloat() * (max - min + 1.0f)) + min;
+ return Math.min(Math.max(f, min), max);
}
/**
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java
index 7fb23b2f38..64d8b63cb2 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java
@@ -1,6 +1,33 @@
/*
- * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java
index 38e9916c9b..0288e38216 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java
@@ -1,6 +1,33 @@
/*
- * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGCallbackPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGCallbackPass.java
index 86e79fede2..2b5dd005db 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGCallbackPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGCallbackPass.java
@@ -1,6 +1,33 @@
/*
- * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGComputePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGComputePass.java
index 1977529645..015017ff67 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGComputePass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGComputePass.java
@@ -1,6 +1,33 @@
/*
- * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java
index d015234fc3..25c7eb70f8 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java
@@ -1,6 +1,33 @@
/*
- * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java
index 89dc6951ff..ef6d86945d 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
import com.jme3.texture.FrameBuffer;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferSource.java
index ebac06934a..876b42ba4d 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferSource.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferSource.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
import com.jme3.texture.FrameBuffer;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGGlobal.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGGlobal.java
index d1a11880dc..40332f6af3 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGGlobal.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGGlobal.java
@@ -1,6 +1,33 @@
/*
- * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
index 08b12016f6..f4075bf630 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
@@ -1,6 +1,33 @@
/*
- * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java
index 72c933e181..57821553db 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
import com.jme3.renderer.RenderManager;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java
index 1504c01d7d..9e7b205702 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java
@@ -1,6 +1,33 @@
/*
- * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
@@ -23,13 +50,18 @@ public FGRenderQueuePass(String name) {
super(name);
}
+ /**
+ * A RenderPass may use a specified viewport. This can be set using this function.
+ * @param forceViewPort targetViewPort
+ */
public void setForceViewPort(ViewPort forceViewPort) {
this.forceViewPort = forceViewPort;
}
/**
* Dispatch visible mesh draw commands to process task, to prepare for this pass.
- * @param renderQueue
+ * todo:For the current GLRenderer, the MeshDrawCommand concept actually does not exist. So this is prepared for future Vulkan-like renderers
+ * @param renderQueue targetRenderQueue
*/
public abstract void dispatchPassSetup(RenderQueue renderQueue);
@@ -50,6 +82,11 @@ public void execute(FGRenderContext renderContext) {
executeDrawCommandList(renderContext);
renderContext.renderManager.setRenderGeometryHandler(null);
}
+
+ /**
+ * todo:For the current GLRenderer, the MeshDrawCommand concept actually does not exist. So this is prepared for future Vulkan-like renderers
+ * @param renderContext
+ */
public abstract void executeDrawCommandList(FGRenderContext renderContext);
@Override
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderTargetSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderTargetSource.java
index 6212e4b6f6..645651061a 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderTargetSource.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderTargetSource.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
import com.jme3.texture.FrameBuffer;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSink.java
index 27a8879b5f..c073ce04b8 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSink.java
@@ -1,6 +1,33 @@
/*
- * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSource.java
index 370cd92d8a..cdf9ad3c19 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSource.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSource.java
@@ -1,6 +1,33 @@
/*
- * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java
index 45f71597d8..798aab91d8 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
import com.jme3.material.Material;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarBindableSink.java
index 68207df98c..e657912272 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarBindableSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarBindableSink.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
import java.util.ArrayList;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java
index 6b0723e307..5ee2d24575 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
/**
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
index a90d64087d..10009a8514 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
@@ -1,13 +1,52 @@
/*
- * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
import java.util.ArrayList;
/**
- * @see https://www.gdcvault.com/play/1024612/FrameGraph-Extensible-Rendering-Architecture-in.
+ * The FrameGraph system is used to manage render passes and the dependencies between them in a declarative way. Some key aspects:
+ * - It represents the rendering pipeline as a directed acyclic graph of passes and their inputs/outputs.
+ * - Passes can be things like shadow map creation, geometry passes, post-processing etc.
+ * - Outputs from one pass can be reused as inputs to others, avoiding redundant work.
+ * - The FrameGraph handles synchronization, pass scheduling and resource transitions automatically based on dependencies.
+ * - Developers define passes and connect inputs/outputs, while the system handles execution.
+ * - Passes can have arbitrary Java logic, shaders, and framebuffer configurations.
+ * - Framebuffers are created on demand based on pass requirements.
+ * - FrameGraphRecursion queues allow recursive pass execution (e.g. for nested realtime reflections).
+ * - The system optimizes what needs to run each frame based on dirty state.
+ * In summary, FrameGraph enables declaring a rendering pipeline at a high level while handling all the underlying complexity of synchronization, resource management, and efficient execution. This simplifies the developer's job and avoids boilerplate code.
+ * The key advantages are automatic input/output reuse, efficient scheduling and batching, simplified boilerplate, and handling advanced cases like recursions. Overall it provides a clean abstraction for building complex, efficient rendering pipelines.
+ * https://www.gdcvault.com/play/1024612/FrameGraph-Extensible-Rendering-Architecture-in.
* @author JohnKkk
*/
public class FrameGraph {
@@ -28,6 +67,9 @@ public FGRenderContext getRenderContext() {
return renderContext;
}
+ /**
+ * Binding input resources to the global sink in a FrameGraph refers to making certain resources available globally to all passes.
+ */
protected void linkGlobalSinks(){
for(FGSink sink : globalSinks){
String linkPassName = sink.getLinkPassName();
@@ -40,7 +82,11 @@ protected void linkGlobalSinks(){
}
}
}
-
+
+ /**
+ * Binding input resources to a specific pass in a FrameGraph refers to connecting the necessary resources that pass requires as inputs.
+ * @param pass targetPass
+ */
protected void linkSinks(FGPass pass){
for(FGSink sink : pass.getSinks()){
String linkPassName = sink.getLinkPassName();
@@ -94,7 +140,18 @@ protected void linkSinks(FGPass pass){
}
}
}
-
+
+ /**
+ * Execute frameGraph
+ *
+ * example:
+ * FrameGraph fg = new FrameGraph();
+ * fg.addPass(pass1);
+ * fg.addPass(pass2);
+ * fg.finalize();
+ * fg.execute();
+ *
+ */
public void execute(){
assert finalized;
for(FGPass nextPass : passes){
@@ -102,7 +159,11 @@ public void execute(){
}
finalized = false;
}
-
+
+ /**
+ * The FrameGraph can be reused by just calling reset() to clear the current graph, then re-adding the required passes and binding the necessary resources again, before calling execute() once more.
+ * This allows reusing the same FrameGraph instance to construct different render pipelines, avoiding repeated resource creation. Just update the passes and connections as needed. This improves code reuse and simplifies render pipeline adjustments.
+ */
public void reset(){
assert !finalized;
for(FGPass nextPass : passes){
@@ -113,11 +174,19 @@ public void reset(){
renderContext.renderManager.setRenderGeometryHandler(null);
}
}
-
+
+ /**
+ * Some resources may not belong to any pass, but need to be shared across multiple framegraphs.
+ * @param source targetFGSource
+ */
public void addGlobalSource(FGSource source){
globalSources.add(source);
}
+ /**
+ * Some resources may not belong to any pass, but need to be shared across multiple framegraphs.
+ * @param source targetFGSource
+ */
public void replaceOrAddGlobalSource(FGSource source){
int index = -1;
for(int i = 0;i < globalSources.size();i++){
@@ -131,11 +200,30 @@ public void replaceOrAddGlobalSource(FGSource source){
}
globalSources.add(source);
}
-
+
+ /**
+ * A FrameGraph may contain global sinks, such as a backBuffer.
+ * @param sink targetFGSink
+ */
public void addGlobalSink(FGSink sink){
globalSinks.add(sink);
}
-
+
+ /**
+ * Adding an executable Pass to a FrameGraph, note that Passes will execute in the order they are added:
+ * - To add a Pass to a FrameGraph, call frameGraph.addPass() and provide a name and a Pass executor function.
+ * - The executor function contains the actual rendering commands for that Pass.
+ * - Passes added earlier will execute before ones added later.
+ * - Add passes in the order of desired execution.
+ * - After adding passes, call frameGraph.validate() to validate the graph before execution.
+ * - Then call frameGraph.compile() to prepare the graph for execution.
+ * - In the render loop, call frameGraph.execute() to run the Pass network.
+ * - Passes with unsatisfied resource dependencies will be skipped until their inputs are ready.
+ * - FrameGraph handles scheduling passes in the correct order automatically based on dependencies.
+ * - But the order passes are added determines the base execution order.
+ * So in summary, add Passes in the desired execution order to the FrameGraph. The FrameGraph system will then handle scheduling them based on resource availability while respecting the original adding order.
+ * @param pass targetPass
+ */
public final void addPass(FGPass pass){
assert !finalized;
// validate name uniqueness
@@ -164,7 +252,10 @@ public final FGPass findPassByName(String name){
System.err.println("Failed to find pass name");
return null;
}
-
+
+ /**
+ * Prepare all passes to get ready for execution of the frameGraph, by calling this function before executing the frameGraph.
+ */
public final void finalize(){
assert !finalized;
for(FGPass nextPass : passes){
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSink.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSink.java
index 26fa54ad5d..f20ac645b7 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSink.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.renderPass;
import com.jme3.renderer.framegraph.FGBindable;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSource.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSource.java
index b932087d63..9decca3bb3 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSource.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSource.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.renderPass;
import com.jme3.light.LightList;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredShadingPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredShadingPass.java
index 5fc201093c..40af7c1aee 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredShadingPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredShadingPass.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.renderPass;
import com.jme3.light.LightList;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/ForwardPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/ForwardPass.java
index f34c41ae29..44feb97c03 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/ForwardPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/ForwardPass.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.renderPass;
import com.jme3.renderer.Camera;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java
index 7ef1061068..8329195692 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.renderPass;
import com.jme3.light.Light;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/GuiPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/GuiPass.java
index 01c3a35734..256e974fe3 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/GuiPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/GuiPass.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.renderPass;
import com.jme3.renderer.Camera;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/IRenderGeometry.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/IRenderGeometry.java
index d3de38c7c7..7c62efae9d 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/IRenderGeometry.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/IRenderGeometry.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.renderPass;
import com.jme3.renderer.RenderManager;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/OpaquePass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/OpaquePass.java
index 96ff9a4737..ca58b49ed7 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/OpaquePass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/OpaquePass.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.renderPass;
import com.jme3.renderer.framegraph.FGRenderContext;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/PostProcessorPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/PostProcessorPass.java
index 05a73579cc..588517ece6 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/PostProcessorPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/PostProcessorPass.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.renderPass;
import com.jme3.post.SceneProcessor;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/ResolveSceneColorPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/ResolveSceneColorPass.java
index fea33f6731..ac06528f1f 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/ResolveSceneColorPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/ResolveSceneColorPass.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.renderPass;
import com.jme3.material.Material;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/ScreenPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/ScreenPass.java
index 5396e0f2bb..fc943a2a45 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/ScreenPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/ScreenPass.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.renderPass;
import com.jme3.asset.AssetManager;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/SkyPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/SkyPass.java
index dfe4154987..a78b78c55a 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/SkyPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/SkyPass.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.renderPass;
import com.jme3.renderer.framegraph.FGRenderContext;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/TileDeferredShadingPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/TileDeferredShadingPass.java
index 63dce6a330..5ed0492a04 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/TileDeferredShadingPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/TileDeferredShadingPass.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.renderPass;
import com.jme3.light.LightList;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/TranslucentPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/TranslucentPass.java
index 713ef95956..8f798cfafc 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/TranslucentPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/TranslucentPass.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.renderPass;
import com.jme3.renderer.framegraph.FGRenderContext;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/TransparentPass.java b/jme3-core/src/main/java/com/jme3/renderer/renderPass/TransparentPass.java
index e473b1f830..fb81c4c55d 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/TransparentPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/renderPass/TransparentPass.java
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.renderPass;
import com.jme3.renderer.framegraph.FGRenderContext;
diff --git a/jme3-core/src/main/java/com/jme3/shader/DefineList.java b/jme3-core/src/main/java/com/jme3/shader/DefineList.java
index d368f24948..6cc57c64bd 100644
--- a/jme3-core/src/main/java/com/jme3/shader/DefineList.java
+++ b/jme3-core/src/main/java/com/jme3/shader/DefineList.java
@@ -41,7 +41,7 @@
*/
public final class DefineList {
- public static final int MAX_DEFINES = 64;
+ public static final int MAX_DEFINES = 65;
private long isSet;
private final int[] values;
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md
index 6fe7c03962..7940dd3da3 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.j3md
@@ -128,13 +128,6 @@ MaterialDef Phong Lighting {
Vector2 LinearFog
Float ExpFog
Float ExpSqFog
-
- // Context GBuffer Data
- Texture2D Context_InGBuff0
- Texture2D Context_InGBuff1
- Texture2D Context_InGBuff2
- Texture2D Context_InGBuff3
- Texture2D Context_InGBuff4
}
Technique {
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md
index a9aba47d6d..9783972821 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.j3md
@@ -125,13 +125,6 @@ MaterialDef PBR Lighting {
Boolean UseVertexColor
Boolean BackfaceShadows : false
-
- // Context GBuffer Data
- Texture2D Context_InGBuff0
- Texture2D Context_InGBuff1
- Texture2D Context_InGBuff2
- Texture2D Context_InGBuff3
- Texture2D Context_InGBuff4
}
Technique {
diff --git a/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md b/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md
index 73c2658a1b..7af5add5b9 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md
@@ -63,13 +63,6 @@ MaterialDef Unshaded {
// 1.0 indicates 100% desaturation
Float DesaturationValue
-
- // Context GBuffer Data
- Texture2D Context_InGBuff0
- Texture2D Context_InGBuff1
- Texture2D Context_InGBuff2
- Texture2D Context_InGBuff3
- Texture2D Context_InGBuff4
}
Technique {
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag
index ee0de9c81b..21e0588780 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag
@@ -20,6 +20,7 @@ varying mat4 viewProjectionMatrixInverse;
uniform mat4 g_ViewMatrix;
uniform vec3 g_CameraPosition;
uniform vec4 g_AmbientLightColor;
+uniform int m_NBLight;
#if defined(USE_TEXTURE_PACK_MODE)
uniform int g_LightCount;
@@ -62,7 +63,7 @@ void main(){
int lightNum = 0;
#if defined(USE_TEXTURE_PACK_MODE)
float lightTexSizeInv = 1.0f / (float(PACK_NB_LIGHTS) - 1.0f);
- lightNum = g_LightCount;
+ lightNum = m_NBLight;
#else
lightNum = NB_LIGHTS;
#endif
@@ -147,7 +148,7 @@ void main(){
int lightNum = 0;
#if defined(USE_TEXTURE_PACK_MODE)
float lightTexSizeInv = 1.0f / (float(PACK_NB_LIGHTS) - 1.0f);
- lightNum = g_LightCount;
+ lightNum = m_NBLight;
#else
lightNum = NB_LIGHTS;
#endif
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md
index dd1c1bc7f4..202deba7bd 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md
@@ -1,6 +1,7 @@
MaterialDef DeferredShading {
MaterialParameters {
+ Int NBLight
// For instancing
Boolean UseInstancing
// UseLightsCull
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
index 915c99fa53..a1a8a60772 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
@@ -20,6 +20,7 @@ varying mat4 viewProjectionMatrixInverse;
uniform mat4 g_ViewMatrix;
uniform vec3 g_CameraPosition;
uniform vec4 g_AmbientLightColor;
+uniform int m_NBLight;
@@ -71,7 +72,7 @@ void main(){
int lightNum = 0;
#if defined(USE_TEXTURE_PACK_MODE)
float lightTexSizeInv = 1.0f / (float(PACK_NB_LIGHTS) - 1.0f);
- lightNum = g_LightCount;
+ lightNum = m_NBLight;
#else
lightNum = NB_LIGHTS;
#endif
@@ -249,7 +250,7 @@ void main(){
int lightNum = 0;
#if defined(USE_TEXTURE_PACK_MODE)
float lightTexSizeInv = 1.0f / (float(PACK_NB_LIGHTS) - 1.0f);
- lightNum = g_LightCount;
+ lightNum = m_NBLight;
#else
lightNum = NB_LIGHTS;
#endif
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md
index f5c8e4ed28..1d73635a52 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md
@@ -1,6 +1,7 @@
MaterialDef DeferredShading {
MaterialParameters {
+ Int NBLight
// For instancing
Boolean UseInstancing
// UseLightsCull
From 82c6dc20b3b3da2fd4a84bfabc9f8bf16cc45a66 Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Thu, 19 Oct 2023 17:12:56 +0800
Subject: [PATCH 019/111] jme3-terrain:Implement PBRTerrain compatibility code
---
.../MatDefs/Terrain/AdvancedPBRTerrain.j3md | 6 -
.../GBufferPack/PBRTerrainGBufferPack.frag | 435 ++++++++++++++++++
.../Common/MatDefs/Terrain/PBRTerrain.j3md | 91 ++++
3 files changed, 526 insertions(+), 6 deletions(-)
create mode 100644 jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/PBRTerrainGBufferPack.frag
diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/AdvancedPBRTerrain.j3md b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/AdvancedPBRTerrain.j3md
index 7bd7350498..d17e8e860b 100644
--- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/AdvancedPBRTerrain.j3md
+++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/AdvancedPBRTerrain.j3md
@@ -250,12 +250,6 @@ MaterialDef Advanced PBR Terrain {
// Alpha threshold for fragment discarding
Float AlphaDiscardThreshold (AlphaTestFallOff)
- // Context GBuffer Data
- Texture2D Context_InGBuff0
- Texture2D Context_InGBuff1
- Texture2D Context_InGBuff2
- Texture2D Context_InGBuff3
- Texture2D Context_InGBuff4
}
Technique {
diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/PBRTerrainGBufferPack.frag b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/PBRTerrainGBufferPack.frag
new file mode 100644
index 0000000000..ba92341a60
--- /dev/null
+++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/GBufferPack/PBRTerrainGBufferPack.frag
@@ -0,0 +1,435 @@
+#import "Common/ShaderLib/GLSLCompat.glsllib"
+#import "Common/ShaderLib/PBR.glsllib"
+#import "Common/ShaderLib/Parallax.glsllib"
+#import "Common/ShaderLib/Lighting.glsllib"
+#import "Common/MatDefs/Terrain/AfflictionLib.glsllib"
+#import "Common/ShaderLib/Deferred.glsllib"
+
+// shading model
+#import "Common/ShaderLib/ShadingModel.glsllib"
+// octahedral
+#import "Common/ShaderLib/Octahedral.glsllib"
+
+varying vec3 wPosition;
+varying vec3 vNormal;
+varying vec2 texCoord;
+uniform vec3 g_CameraPosition;
+varying vec3 vPosition;
+varying vec3 vnPosition;
+varying vec3 vViewDir;
+varying vec4 vLightDir;
+varying vec4 vnLightDir;
+varying vec3 lightVec;
+varying vec3 inNormal;
+varying vec3 wNormal;
+
+#ifdef DEBUG_VALUES_MODE
+ uniform int m_DebugValuesMode;
+#endif
+
+#ifdef TRI_PLANAR_MAPPING
+ varying vec4 wVertex;
+#endif
+
+//texture-slot params for 12 unique texture slots (0-11) :
+#for i=0..12 ( $0 )
+ uniform int m_AfflictionMode_$i;
+ uniform float m_Roughness_$i;
+ uniform float m_Metallic_$i;
+
+ #ifdef ALBEDOMAP_$i
+ uniform sampler2D m_AlbedoMap_$i;
+ #endif
+ #ifdef ALBEDOMAP_$i_SCALE
+ uniform float m_AlbedoMap_$i_scale;
+ #endif
+ #ifdef NORMALMAP_$i
+ uniform sampler2D m_NormalMap_$i;
+ #endif
+#endfor
+
+//3 alpha maps :
+#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 DISCARD_ALPHA
+ uniform float m_AlphaDiscardThreshold;
+#endif
+
+//fog vars for basic fog :
+#ifdef USE_FOG
+#import "Common/ShaderLib/MaterialFog.glsllib"
+ uniform vec4 m_FogColor;
+ float fogDistance;
+
+ uniform vec2 m_LinearFog;
+#endif
+#ifdef FOG_EXP
+ uniform float m_ExpFog;
+#endif
+#ifdef FOG_EXPSQ
+ uniform float m_ExpSqFog;
+#endif
+
+//sun intensity is a secondary AO value that can be painted per-vertex in the red channel of the
+// vertex colors, or it can be set as a static value for an entire material with the StaticSunIntensity float param
+#if defined(USE_VERTEX_COLORS_AS_SUN_INTENSITY)
+ varying vec4 vertColors;
+#endif
+
+#ifdef STATIC_SUN_INTENSITY
+ uniform float m_StaticSunIntensity;
+#endif
+//sun intensity AO value is only applied to the directional light, not to point lights, so it is important to track if the
+//sun is more/less bright than the brightest point light for each fragment to determine how the light probe's ambient light should be scaled later on in light calculation code
+float brightestPointLight = 0.0;
+
+//optional affliction paramaters that use the AfflictionAlphaMap's green channel for splatting m_SplatAlbedoMap and the red channel for splatting desaturation :
+#ifdef AFFLICTIONTEXTURE
+ uniform sampler2D m_AfflictionAlphaMap;
+#endif
+#ifdef USE_SPLAT_NOISE
+ uniform float m_SplatNoiseVar;
+#endif
+//only defined for non-terrain geoemtries and terrains that are not positioned nor sized in correlation to the 2d array of AfflictionAlphaMaps used for splatting accross large tile based scenes in a grid
+#ifdef TILELOCATION
+ uniform float m_TileWidth;
+ uniform vec3 m_TileLocation;
+#endif
+#ifdef AFFLICTIONALBEDOMAP
+ uniform sampler2D m_SplatAlbedoMap;
+#endif
+#ifdef AFFLICTIONNORMALMAP
+ uniform sampler2D m_SplatNormalMap;
+#endif
+#ifdef AFFLICTIONROUGHNESSMETALLICMAP
+ uniform sampler2D m_SplatRoughnessMetallicMap;
+#endif
+#ifdef AFFLICTIONEMISSIVEMAP
+ uniform sampler2D m_SplatEmissiveMap;
+#endif
+
+uniform int m_AfflictionSplatScale;
+uniform float m_AfflictionRoughnessValue;
+uniform float m_AfflictionMetallicValue;
+uniform float m_AfflictionEmissiveValue;
+uniform vec4 m_AfflictionEmissiveColor;
+
+vec4 afflictionVector;
+float noiseHash;
+float livelinessValue;
+float afflictionValue;
+int afflictionMode = 1;
+
+//general temp vars :
+vec4 tempAlbedo, tempNormal, tempEmissiveColor;
+float tempParallax, tempMetallic, tempRoughness, tempAo, tempEmissiveIntensity;
+
+vec3 viewDir;
+vec2 coord;
+vec4 albedo = vec4(1.0);
+vec3 normal = vec3(0.5,0.5,1);
+vec3 norm;
+float Metallic;
+float Roughness;
+float packedAoValue = 1.0;
+vec4 emissive;
+float emissiveIntensity = 1.0;
+float indoorSunLightExposure = 1.0;
+
+vec4 packedMetallicRoughnessAoEiVec;
+vec4 packedNormalParallaxVec;
+
+void main(){
+
+ #ifdef USE_FOG
+ fogDistance = distance(g_CameraPosition, wPosition.xyz);
+ #endif
+
+ indoorSunLightExposure = 1.0;
+
+ viewDir = normalize(g_CameraPosition - wPosition);
+
+ norm = normalize(wNormal);
+ normal = norm;
+
+ afflictionVector = vec4(1.0, 0.0, 1.0, 0.0); //r channel is sturation, g channel is affliction splat texture intensity, b and a unused (might use b channel for wetness eventually)
+
+ #ifdef AFFLICTIONTEXTURE
+
+ #ifdef TILELOCATION
+ //subterrains that are not centred in tile or equal to tile width in total size need to have m_TileWidth pre-set. (tileWidth is the x,z dimesnions that the AfflictionAlphaMap represents)
+ vec2 tileCoords;
+ float xPos, zPos;
+
+ vec3 locInTile = (wPosition - m_TileLocation);
+
+ locInTile += vec3(m_TileWidth/2, 0, m_TileWidth/2);
+
+ xPos = (locInTile.x / m_TileWidth);
+ zPos = 1 - (locInTile.z / m_TileWidth);
+
+ tileCoords = vec2(xPos, zPos);
+
+ afflictionVector = texture2D(m_AfflictionAlphaMap, tileCoords).rgba;
+ #else
+ // ..othrewise when terrain size matches tileWidth and location matches tileLocation, the terrain's texCoords can be used for simple texel fetching of the AfflictionAlphaMap
+ afflictionVector = texture2D(m_AfflictionAlphaMap, texCoord.xy).rgba;
+ #endif
+ #endif
+
+ livelinessValue = afflictionVector.r;
+ afflictionValue = afflictionVector.g;
+
+ #ifdef ALBEDOMAP_0
+ #ifdef ALPHAMAP
+
+ vec4 alphaBlend;
+ vec4 alphaBlend_0, alphaBlend_1, alphaBlend_2;
+ int texChannelForAlphaBlending;
+
+ alphaBlend_0 = texture2D( m_AlphaMap, texCoord.xy );
+
+ #ifdef ALPHAMAP_1
+ alphaBlend_1 = texture2D( m_AlphaMap_1, texCoord.xy );
+ #endif
+ #ifdef ALPHAMAP_2
+ alphaBlend_2 = texture2D( m_AlphaMap_2, texCoord.xy );
+ #endif
+
+ vec2 texSlotCoords;
+
+ float finalAlphaBlendForLayer = 1.0;
+
+ vec3 blending = abs( norm );
+ 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);
+
+ #for i=0..12 (#ifdef ALBEDOMAP_$i $0 #endif)
+
+ //assign texture slot's blending from index's correct alpha map
+ if($i <= 3){
+ alphaBlend = alphaBlend_0;
+ }else if($i <= 7){
+ alphaBlend = alphaBlend_1;
+ }else if($i <= 11){
+ alphaBlend = alphaBlend_2;
+ }
+
+ texChannelForAlphaBlending = int(mod($i, 4.0)); //pick the correct channel (r g b or a) based on the layer's index
+ switch(texChannelForAlphaBlending) {
+ case 0:
+ finalAlphaBlendForLayer = alphaBlend.r;
+ break;
+ case 1:
+ finalAlphaBlendForLayer = alphaBlend.g;
+ break;
+ case 2:
+ finalAlphaBlendForLayer = alphaBlend.b;
+ break;
+ case 3:
+ finalAlphaBlendForLayer = alphaBlend.a;
+ break;
+ }
+
+ afflictionMode = m_AfflictionMode_$i;
+
+ #ifdef TRI_PLANAR_MAPPING
+ //tri planar
+ tempAlbedo = getTriPlanarBlend(wVertex, blending, m_AlbedoMap_$i, m_AlbedoMap_$i_scale);
+
+ #ifdef NORMALMAP_$i
+ tempNormal.rgb = getTriPlanarBlend(wVertex, blending, m_NormalMap_$i, m_AlbedoMap_$i_scale).rgb;
+ tempNormal.rgb = calculateTangentsAndApplyToNormals(tempNormal.rgb, wNormal);// this gets rid of the need for pre-generating tangents for TerrainPatches, since doing so doesn't seem to work (tbnMat is always blank for terrains even with tangents pre-generated, not sure why...)
+ #else
+ tempNormal.rgb = wNormal.rgb;
+ #endif
+ #else
+
+ // non triplanar
+ texSlotCoords = texCoord * m_AlbedoMap_$i_scale;
+
+ tempAlbedo.rgb = texture2D(m_AlbedoMap_$i, texSlotCoords).rgb;
+ #ifdef NORMALMAP_$i
+ tempNormal.xyz = texture2D(m_NormalMap_$i, texSlotCoords).xyz;
+ tempNormal.rgb = calculateTangentsAndApplyToNormals(tempNormal.rgb, wNormal);
+ #else
+ tempNormal.rgb = wNormal.rgb;
+ #endif
+ #endif
+
+ //note: most of these functions can be found in AfflictionLib.glslib
+ tempAlbedo.rgb = alterLiveliness(tempAlbedo.rgb, livelinessValue, afflictionMode); //changes saturation of albedo for this layer; does nothing if not using AfflictionAlphaMap for affliction splatting
+
+ //mix values from this index layer to final output values based on finalAlphaBlendForLayer
+ albedo.rgb = mix(albedo.rgb, tempAlbedo.rgb , finalAlphaBlendForLayer);
+ normal.rgb = mix(normal.rgb, tempNormal.rgb, finalAlphaBlendForLayer);
+ Metallic = mix(Metallic, m_Metallic_$i, finalAlphaBlendForLayer);
+ Roughness = mix(Roughness, m_Roughness_$i, finalAlphaBlendForLayer);
+
+ #endfor
+ #endif
+ #endif
+
+
+ float alpha = albedo.a;
+ #ifdef DISCARD_ALPHA
+ if(alpha < m_AlphaDiscardThreshold){
+ discard;
+ }
+ #endif
+
+
+ //APPLY AFFLICTIONN TO THE PIXEL
+ #ifdef AFFLICTIONTEXTURE
+ vec4 afflictionAlbedo;
+
+ float newAfflictionScale = m_AfflictionSplatScale;
+ vec2 newScaledCoords;
+
+ #ifdef AFFLICTIONALBEDOMAP
+ #ifdef TRI_PLANAR_MAPPING
+ newAfflictionScale = newAfflictionScale / 256;
+ afflictionAlbedo = getTriPlanarBlend(wVertex, blending, m_SplatAlbedoMap , newAfflictionScale);
+ #else
+ newScaledCoords = mod(wPosition.xz / m_AfflictionSplatScale, 0.985);
+ afflictionAlbedo = texture2D(m_SplatAlbedoMap , newScaledCoords);
+ #endif
+
+ #else
+ afflictionAlbedo = vec4(1.0, 1.0, 1.0, 1.0);
+ #endif
+
+ vec3 afflictionNormal;
+ #ifdef AFFLICTIONNORMALMAP
+ #ifdef TRI_PLANAR_MAPPING
+
+ afflictionNormal = getTriPlanarBlend(wVertex, blending, m_SplatNormalMap , newAfflictionScale).rgb;
+
+ #else
+ afflictionNormal = texture2D(m_SplatNormalMap , newScaledCoords).rgb;
+ #endif
+
+ #else
+ afflictionNormal = norm;
+
+ #endif
+ float afflictionMetallic = m_AfflictionMetallicValue;
+ float afflictionRoughness = m_AfflictionRoughnessValue;
+ float afflictionAo = 1.0;
+
+
+ vec4 afflictionEmissive = m_AfflictionEmissiveColor;
+ float afflictionEmissiveIntensity = m_AfflictionEmissiveValue;
+
+
+ #ifdef AFFLICTIONROUGHNESSMETALLICMAP
+ vec4 metallicRoughnessAoEiVec = texture2D(m_SplatRoughnessMetallicMap, newScaledCoords);
+ afflictionRoughness *= metallicRoughnessAoEiVec.g;
+ afflictionMetallic *= metallicRoughnessAoEiVec.b;
+ afflictionAo = metallicRoughnessAoEiVec.r;
+ afflictionEmissiveIntensity *= metallicRoughnessAoEiVec.a; //important not to leave this channel all black by accident when creating the mraoei map if using affliction emissiveness
+
+ #endif
+
+ #ifdef AFFLICTIONEMISSIVEMAP
+ vec4 emissiveMapColor = texture2D(m_SplatEmissiveMap, newScaledCoords);
+ afflictionEmissive *= emissiveMapColor;
+ #endif
+
+ float adjustedAfflictionValue = afflictionValue;
+ #ifdef USE_SPLAT_NOISE
+ noiseHash = getStaticNoiseVar0(wPosition, afflictionValue * m_SplatNoiseVar);
+
+ adjustedAfflictionValue = getAdjustedAfflictionVar(afflictionValue);
+ if(afflictionValue >= 0.99){
+ adjustedAfflictionValue = afflictionValue;
+ }
+ #else
+ noiseHash = 1.0;
+ #endif
+
+ Roughness = alterAfflictionRoughness(adjustedAfflictionValue, Roughness, afflictionRoughness, noiseHash);
+ Metallic = alterAfflictionMetallic(adjustedAfflictionValue, Metallic, afflictionMetallic, noiseHash);
+ albedo = alterAfflictionColor(adjustedAfflictionValue, albedo, afflictionAlbedo, noiseHash );
+ normal = alterAfflictionNormalsForTerrain(adjustedAfflictionValue, normal, afflictionNormal, noiseHash , wNormal);
+ emissive = alterAfflictionGlow(adjustedAfflictionValue, emissive, afflictionEmissive, noiseHash);
+ emissiveIntensity = alterAfflictionEmissiveIntensity(adjustedAfflictionValue, emissiveIntensity, afflictionEmissiveIntensity, noiseHash);
+ emissiveIntensity *= afflictionEmissive.a;
+ //affliction ao value blended below after specular calculation
+ #endif
+
+// spec gloss pipeline code would go here if supported, but likely will not be for terrain shaders as defines are limited and heavily used
+
+float specular = 0.5;
+float nonMetalSpec = 0.08 * specular;
+vec4 specularColor = (nonMetalSpec - nonMetalSpec * Metallic) + albedo * Metallic;
+vec4 diffuseColor = albedo - albedo * Metallic;
+vec3 fZero = vec3(specular);
+
+//simple ao calculation, no support for lightmaps like stock pbr shader.. (probably could add lightmap support with another texture array, but
+// that would add another texture read per slot and require removing 12 other defines to make room...)
+ vec3 ao = vec3(packedAoValue);
+
+ #ifdef AFFLICTIONTEXTURE
+ ao = alterAfflictionAo(afflictionValue, ao, vec3(afflictionAo), noiseHash); // alter the AO map for affliction values
+ #endif
+ ao.rgb = ao.rrr;
+ specularColor.rgb *= ao;
+
+ #ifdef STATIC_SUN_INTENSITY
+ indoorSunLightExposure = m_StaticSunIntensity; //single float value to indicate percentage of
+ //sunlight hitting the model (only works for small models or models with 100% consistent sunlighting accross every pixel)
+ #endif
+ #ifdef USE_VERTEX_COLORS_AS_SUN_INTENSITY
+ indoorSunLightExposure = vertColors.r * indoorSunLightExposure; //use R channel of vertexColors for..
+ #endif
+ // similar purpose as above...
+ //but uses r channel vert colors like an AO map specifically
+ //for sunlight (solution for scaling lighting for indoor
+ // and shadey/dimly lit models, especially big ones that
+ // span accross varying directionalLight exposure)
+ brightestPointLight = 0.0;
+
+
+ // pack
+ vec2 n1 = octEncode(normal);
+ vec2 n2 = octEncode(norm);
+ Context_OutGBuff3.xy = n1;
+ Context_OutGBuff3.zw = n2;
+ Context_OutGBuff0.rgb = floor(diffuseColor.rgb * 100.0f) + ao * 0.1f;
+ Context_OutGBuff1.rgb = floor(specularColor.rgb * 100.0f) + fZero * 0.1f;
+ Context_OutGBuff1.a = Roughness;
+ Context_OutGBuff0.a = alpha;
+
+
+
+
+ float minVertLighting;
+ #ifdef BRIGHTEN_INDOOR_SHADOWS
+ minVertLighting = 0.0833; //brighten shadows so that caves which are naturally covered from the DL shadows are not way too dark compared to when shadows are off (mostly only necessary for naturally dark scenes, or dark areas when using the sun intensity code above)
+ #else
+ minVertLighting = 0.0533;
+
+ #endif
+
+ indoorSunLightExposure = max(indoorSunLightExposure, brightestPointLight);
+ indoorSunLightExposure = max(indoorSunLightExposure, minVertLighting); //scale the indoorSunLightExposure back up to account for the brightest point light nearby before scaling light probes by this value below
+
+ // shading model id
+ Context_OutGBuff2.a = STANDARD_LIGHTING + indoorSunLightExposure * 0.01f;
+
+ if(emissive.a > 0){
+ emissive = emissive * pow(emissive.a * 5, emissiveIntensity) * emissiveIntensity * 20 * emissive.a;
+ }
+ Context_OutGBuff2.rgb = emissive.rgb;
+}
diff --git a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/PBRTerrain.j3md b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/PBRTerrain.j3md
index 572bf8ef49..0f36c14c8a 100644
--- a/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/PBRTerrain.j3md
+++ b/jme3-terrain/src/main/resources/Common/MatDefs/Terrain/PBRTerrain.j3md
@@ -317,6 +317,97 @@ MaterialDef PBR Terrain {
}
}
+ Technique GBufferPass{
+
+ Pipeline Deferred
+
+ VertexShader GLSL300 GLSL150 GLSL130 GLSL100: Common/MatDefs/Terrain/PBRTerrain.vert
+ FragmentShader GLSL300 GLSL150 GLSL130 GLSL100: Common/MatDefs/Terrain/GBufferPack/PBRTerrainGBufferPack.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ CameraPosition
+ WorldMatrix
+ WorldNormalMatrix
+ ViewProjectionMatrix
+ ViewMatrix
+ Time
+
+ }
+
+ Defines {
+ BOUND_DRAW_BUFFER: BoundDrawBuffer
+
+ TILELOCATION : TileLocation
+ AFFLICTIONTEXTURE : AfflictionAlphaMap
+
+ AFFLICTIONALBEDOMAP: SplatAlbedoMap
+ AFFLICTIONNORMALMAP : SplatNormalMap
+ AFFLICTIONROUGHNESSMETALLICMAP : SplatRoughnessMetallicMap
+ AFFLICTIONEMISSIVEMAP : SplatEmissiveMap
+
+ USE_SPLAT_NOISE : SplatNoiseVar
+
+
+ USE_VERTEX_COLORS_AS_SUN_INTENSITY : UseVertexColorsAsSunIntensity
+ STATIC_SUN_INTENSITY : StaticSunIntensity
+ BRIGHTEN_INDOOR_SHADOWS : BrightenIndoorShadows
+
+ DISCARD_ALPHA : AlphaDiscardThreshold
+
+ USE_FOG : UseFog
+ FOG_LINEAR : LinearFog
+ FOG_EXP : ExpFog
+ FOG_EXPSQ : ExpSqFog
+
+ TRI_PLANAR_MAPPING : useTriPlanarMapping
+
+ ALBEDOMAP_0 : AlbedoMap_0
+ ALBEDOMAP_1 : AlbedoMap_1
+ ALBEDOMAP_2 : AlbedoMap_2
+ ALBEDOMAP_3 : AlbedoMap_3
+ ALBEDOMAP_4 : AlbedoMap_4
+ ALBEDOMAP_5 : AlbedoMap_5
+ ALBEDOMAP_6 : AlbedoMap_6
+ ALBEDOMAP_7 : AlbedoMap_7
+ ALBEDOMAP_8 : AlbedoMap_8
+ ALBEDOMAP_9 : AlbedoMap_9
+ ALBEDOMAP_10 : AlbedoMap_10
+ ALBEDOMAP_11 : AlbedoMap_11
+
+ NORMALMAP_0 : NormalMap_0
+ 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
+
+ ALPHAMAP : AlphaMap
+ ALPHAMAP_1 : AlphaMap_1
+ ALPHAMAP_2 : AlphaMap_2
+ ALBEDOMAP_0_SCALE : AlbedoMap_0_scale
+ ALBEDOMAP_1_SCALE : AlbedoMap_1_scale
+ ALBEDOMAP_2_SCALE : AlbedoMap_2_scale
+ ALBEDOMAP_3_SCALE : AlbedoMap_3_scale
+ ALBEDOMAP_4_SCALE : AlbedoMap_4_scale
+ ALBEDOMAP_5_SCALE : AlbedoMap_5_scale
+ ALBEDOMAP_6_SCALE : AlbedoMap_6_scale
+ ALBEDOMAP_7_SCALE : AlbedoMap_7_scale
+ ALBEDOMAP_8_SCALE : AlbedoMap_8_scale
+ ALBEDOMAP_9_SCALE : AlbedoMap_9_scale
+ ALBEDOMAP_10_SCALE : AlbedoMap_10_scale
+ ALBEDOMAP_11_SCALE : AlbedoMap_11_scale
+
+ DEBUG_VALUES_MODE : DebugValuesMode
+
+ }
+ }
Technique PreShadow {
From 0359a8e69d0074882f351cf127b30a3dfe9d3c8c Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Fri, 20 Oct 2023 11:06:49 +0800
Subject: [PATCH 020/111] jme3-core:Fixed Tile-basedDeferred light culling
issue, fixed some flickering problems, fixed attenuation issue with multiple
PBR lights under deferred rendering.
---
.../DeferredSinglePassLightingLogic.java | 20 ++++++++++++----
.../SkyLightAndReflectionProbeRender.java | 6 ++++-
...eBasedDeferredSinglePassLightingLogic.java | 13 ++++++----
.../java/com/jme3/renderer/RenderManager.java | 4 +++-
.../ShadingCommon/DeferredShading.frag | 3 ++-
.../TileBasedDeferredShading.frag | 24 +++++++++++--------
6 files changed, 49 insertions(+), 21 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java
index 8c4beecb78..79ed98e35a 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/DeferredSinglePassLightingLogic.java
@@ -77,6 +77,7 @@ public final class DeferredSinglePassLightingLogic extends DefaultTechniqueDefLo
private static final String DEFINE_DEFERRED_SINGLE_PASS_LIGHTING = "DEFERRED_SINGLE_PASS_LIGHTING";
private static final String DEFINE_NB_LIGHTS = "NB_LIGHTS";
private static final String DEFINE_USE_TEXTURE_PACK_MODE = "USE_TEXTURE_PACK_MODE";
+ private static final String DEFINE_USE_AMBIENT_LIGHT = "USE_AMBIENT_LIGHT";
private static final String DEFINE_PACK_NB_LIGHTS = "PACK_NB_LIGHTS";
private static final String DEFINE_NB_SKY_LIGHT_AND_REFLECTION_PROBES = "NB_SKY_LIGHT_AND_REFLECTION_PROBES";
private static final RenderState ADDITIVE_LIGHT = new RenderState();
@@ -91,6 +92,7 @@ public final class DeferredSinglePassLightingLogic extends DefaultTechniqueDefLo
private ImageRaster lightDataUpdateIO2;
private ImageRaster lightDataUpdateIO3;
private int lightNum;
+ private boolean useAmbientLight;
private final ColorRGBA ambientLightColor = new ColorRGBA(0, 0, 0, 1);
final private List skyLightAndReflectionProbes = new ArrayList<>(3);
@@ -105,6 +107,7 @@ public final class DeferredSinglePassLightingLogic extends DefaultTechniqueDefLo
private int packNbLightsDefineId;
private int packTextureModeDefineId;
private final int nbSkyLightAndReflectionProbesDefineId;
+ private final int useAmbientLightDefineId;
public DeferredSinglePassLightingLogic(TechniqueDef techniqueDef) {
super(techniqueDef);
@@ -118,6 +121,7 @@ public DeferredSinglePassLightingLogic(TechniqueDef techniqueDef) {
nbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_LIGHTS, VarType.Int);
}
nbSkyLightAndReflectionProbesDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_SKY_LIGHT_AND_REFLECTION_PROBES, VarType.Int);
+ useAmbientLightDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_USE_AMBIENT_LIGHT, VarType.Boolean);
}
private void cleanupLightData(){
@@ -132,6 +136,13 @@ private void cleanupLightData(){
}
}
+ /**
+ * Try reallocating textures to accommodate enough light data.
+ * Currently, a large amount of light information is stored in textures, divided into three texture1d,
+ * lightData1 stores lightColor (rgb stores lightColor, a stores lightType), lightData2 stores lightPosition +
+ * invRange/lightDir, lightData3 stores dir and spotAngleCos about SpotLight.
+ * @param lightNum By preallocating texture memory for the known number of lights, dynamic reallocation at runtime can be prevented.
+ */
private void prepareLightData(int lightNum){
this.lightNum = lightNum;
// 1d texture
@@ -181,8 +192,9 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager
//Though the second pass should not render IBL as it is taken care of on first pass like ambient light in phong lighting.
//We cannot change the define between passes and the old technique, and for some reason the code fails on mac (renders nothing).
if(lights != null) {
- SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, false);
+ useAmbientLight = SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, false);
defines.set(nbSkyLightAndReflectionProbesDefineId, skyLightAndReflectionProbes.size());
+ defines.set(useAmbientLightDefineId, useAmbientLight);
}
return super.makeCurrent(assetManager, renderManager, rendererCaps, lights, defines);
}
@@ -222,7 +234,7 @@ protected int updateLightListPackToTexture(Shader shader, Geometry g, LightList
ambientColor.setValue(VarType.Vector4, ColorRGBA.Black);
} else {
// extractSkyLightAndReflectionProbes(lightList,true);
- ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, true, ambientLightColor));
+ ambientColor.setValue(VarType.Vector4, ambientLightColor);
}
// render skyLights and reflectionProbes
@@ -381,7 +393,7 @@ protected int updateLightListUniforms(Shader shader, Geometry g, LightList light
rm.getRenderer().applyRenderState(ADDITIVE_LIGHT);
ambientColor.setValue(VarType.Vector4, ColorRGBA.Black);
} else {
- ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, true, ambientLightColor));
+ ambientColor.setValue(VarType.Vector4, ambientLightColor);
}
int lightDataIndex = 0;
@@ -480,7 +492,7 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry
prepareLightData(renderManager.getCurMaxDeferredShadingLightNum());
}
// todo:Currently, this texturePackMode is only suitable for scenes where there are a large number of light sources per frame. The number of light sources is submitted to the texture all at once, so lightNum can be pre-allocated, but light source information can also be submitted to the texture all at once here, and then drawn in multiple passes (drawing each time by the specified singlePassLightBatchSize)
- SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, true);
+ useAmbientLight = SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, true);
int count = lights.size();
// FIXME:Setting uniform variables this way will take effect immediately in the current frame, however lightData is set through geometry.getMaterial().setTexture(XXX) which will take effect next frame, so here I changed to use geometry.getMaterial().setParam() uniformly to update all parameters, to keep the frequency consistent.
// Uniform lightCount = shader.getUniform("g_LightCount");
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/SkyLightAndReflectionProbeRender.java b/jme3-core/src/main/java/com/jme3/material/logic/SkyLightAndReflectionProbeRender.java
index 9ba78a20e1..c51f30918d 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/SkyLightAndReflectionProbeRender.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/SkyLightAndReflectionProbeRender.java
@@ -90,14 +90,17 @@ public static int setSkyLightAndReflectionProbeData(RenderManager rm, int lastTe
* @param ambientLightColor
* @param skyLightAndReflectionProbes
* @param removeLights
+ * @return hasAmbientLight
*/
- public static void extractSkyLightAndReflectionProbes(LightList lightList, ColorRGBA ambientLightColor, List skyLightAndReflectionProbes, boolean removeLights) {
+ public static boolean extractSkyLightAndReflectionProbes(LightList lightList, ColorRGBA ambientLightColor, List skyLightAndReflectionProbes, boolean removeLights) {
ambientLightColor.set(0, 0, 0, 1);
+ boolean hasAmbientLight = false;
skyLightAndReflectionProbes.clear();
for (int j = 0; j < lightList.size(); j++) {
Light l = lightList.get(j);
if (l instanceof AmbientLight) {
ambientLightColor.addLocal(l.getColor());
+ hasAmbientLight = true;
if(removeLights){
lightList.remove(j);
j--;
@@ -116,6 +119,7 @@ public static void extractSkyLightAndReflectionProbes(LightList lightList, Color
}
ambientLightColor.a = 1.0f;
+ return hasAmbientLight;
}
}
diff --git a/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java b/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
index 90b41d86ae..a12aab6cec 100644
--- a/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
+++ b/jme3-core/src/main/java/com/jme3/material/logic/TileBasedDeferredSinglePassLightingLogic.java
@@ -79,6 +79,7 @@ public class TileBasedDeferredSinglePassLightingLogic extends DefaultTechniqueDe
private final static String _S_TILE_HEIGHT = "g_HeightTile";
private static final String DEFINE_TILE_BASED_DEFERRED_SINGLE_PASS_LIGHTING = "TILE_BASED_DEFERRED_SINGLE_PASS_LIGHTING";
private static final String DEFINE_NB_LIGHTS = "NB_LIGHTS";
+ private static final String DEFINE_USE_AMBIENT_LIGHT = "USE_AMBIENT_LIGHT";
private static final String DEFINE_USE_TEXTURE_PACK_MODE = "USE_TEXTURE_PACK_MODE";
private static final String DEFINE_PACK_NB_LIGHTS = "PACK_NB_LIGHTS";
private static final String DEFINE_NB_SKY_LIGHT_AND_REFLECTION_PROBES = "NB_SKY_LIGHT_AND_REFLECTION_PROBES";
@@ -100,6 +101,7 @@ public class TileBasedDeferredSinglePassLightingLogic extends DefaultTechniqueDe
private ImageRaster lightDataUpdateIO2;
private ImageRaster lightDataUpdateIO3;
private int lightNum;
+ private boolean useAmbientLight;
private final ColorRGBA ambientLightColor = new ColorRGBA(0, 0, 0, 1);
final private List skyLightAndReflectionProbes = new ArrayList<>(3);
@@ -114,6 +116,7 @@ public class TileBasedDeferredSinglePassLightingLogic extends DefaultTechniqueDe
private int packNbLightsDefineId;
private int packTextureModeDefineId;
private final int nbSkyLightAndReflectionProbesDefineId;
+ private final int useAmbientLightDefineId;
@@ -577,6 +580,7 @@ public TileBasedDeferredSinglePassLightingLogic(TechniqueDef techniqueDef) {
nbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_LIGHTS, VarType.Int);
}
nbSkyLightAndReflectionProbesDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_SKY_LIGHT_AND_REFLECTION_PROBES, VarType.Int);
+ useAmbientLightDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_USE_AMBIENT_LIGHT, VarType.Boolean);
}
private void cleanupLightData(){
@@ -661,8 +665,9 @@ public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager
//Though the second pass should not render IBL as it is taken care of on first pass like ambient light in phong lighting.
//We cannot change the define between passes and the old technique, and for some reason the code fails on mac (renders nothing).
if(lights != null) {
- SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, false);
+ useAmbientLight = SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, false);
defines.set(nbSkyLightAndReflectionProbesDefineId, skyLightAndReflectionProbes.size());
+ defines.set(useAmbientLightDefineId, useAmbientLight);
}
return super.makeCurrent(assetManager, renderManager, rendererCaps, lights, defines);
}
@@ -700,7 +705,7 @@ protected int updateLightListPackToTexture(Shader shader, Geometry g, LightList
rm.getRenderer().applyRenderState(ADDITIVE_LIGHT);
ambientColor.setValue(VarType.Vector4, ColorRGBA.Black);
} else {
- ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, true, ambientLightColor));
+ ambientColor.setValue(VarType.Vector4, ambientLightColor);
}
// render skyLights and reflectionProbes
@@ -859,7 +864,7 @@ protected int updateLightListUniforms(Shader shader, Geometry g, LightList light
rm.getRenderer().applyRenderState(ADDITIVE_LIGHT);
ambientColor.setValue(VarType.Vector4, ColorRGBA.Black);
} else {
- ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList, true, ambientLightColor));
+ ambientColor.setValue(VarType.Vector4, ambientLightColor);
}
int lightDataIndex = 0;
@@ -944,7 +949,7 @@ public void render(RenderManager renderManager, Shader shader, Geometry geometry
cleanupLightData();
prepareLightData(renderManager.getCurMaxDeferredShadingLightNum());
}
- SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, true);
+ useAmbientLight = SkyLightAndReflectionProbeRender.extractSkyLightAndReflectionProbes(lights, ambientLightColor, skyLightAndReflectionProbes, true);
int count = lights.size();
// FIXME:Setting uniform variables this way will take effect immediately in the current frame, however lightData is set through geometry.getMaterial().setTexture(XXX) which will take effect next frame, so here I changed to use geometry.getMaterial().setParam() uniformly to update all parameters, to keep the frequency consistent.
// Uniform lightCount = shader.getUniform("g_LightCount");
diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
index f2f373d52e..89d394bb85 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
@@ -88,7 +88,8 @@ public class RenderManager {
private int curMaxDeferredShadingLightNum = 1024;
// TileInfo
private TileBasedDeferredSinglePassLightingLogic.TileInfo tileInfo;
- private int forceTileSize = 0;
+ // Based on your current resolution and total light source count, try adjusting the tileSize - it must be a power of 2 such as 32, 64, 128 etc.
+ private int forceTileSize = 64;
// If ForceTileSize is not specified, curTileSize is calculated each frame by dividing viewport horizontal width by NumberTileDivisions.
private int curTileSize = -1;
private int numberTileDivisions = 4;
@@ -195,6 +196,7 @@ public int getNumberTileDivisions() {
/**
* Tile-based DeferredShading divides the screen into multiple tiles, then assigns lights to corresponding tiles for rendering. In theory, the number of tiles should be set as powers of 2, such as 32, 64 etc, but it can be set larger depending on usage.
* 0 means auto calculate, then the number of tiles per frame is dynamically calculated based on NumberTileDivisions and current viewport width.
+ * Based on your current resolution and total light source count, try adjusting the tileSize - it must be a power of 2 such as 32, 64, 128 etc.
* @param forceTileSize
*/
public void setForceTileSize(int forceTileSize) {
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag
index 21e0588780..a8e7b3eb84 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.frag
@@ -9,6 +9,7 @@
// octahedral
#import "Common/ShaderLib/Octahedral.glsllib"
// skyLight and reflectionProbe
+uniform vec4 g_AmbientLightColor;
#import "Common/ShaderLib/SkyLightReflectionProbe.glsllib"
#if defined(USE_LIGHTS_CULL_MODE)
uniform vec2 g_ResolutionInverse;
@@ -19,7 +20,6 @@
varying mat4 viewProjectionMatrixInverse;
uniform mat4 g_ViewMatrix;
uniform vec3 g_CameraPosition;
-uniform vec4 g_AmbientLightColor;
uniform int m_NBLight;
#if defined(USE_TEXTURE_PACK_MODE)
@@ -178,6 +178,7 @@ void main(){
#if __VERSION__ >= 110
}
#endif
+ spotFallOff *= lightDir.w;
#ifdef NORMALMAP
//Normal map -> lighting is computed in tangent space
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
index a1a8a60772..9cf1bd9b3c 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
@@ -9,6 +9,7 @@
// octahedral
#import "Common/ShaderLib/Octahedral.glsllib"
// skyLight and reflectionProbe
+uniform vec4 g_AmbientLightColor;
#import "Common/ShaderLib/SkyLightReflectionProbe.glsllib"
#if defined(USE_LIGHTS_CULL_MODE)
uniform vec2 g_ResolutionInverse;
@@ -19,7 +20,6 @@
varying mat4 viewProjectionMatrixInverse;
uniform mat4 g_ViewMatrix;
uniform vec3 g_CameraPosition;
-uniform vec4 g_AmbientLightColor;
uniform int m_NBLight;
@@ -256,8 +256,10 @@ void main(){
#endif
gl_FragColor.rgb = vec3(0.0);
// Tile Based Shading
+ // get the grid data index
+ vec2 gridIndex = vec2(((innerTexCoord.x*g_Resolution.x) / float(g_TileSize)) / float(g_WidthTile), ((innerTexCoord.y*g_Resolution.y) / float(g_TileSize)) / float(g_HeightTile));
// get tile info
- vec3 tile = texture2D(m_TileLightDecode, innerTexCoord).xyz;
+ vec3 tile = texture2D(m_TileLightDecode, gridIndex).xyz;
int uoffset = int(tile.x);
int voffset = int(tile.z);
int count = int(tile.y);
@@ -273,11 +275,12 @@ void main(){
temp = float(uoffset + i);
offset = 0;
- if (temp >= g_TileLightOffsetSize){
- temp -= g_TileLightOffsetSize;
- offset++;
+ if(temp >= g_TileLightOffsetSize){
+ //temp -= g_TileLightOffsetSize;
+ offset += int(temp / float(g_TileLightOffsetSize));
+ temp = float(int(temp) % g_TileLightOffsetSize);
}
- if (temp == g_TileLightOffsetSize){
+ if(temp == g_TileLightOffsetSize){
temp = 0.0f;
}
@@ -301,17 +304,18 @@ void main(){
#if __VERSION__ >= 110
// allow use of control flow
if(lightColor.w > 1.0){
- #endif
+ #endif
#if defined(USE_TEXTURE_PACK_MODE)
spotFallOff = computeSpotFalloff(texture2D(m_LightPackData3, lightDataUV), lightVec);
#else
spotFallOff = computeSpotFalloff(g_LightData[lightId*3+2], lightVec);
#endif
- #if __VERSION__ >= 110
+ #if __VERSION__ >= 110
}
- #endif
+ #endif
+ spotFallOff *= lightDir.w;
- #ifdef NORMALMAP
+ #ifdef NORMALMAP
//Normal map -> lighting is computed in tangent space
lightDir.xyz = normalize(lightDir.xyz * tbnMat);
#else
From 98e0ae4e76a0198ca7451cb94f1c2a0087dbafbf Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Fri, 20 Oct 2023 11:09:00 +0800
Subject: [PATCH 021/111] jme3-examples:update TestCode
---
.../renderpath/TestPBRTerrainRenderPath.java | 430 ++++++++++++++++++
.../TestTileBasedDeferredShading.java | 6 +-
2 files changed, 435 insertions(+), 1 deletion(-)
create mode 100644 jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java
new file mode 100644
index 0000000000..9d393c7c3d
--- /dev/null
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java
@@ -0,0 +1,430 @@
+package jme3test.renderpath;
+
+/*
+ * Copyright (c) 2009-2021 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.
+ */
+import com.jme3.app.DetailedProfilerState;
+import com.jme3.app.SimpleApplication;
+import com.jme3.asset.TextureKey;
+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.LightProbe;
+import com.jme3.light.PointLight;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.ToneMapFilter;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.instancing.InstancedNode;
+import com.jme3.scene.shape.Sphere;
+import com.jme3.system.AppSettings;
+import com.jme3.terrain.geomipmap.TerrainLodControl;
+import com.jme3.terrain.geomipmap.TerrainQuad;
+import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;
+import com.jme3.terrain.heightmap.AbstractHeightMap;
+import com.jme3.terrain.heightmap.ImageBasedHeightMap;
+import com.jme3.texture.Texture;
+import com.jme3.texture.Texture.WrapMode;
+
+/**
+ * This test uses 'PBRTerrain.j3md' to create a terrain Material for PBR.
+ *
+ * Upon running the app, the user should see a mountainous, terrain-based
+ * landscape with some grassy areas, some snowy areas, and some tiled roads and
+ * gravel paths weaving between the valleys. Snow should be slightly
+ * shiny/reflective, and marble texture should be even shinier. If you would
+ * like to know what each texture is supposed to look like, you can find the
+ * textures used for this test case located in jme3-testdata. (Screenshots
+ * showing how this test-case should look will also be available soon so you can
+ * compare your results, and I will replace this comment with a link to their
+ * location as soon as they are posted.)
+ *
+ * Press 'p' to toggle tri-planar mode. Enabling tri-planar mode should prevent
+ * stretching of textures in steep areas of the terrain.
+ *
+ * Press 'n' to toggle between night and day. Pressing 'n' will cause the light
+ * to gradually fade darker/brighter until the min/max lighting levels are
+ * reached. At night the scene should be noticeably darker.
+ *
+ * Uses assets from CC0Textures.com, licensed under CC0 1.0 Universal. For more
+ * information on the textures this test case uses, view the license.txt file
+ * located in the jme3-testdata directory where these textures are located:
+ * jme3-testdata/src/main/resources/Textures/Terrain/PBR
+ *
+ *
+ * Notes: (as of 12 April 2021)
+ *
+ * -
+ * This shader is subject to the GLSL max limit of 16 textures, and users should
+ * consider using "AdvancedPBRTerrain.j3md" instead if they need additional
+ * texture slots.
+ *
+ *
+ *
+ * @author yaRnMcDonuts,johnKkk
+ */
+public class TestPBRTerrainRenderPath extends SimpleApplication {
+
+ private TerrainQuad terrain;
+ private Material matTerrain;
+ private boolean triPlanar = false;
+
+ private final int terrainSize = 512;
+ private final int patchSize = 256;
+ private final float dirtScale = 24;
+ private final float darkRockScale = 24;
+ private final float snowScale = 64;
+ private final float tileRoadScale = 64;
+ private final float grassScale = 24;
+ private final float marbleScale = 64;
+ private final float gravelScale = 64;
+
+ private AmbientLight ambientLight;
+ private DirectionalLight directionalLight;
+ private PointLight[] pointLights;
+ private boolean isNight = true;
+
+ private final float dayLightIntensity = 1.0f;
+ private final float nightLightIntensity = 0.03f;
+
+ private BitmapText keybindingsText;
+
+ private final float camMoveSpeed = 50f;
+
+ public static void main(String[] args) {
+ TestPBRTerrainRenderPath app = new TestPBRTerrainRenderPath();
+ AppSettings appSettings = new AppSettings(true);
+ appSettings.setWidth(1600);
+ appSettings.setHeight(900);
+// appSettings.setRenderer(AppSettings.LWJGL_OPENGL33);
+ app.start();
+ }
+
+ private final ActionListener actionListener = new ActionListener() {
+ @Override
+ public void onAction(String name, boolean pressed, float tpf) {
+ if (name.equals("triPlanar") && !pressed) {
+ triPlanar = !triPlanar;
+ if (triPlanar) {
+ matTerrain.setBoolean("useTriPlanarMapping", true);
+ // Tri-planar textures don't use the mesh's texture coordinates but real world coordinates,
+ // so we need to convert these texture coordinate scales into real world scales so it looks
+ // the same when we switch to/from tri-planar mode.
+ matTerrain.setFloat("AlbedoMap_0_scale", (dirtScale / terrainSize));
+ matTerrain.setFloat("AlbedoMap_1_scale", (darkRockScale / terrainSize));
+ matTerrain.setFloat("AlbedoMap_2_scale", (snowScale / terrainSize));
+ matTerrain.setFloat("AlbedoMap_3_scale", (tileRoadScale / terrainSize));
+ matTerrain.setFloat("AlbedoMap_4_scale", (grassScale / terrainSize));
+ matTerrain.setFloat("AlbedoMap_5_scale", (marbleScale / terrainSize));
+ matTerrain.setFloat("AlbedoMap_6_scale", (gravelScale / terrainSize));
+ } else {
+ matTerrain.setBoolean("useTriPlanarMapping", false);
+
+ matTerrain.setFloat("AlbedoMap_0_scale", dirtScale);
+ matTerrain.setFloat("AlbedoMap_1_scale", darkRockScale);
+ matTerrain.setFloat("AlbedoMap_2_scale", snowScale);
+ matTerrain.setFloat("AlbedoMap_3_scale", tileRoadScale);
+ matTerrain.setFloat("AlbedoMap_4_scale", grassScale);
+ matTerrain.setFloat("AlbedoMap_5_scale", marbleScale);
+ matTerrain.setFloat("AlbedoMap_6_scale", gravelScale);
+ }
+ }
+ if (name.equals("toggleNight") && !pressed) {
+ isNight = !isNight;
+ // Ambient and directional light are faded smoothly in update loop below.
+ }
+ }
+ };
+
+ @Override
+ public void simpleInitApp() {
+ // For this scene, use a tileSize=64 configuration (at 1600*900 resolution)
+ renderManager.setForceTileSize(64);// 1600 * 900 resolution config
+ setupKeys();
+ setUpTerrain();
+ setUpTerrainMaterial();
+ setUpLights();
+ setUpCamera();
+ FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
+ int numSamples = context.getSettings().getSamples();
+ if (numSamples > 0) {
+ fpp.setNumSamples(numSamples);
+ }
+
+// fpp.addFilter(new FXAAFilter());
+ fpp.addFilter(new ToneMapFilter(Vector3f.UNIT_XYZ.mult(1.0f)));
+// fpp.addFilter(new SSAOFilter(0.5f, 3, 0.2f, 0.2f));
+ viewPort.addProcessor(fpp);
+ }
+
+ private void setUpTerrainMaterial() {
+ // PBR terrain matdef
+ matTerrain = new Material(assetManager, "Common/MatDefs/Terrain/PBRTerrain.j3md");
+
+ matTerrain.setBoolean("useTriPlanarMapping", false);
+
+ // ALPHA map (for splat textures)
+ matTerrain.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alpha1.png"));
+ matTerrain.setTexture("AlphaMap_1", assetManager.loadTexture("Textures/Terrain/splat/alpha2.png"));
+ // this material also supports 'AlphaMap_2', so you can get up to 12 diffuse textures
+
+ // DIRT texture, Diffuse textures 0 to 3 use the first AlphaMap
+ Texture dirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png");
+ dirt.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("AlbedoMap_0", dirt);
+ matTerrain.setFloat("AlbedoMap_0_scale", dirtScale);
+ matTerrain.setFloat("Roughness_0", 1);
+ matTerrain.setFloat("Metallic_0", 0);
+ //matTerrain.setInt("AfflictionMode_0", 0);
+
+ // DARK ROCK texture
+ Texture darkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Color.png");
+ darkRock.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("AlbedoMap_1", darkRock);
+ matTerrain.setFloat("AlbedoMap_1_scale", darkRockScale);
+ matTerrain.setFloat("Roughness_1", 0.92f);
+ matTerrain.setFloat("Metallic_1", 0.02f);
+ //matTerrain.setInt("AfflictionMode_1", 0);
+
+ // SNOW texture
+ Texture snow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Color.png");
+ snow.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("AlbedoMap_2", snow);
+ matTerrain.setFloat("AlbedoMap_2_scale", snowScale);
+ matTerrain.setFloat("Roughness_2", 0.55f);
+ matTerrain.setFloat("Metallic_2", 0.12f);
+
+ Texture tiles = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Color.png");
+ tiles.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("AlbedoMap_3", tiles);
+ matTerrain.setFloat("AlbedoMap_3_scale", tileRoadScale);
+ matTerrain.setFloat("Roughness_3", 0.87f);
+ matTerrain.setFloat("Metallic_3", 0.08f);
+
+ // GRASS texture
+ Texture grass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Color.png");
+ grass.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("AlbedoMap_4", grass);
+ matTerrain.setFloat("AlbedoMap_4_scale", grassScale);
+ matTerrain.setFloat("Roughness_4", 1);
+ matTerrain.setFloat("Metallic_4", 0);
+
+ // MARBLE texture
+ Texture marble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Color.png");
+ marble.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("AlbedoMap_5", marble);
+ matTerrain.setFloat("AlbedoMap_5_scale", marbleScale);
+ matTerrain.setFloat("Roughness_5", 0.06f);
+ matTerrain.setFloat("Metallic_5", 0.8f);
+
+ // Gravel texture
+ Texture gravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Color.png");
+ gravel.setWrap(WrapMode.Repeat);
+ matTerrain.setTexture("AlbedoMap_6", gravel);
+ matTerrain.setFloat("AlbedoMap_6_scale", gravelScale);
+ matTerrain.setFloat("Roughness_6", 0.9f);
+ matTerrain.setFloat("Metallic_6", 0.07f);
+ // NORMAL MAPS
+ Texture normalMapDirt = assetManager.loadTexture("Textures/Terrain/PBR/Ground036_1K_Normal.png");
+ normalMapDirt.setWrap(WrapMode.Repeat);
+
+ Texture normalMapDarkRock = assetManager.loadTexture("Textures/Terrain/PBR/Rock035_1K_Normal.png");
+ normalMapDarkRock.setWrap(WrapMode.Repeat);
+
+ Texture normalMapSnow = assetManager.loadTexture("Textures/Terrain/PBR/Snow006_1K_Normal.png");
+ normalMapSnow.setWrap(WrapMode.Repeat);
+
+ Texture normalMapGravel = assetManager.loadTexture("Textures/Terrain/PBR/Gravel015_1K_Normal.png");
+ normalMapGravel.setWrap(WrapMode.Repeat);
+
+ Texture normalMapGrass = assetManager.loadTexture("Textures/Terrain/PBR/Ground037_1K_Normal.png");
+ normalMapGrass.setWrap(WrapMode.Repeat);
+
+// Texture normalMapMarble = assetManager.loadTexture("Textures/Terrain/PBR/Marble013_1K_Normal.png");
+// normalMapMarble.setWrap(WrapMode.Repeat);
+
+ Texture normalMapTiles = assetManager.loadTexture("Textures/Terrain/PBR/Tiles083_1K_Normal.png");
+ normalMapTiles.setWrap(WrapMode.Repeat);
+
+ matTerrain.setTexture("NormalMap_0", normalMapDirt);
+ matTerrain.setTexture("NormalMap_1", normalMapDarkRock);
+ matTerrain.setTexture("NormalMap_2", normalMapSnow);
+ matTerrain.setTexture("NormalMap_3", normalMapTiles);
+ matTerrain.setTexture("NormalMap_4", normalMapGrass);
+// matTerrain.setTexture("NormalMap_5", normalMapMarble); // Adding this texture would exceed the 16 texture limit.
+ matTerrain.setTexture("NormalMap_6", normalMapGravel);
+
+ terrain.setMaterial(matTerrain);
+ new RenderPathHelper(this, new Vector3f(0, cam.getHeight() / 2, 0), KeyInput.KEY_K, "K");
+ getStateManager().attach(new DetailedProfilerState());
+ }
+
+ private void setupKeys() {
+ flyCam.setMoveSpeed(50);
+ inputManager.addMapping("triPlanar", new KeyTrigger(KeyInput.KEY_P));
+ inputManager.addMapping("toggleNight", new KeyTrigger(KeyInput.KEY_N));
+
+ inputManager.addListener(actionListener, "triPlanar");
+ inputManager.addListener(actionListener, "toggleNight");
+
+ keybindingsText = new BitmapText(assetManager.loadFont("Interface/Fonts/Default.fnt"));
+ keybindingsText.setText("Press 'N' to toggle day/night fade (takes a moment) \nPress 'P' to toggle tri-planar mode");
+
+ getGuiNode().attachChild(keybindingsText);
+ keybindingsText.move(new Vector3f(200, 120, 0));
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+ super.simpleUpdate(tpf);
+
+ //smoothly transition from day to night
+ float currentLightIntensity = ambientLight.getColor().getRed();
+ float incrementPerFrame = tpf * 0.3f;
+
+ if (isNight) {
+ if (ambientLight.getColor().getRed() > nightLightIntensity) {
+ currentLightIntensity -= incrementPerFrame;
+ if (currentLightIntensity < nightLightIntensity) {
+ currentLightIntensity = nightLightIntensity;
+ }
+
+ ambientLight.getColor().set(currentLightIntensity, currentLightIntensity, currentLightIntensity, 1.0f);
+ directionalLight.getColor().set(currentLightIntensity, currentLightIntensity, currentLightIntensity, 1.0f);
+ }
+ } else {
+ if (ambientLight.getColor().getRed() < dayLightIntensity) {
+ currentLightIntensity += incrementPerFrame;
+ if (currentLightIntensity > dayLightIntensity) {
+ currentLightIntensity = dayLightIntensity;
+ }
+
+ ambientLight.getColor().set(currentLightIntensity, currentLightIntensity, currentLightIntensity, 1.0f);
+ directionalLight.getColor().set(currentLightIntensity, currentLightIntensity, currentLightIntensity, 1.0f);
+ }
+ }
+ }
+
+ private void setUpTerrain() {
+ // HEIGHTMAP image (for the terrain heightmap)
+ TextureKey hmKey = new TextureKey("Textures/Terrain/splat/mountains512.png", false);
+ Texture heightMapImage = assetManager.loadTexture(hmKey);
+
+ // CREATE HEIGHTMAP
+ AbstractHeightMap heightmap = null;
+ try {
+ heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.3f);
+ heightmap.load();
+ heightmap.smooth(0.9f, 1);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ terrain = new TerrainQuad("terrain", patchSize + 1, terrainSize + 1, heightmap.getHeightMap());
+//, new LodPerspectiveCalculatorFactory(getCamera(), 4)); // add this in to see it use entropy for LOD calculations
+ TerrainLodControl control = new TerrainLodControl(terrain, getCamera());
+ control.setLodCalculator(new DistanceLodCalculator(patchSize + 1, 2.7f)); // patch size, and a multiplier
+ terrain.addControl(control);
+ terrain.setMaterial(matTerrain);
+ terrain.setLocalTranslation(0, -100, 0);
+ terrain.setLocalScale(1f, 1f, 1f);
+ rootNode.attachChild(terrain);
+ }
+
+ private void setUpLights() {
+ LightProbe probe = (LightProbe) assetManager.loadAsset("Scenes/LightProbes/quarry_Probe.j3o");
+
+ probe.setAreaType(LightProbe.AreaType.Spherical);
+ probe.getArea().setRadius(2000);
+ probe.getArea().setCenter(new Vector3f(0, 0, 0));
+ rootNode.addLight(probe);
+
+ directionalLight = new DirectionalLight();
+ directionalLight.setDirection((new Vector3f(-0.3f, -0.5f, -0.3f)).normalize());
+ directionalLight.setColor(ColorRGBA.White);
+ rootNode.addLight(directionalLight);
+
+ ambientLight = new AmbientLight();
+ directionalLight.setColor(ColorRGBA.White);
+ rootNode.addLight(ambientLight);
+
+
+ // pointLights
+ int numPointLight = 1000;
+ ColorRGBA colors[] = new ColorRGBA[]{
+ ColorRGBA.White,
+ ColorRGBA.Red,
+ ColorRGBA.Blue,
+ ColorRGBA.Green,
+ ColorRGBA.Yellow,
+ ColorRGBA.Orange,
+ ColorRGBA.Brown,
+ };
+ pointLights = new PointLight[numPointLight];
+// InstancedNode debugSpheres = new InstancedNode("debugSpheres");
+// Sphere sphereMesh = new Sphere(16, 16, 1);
+// Geometry sphere = new Geometry("Sphere");
+// sphere.setMesh(sphereMesh);
+// Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+// mat.getAdditionalRenderState().setWireframe(true);
+// mat.setColor("Color", ColorRGBA.Green);
+// mat.setBoolean("UseInstancing", true);
+// sphere.setMaterial(mat);
+ float xHalf = 200, yHalf = 100, zHalf = 200;
+ for(int i = 0;i < numPointLight;i++){
+ pointLights[i] = new PointLight();
+ pointLights[i].setColor(colors[FastMath.nextRandomInt(0, colors.length - 1)]);
+ pointLights[i].setRadius(FastMath.nextRandomFloat(10.0f, 20.0f));
+ pointLights[i].setPosition(new Vector3f(FastMath.nextRandomFloat(-xHalf, xHalf), FastMath.nextRandomFloat(-yHalf, -60.0f), FastMath.nextRandomFloat(-zHalf, zHalf)));
+ rootNode.addLight(pointLights[i]);
+// Geometry sp = sphere.clone(false);
+// sp.setLocalTranslation(new Vector3f(FastMath.nextRandomFloat(-xHalf, xHalf), FastMath.nextRandomFloat(-yHalf, -60.0f), FastMath.nextRandomFloat(-zHalf, zHalf)));
+// sp.setLocalScale(FastMath.nextRandomFloat(10.0f, 20.0f));
+// debugSpheres.attachChild(sp);
+ }
+// debugSpheres.instance();
+// rootNode.attachChild(debugSpheres);
+ }
+
+ private void setUpCamera() {
+ cam.setLocation(new Vector3f(0, 10, -10));
+ cam.lookAtDirection(new Vector3f(0, -1.5f, -1).normalizeLocal(), Vector3f.UNIT_Y);
+
+ getFlyByCamera().setMoveSpeed(camMoveSpeed);
+ }
+}
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java b/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java
index 159aa57d27..3e8fe040d8 100644
--- a/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TestTileBasedDeferredShading.java
@@ -25,6 +25,8 @@ public class TestTileBasedDeferredShading extends SimpleApplication {
private Material material;
@Override
public void simpleInitApp() {
+ // Based on your current resolution and total light source count, try adjusting the tileSize - it must be a power of 2 such as 32, 64, 128 etc.
+ renderManager.setForceTileSize(128);// 1600 * 900 resolution config
// renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass);
// renderManager.setSinglePassLightBatchSize(30);
// renderManager.setRenderPath(RenderManager.RenderPath.Forward);
@@ -120,7 +122,9 @@ public void simpleInitApp() {
public static void main(String[] args) {
TestTileBasedDeferredShading testTileBasedDeferredShading = new TestTileBasedDeferredShading();
AppSettings appSettings = new AppSettings(true);
- appSettings.setRenderer(AppSettings.LWJGL_OPENGL33);
+ appSettings.setWidth(1600);
+ appSettings.setHeight(900);
+// appSettings.setRenderer(AppSettings.LWJGL_OPENGL33);
testTileBasedDeferredShading.setSettings(appSettings);
testTileBasedDeferredShading.start();
}
From 000fb0e43bc97249809338d1659c617ea0564016 Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Fri, 20 Oct 2023 16:20:08 +0800
Subject: [PATCH 022/111] jme3-examples:update TestPBRTerrainRenderPath.java
---
.../renderpath/TestPBRTerrainRenderPath.java | 40 +++++++++++++++++--
1 file changed, 37 insertions(+), 3 deletions(-)
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java
index 9d393c7c3d..2603562506 100644
--- a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainRenderPath.java
@@ -116,20 +116,27 @@ public class TestPBRTerrainRenderPath extends SimpleApplication {
private AmbientLight ambientLight;
private DirectionalLight directionalLight;
private PointLight[] pointLights;
+ private int currentPointLightNum = 1000;
private boolean isNight = true;
private final float dayLightIntensity = 1.0f;
private final float nightLightIntensity = 0.03f;
private BitmapText keybindingsText;
+ private BitmapText currentPointLightsText;
private final float camMoveSpeed = 50f;
public static void main(String[] args) {
TestPBRTerrainRenderPath app = new TestPBRTerrainRenderPath();
AppSettings appSettings = new AppSettings(true);
+ // For this scene, use a tileSize=64 configuration (at 1600*900 resolution)
+ // TileSize 64
appSettings.setWidth(1600);
appSettings.setHeight(900);
+ appSettings.setVSync(false);
+ app.setSettings(appSettings);
+ app.showSettings = false;
// appSettings.setRenderer(AppSettings.LWJGL_OPENGL33);
app.start();
}
@@ -167,6 +174,24 @@ public void onAction(String name, boolean pressed, float tpf) {
isNight = !isNight;
// Ambient and directional light are faded smoothly in update loop below.
}
+ if (name.equals("delPointLight") && !pressed) {
+ if(currentPointLightNum > 0){
+ for(int i = 0;i < 10;i++){
+ pointLights[currentPointLightNum - i - 1].setEnabled(false);
+ }
+ currentPointLightNum-=10;
+ currentPointLightsText.setText("Current PointLights[" + currentPointLightNum + "],Press '1' addPointLight,Press '2' delPointLight");
+ }
+ }
+ else if(name.equals("addPointLight") && !pressed){
+ if(currentPointLightNum < 1000){
+ for(int i = 0;i < 10;i++){
+ pointLights[currentPointLightNum + i].setEnabled(true);
+ }
+ currentPointLightNum+=10;
+ currentPointLightsText.setText("Current PointLights[" + currentPointLightNum + "],Press '1' addPointLight,Press '2' delPointLight");
+ }
+ }
}
};
@@ -297,15 +322,24 @@ private void setupKeys() {
flyCam.setMoveSpeed(50);
inputManager.addMapping("triPlanar", new KeyTrigger(KeyInput.KEY_P));
inputManager.addMapping("toggleNight", new KeyTrigger(KeyInput.KEY_N));
+ inputManager.addMapping("addPointLight", new KeyTrigger(KeyInput.KEY_1));
+ inputManager.addMapping("delPointLight", new KeyTrigger(KeyInput.KEY_2));
inputManager.addListener(actionListener, "triPlanar");
inputManager.addListener(actionListener, "toggleNight");
+ inputManager.addListener(actionListener, "addPointLight");
+ inputManager.addListener(actionListener, "delPointLight");
keybindingsText = new BitmapText(assetManager.loadFont("Interface/Fonts/Default.fnt"));
keybindingsText.setText("Press 'N' to toggle day/night fade (takes a moment) \nPress 'P' to toggle tri-planar mode");
getGuiNode().attachChild(keybindingsText);
keybindingsText.move(new Vector3f(200, 120, 0));
+
+ currentPointLightsText = new BitmapText(assetManager.loadFont("Interface/Fonts/Default.fnt"));
+ currentPointLightsText.setText("Current PointLights[" + currentPointLightNum + "],Press '1' addPointLight,Press '2' delPointLight");
+ getGuiNode().attachChild(currentPointLightsText);
+ currentPointLightsText.move(new Vector3f(200, 200, 0));
}
@Override
@@ -385,7 +419,7 @@ private void setUpLights() {
// pointLights
- int numPointLight = 1000;
+ currentPointLightNum = 1000;
ColorRGBA colors[] = new ColorRGBA[]{
ColorRGBA.White,
ColorRGBA.Red,
@@ -395,7 +429,7 @@ private void setUpLights() {
ColorRGBA.Orange,
ColorRGBA.Brown,
};
- pointLights = new PointLight[numPointLight];
+ pointLights = new PointLight[currentPointLightNum];
// InstancedNode debugSpheres = new InstancedNode("debugSpheres");
// Sphere sphereMesh = new Sphere(16, 16, 1);
// Geometry sphere = new Geometry("Sphere");
@@ -406,7 +440,7 @@ private void setUpLights() {
// mat.setBoolean("UseInstancing", true);
// sphere.setMaterial(mat);
float xHalf = 200, yHalf = 100, zHalf = 200;
- for(int i = 0;i < numPointLight;i++){
+ for(int i = 0;i < currentPointLightNum;i++){
pointLights[i] = new PointLight();
pointLights[i].setColor(colors[FastMath.nextRandomInt(0, colors.length - 1)]);
pointLights[i].setRadius(FastMath.nextRandomFloat(10.0f, 20.0f));
From 09a22a6a9f7859f8e17111ee8707d35a4a8c17aa Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Fri, 20 Oct 2023 17:05:35 +0800
Subject: [PATCH 023/111] jme3-core:Fix TestTexture3D/TestTexture3DLoading
---
.../src/main/resources/Common/ShaderLib/GLSLCompat.glsllib | 2 ++
1 file changed, 2 insertions(+)
diff --git a/jme3-core/src/main/resources/Common/ShaderLib/GLSLCompat.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/GLSLCompat.glsllib
index 6019886482..af3bd33c3d 100644
--- a/jme3-core/src/main/resources/Common/ShaderLib/GLSLCompat.glsllib
+++ b/jme3-core/src/main/resources/Common/ShaderLib/GLSLCompat.glsllib
@@ -2,6 +2,7 @@
#extension GL_ARB_explicit_attrib_location : enable
#endif
+#if __VERSION__ >= 310
#ifdef FRAGMENT_SHADER
precision highp float;
precision highp int;
@@ -15,6 +16,7 @@
#endif
#endif
+#endif
#if defined GL_ES
# define hfloat highp float
From 83ac2b558d07c1a372e04426e7889fd20d9ec25d Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Fri, 20 Oct 2023 17:11:04 +0800
Subject: [PATCH 024/111] jme3-core:fix lightTexSizeInv undefined
---
.../Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag | 2 ++
1 file changed, 2 insertions(+)
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
index 9cf1bd9b3c..d316ed90e2 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.frag
@@ -75,6 +75,7 @@ void main(){
lightNum = m_NBLight;
#else
lightNum = NB_LIGHTS;
+ float lightTexSizeInv = 1.0f / (float(lightNum) - 1.0f);
#endif
// Tile Based Shading
@@ -253,6 +254,7 @@ void main(){
lightNum = m_NBLight;
#else
lightNum = NB_LIGHTS;
+ float lightTexSizeInv = 1.0f / (float(lightNum) - 1.0f);
#endif
gl_FragColor.rgb = vec3(0.0);
// Tile Based Shading
From 3521b2aa0ec61e0395cb1bd83d7ef7d03d627b29 Mon Sep 17 00:00:00 2001
From: John_R_Kkk <18402012144@163.com>
Date: Sat, 21 Oct 2023 21:42:57 +0800
Subject: [PATCH 025/111] jme3-core: 1.change
java.com.jme3.renderer.renderPass=>java.com.jme3.renderer.pass 2.change
IRenderGeometry.java=>RenderGeometry.java
---
.../java/com/jme3/renderer/RenderManager.java | 16 ++++++++--------
.../renderer/framegraph/FGRenderQueuePass.java | 4 ++--
.../DeferredLightDataSink.java | 2 +-
.../DeferredLightDataSource.java | 2 +-
.../DeferredShadingPass.java | 2 +-
.../{renderPass => pass}/ForwardPass.java | 2 +-
.../{renderPass => pass}/GBufferPass.java | 2 +-
.../renderer/{renderPass => pass}/GuiPass.java | 2 +-
.../{renderPass => pass}/OpaquePass.java | 2 +-
.../{renderPass => pass}/PostProcessorPass.java | 2 +-
.../RenderGeometry.java} | 4 ++--
.../ResolveSceneColorPass.java | 2 +-
.../{renderPass => pass}/ScreenPass.java | 2 +-
.../ScreenSpaceSubsurfaceScatteringPass.java | 2 +-
.../renderer/{renderPass => pass}/SkyPass.java | 2 +-
.../TileDeferredShadingPass.java | 2 +-
.../{renderPass => pass}/TranslucentPass.java | 2 +-
.../{renderPass => pass}/TransparentPass.java | 2 +-
.../com/jme3/renderer/queue/RenderQueue.java | 4 ++--
19 files changed, 29 insertions(+), 29 deletions(-)
rename jme3-core/src/main/java/com/jme3/renderer/{renderPass => pass}/DeferredLightDataSink.java (98%)
rename jme3-core/src/main/java/com/jme3/renderer/{renderPass => pass}/DeferredLightDataSource.java (98%)
rename jme3-core/src/main/java/com/jme3/renderer/{renderPass => pass}/DeferredShadingPass.java (99%)
rename jme3-core/src/main/java/com/jme3/renderer/{renderPass => pass}/ForwardPass.java (98%)
rename jme3-core/src/main/java/com/jme3/renderer/{renderPass => pass}/GBufferPass.java (99%)
rename jme3-core/src/main/java/com/jme3/renderer/{renderPass => pass}/GuiPass.java (98%)
rename jme3-core/src/main/java/com/jme3/renderer/{renderPass => pass}/OpaquePass.java (98%)
rename jme3-core/src/main/java/com/jme3/renderer/{renderPass => pass}/PostProcessorPass.java (98%)
rename jme3-core/src/main/java/com/jme3/renderer/{renderPass/IRenderGeometry.java => pass/RenderGeometry.java} (96%)
rename jme3-core/src/main/java/com/jme3/renderer/{renderPass => pass}/ResolveSceneColorPass.java (99%)
rename jme3-core/src/main/java/com/jme3/renderer/{renderPass => pass}/ScreenPass.java (98%)
rename jme3-core/src/main/java/com/jme3/renderer/{renderPass => pass}/ScreenSpaceSubsurfaceScatteringPass.java (87%)
rename jme3-core/src/main/java/com/jme3/renderer/{renderPass => pass}/SkyPass.java (98%)
rename jme3-core/src/main/java/com/jme3/renderer/{renderPass => pass}/TileDeferredShadingPass.java (98%)
rename jme3-core/src/main/java/com/jme3/renderer/{renderPass => pass}/TranslucentPass.java (98%)
rename jme3-core/src/main/java/com/jme3/renderer/{renderPass => pass}/TransparentPass.java (98%)
diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
index 89d394bb85..0b551b7af1 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
@@ -54,7 +54,7 @@
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
-import com.jme3.renderer.renderPass.*;
+import com.jme3.renderer.pass.*;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
@@ -94,7 +94,7 @@ public class RenderManager {
private int curTileSize = -1;
private int numberTileDivisions = 4;
// frameGraph=============================================================================↓
- private IRenderGeometry iRenderGeometry;
+ private RenderGeometry renderGeometry;
private boolean useFramegraph = true;
private FrameGraph frameGraph;
private GBufferPass gBufferPass;
@@ -255,16 +255,16 @@ public TileBasedDeferredSinglePassLightingLogic.TileInfo getTileInfo() {
/**
* Set an IRenderGeometry for executing drawing call interfaces for the specified FGPass.
- * @param iRenderGeometry
+ * @param renderGeometry
*
- * @see IRenderGeometry
+ * @see RenderGeometry
*/
- public final void setRenderGeometryHandler(IRenderGeometry iRenderGeometry){
- this.iRenderGeometry = iRenderGeometry;
+ public final void setRenderGeometryHandler(RenderGeometry renderGeometry){
+ this.renderGeometry = renderGeometry;
}
- public IRenderGeometry getRenderGeometryHandler() {
- return iRenderGeometry;
+ public RenderGeometry getRenderGeometryHandler() {
+ return renderGeometry;
}
/**
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java
index 9e7b205702..dbd5ad6916 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java
@@ -34,13 +34,13 @@
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.GeometryList;
import com.jme3.renderer.queue.RenderQueue;
-import com.jme3.renderer.renderPass.IRenderGeometry;
+import com.jme3.renderer.pass.RenderGeometry;
/**
* All passes that need to perform rendering must inherit from this class.
* @author JohnKkk
*/
-public abstract class FGRenderQueuePass extends FGBindingPass implements IRenderGeometry {
+public abstract class FGRenderQueuePass extends FGBindingPass implements RenderGeometry {
protected ViewPort forceViewPort;
// It is just geometry data for now. If we extend the RHI interface in the future, it may be adjusted to MeshDrawCommand.
protected GeometryList passMeshDrawCommandList;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSink.java b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataSink.java
similarity index 98%
rename from jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSink.java
rename to jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataSink.java
index f20ac645b7..7543371b45 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataSink.java
@@ -29,7 +29,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package com.jme3.renderer.renderPass;
+package com.jme3.renderer.pass;
import com.jme3.renderer.framegraph.FGBindable;
import com.jme3.renderer.framegraph.FGContainerBindableSink;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSource.java b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataSource.java
similarity index 98%
rename from jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSource.java
rename to jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataSource.java
index 9decca3bb3..a2e2866102 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredLightDataSource.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataSource.java
@@ -29,7 +29,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package com.jme3.renderer.renderPass;
+package com.jme3.renderer.pass;
import com.jme3.light.LightList;
import com.jme3.renderer.framegraph.FGBindable;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredShadingPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingPass.java
similarity index 99%
rename from jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredShadingPass.java
rename to jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingPass.java
index 40af7c1aee..4712feb294 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/DeferredShadingPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingPass.java
@@ -29,7 +29,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package com.jme3.renderer.renderPass;
+package com.jme3.renderer.pass;
import com.jme3.light.LightList;
import com.jme3.material.Material;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/ForwardPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardPass.java
similarity index 98%
rename from jme3-core/src/main/java/com/jme3/renderer/renderPass/ForwardPass.java
rename to jme3-core/src/main/java/com/jme3/renderer/pass/ForwardPass.java
index 44feb97c03..658862ff3d 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/ForwardPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardPass.java
@@ -29,7 +29,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package com.jme3.renderer.renderPass;
+package com.jme3.renderer.pass;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferPass.java
similarity index 99%
rename from jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java
rename to jme3-core/src/main/java/com/jme3/renderer/pass/GBufferPass.java
index 8329195692..9344fec975 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/GBufferPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferPass.java
@@ -29,7 +29,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package com.jme3.renderer.renderPass;
+package com.jme3.renderer.pass;
import com.jme3.light.Light;
import com.jme3.light.LightList;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/GuiPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/GuiPass.java
similarity index 98%
rename from jme3-core/src/main/java/com/jme3/renderer/renderPass/GuiPass.java
rename to jme3-core/src/main/java/com/jme3/renderer/pass/GuiPass.java
index 256e974fe3..540aaa7dc2 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/GuiPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/GuiPass.java
@@ -29,7 +29,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package com.jme3.renderer.renderPass;
+package com.jme3.renderer.pass;
import com.jme3.renderer.Camera;
import com.jme3.renderer.framegraph.FGRenderContext;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/OpaquePass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/OpaquePass.java
similarity index 98%
rename from jme3-core/src/main/java/com/jme3/renderer/renderPass/OpaquePass.java
rename to jme3-core/src/main/java/com/jme3/renderer/pass/OpaquePass.java
index ca58b49ed7..f4c98956aa 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/OpaquePass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/OpaquePass.java
@@ -29,7 +29,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package com.jme3.renderer.renderPass;
+package com.jme3.renderer.pass;
import com.jme3.renderer.framegraph.FGRenderContext;
import com.jme3.renderer.queue.RenderQueue;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/PostProcessorPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessorPass.java
similarity index 98%
rename from jme3-core/src/main/java/com/jme3/renderer/renderPass/PostProcessorPass.java
rename to jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessorPass.java
index 588517ece6..e218b14998 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/PostProcessorPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessorPass.java
@@ -29,7 +29,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package com.jme3.renderer.renderPass;
+package com.jme3.renderer.pass;
import com.jme3.post.SceneProcessor;
import com.jme3.renderer.ViewPort;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/IRenderGeometry.java b/jme3-core/src/main/java/com/jme3/renderer/pass/RenderGeometry.java
similarity index 96%
rename from jme3-core/src/main/java/com/jme3/renderer/renderPass/IRenderGeometry.java
rename to jme3-core/src/main/java/com/jme3/renderer/pass/RenderGeometry.java
index 7c62efae9d..b858c6da8b 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/IRenderGeometry.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/RenderGeometry.java
@@ -29,7 +29,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package com.jme3.renderer.renderPass;
+package com.jme3.renderer.pass;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
@@ -37,7 +37,7 @@
/**
* @author JohnKkk
*/
-public interface IRenderGeometry {
+public interface RenderGeometry {
/**
* Submit the given Geometry to the Pipeline for rendering.
* @param rm
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/ResolveSceneColorPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/ResolveSceneColorPass.java
similarity index 99%
rename from jme3-core/src/main/java/com/jme3/renderer/renderPass/ResolveSceneColorPass.java
rename to jme3-core/src/main/java/com/jme3/renderer/pass/ResolveSceneColorPass.java
index ac06528f1f..51b9b39488 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/ResolveSceneColorPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/ResolveSceneColorPass.java
@@ -29,7 +29,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package com.jme3.renderer.renderPass;
+package com.jme3.renderer.pass;
import com.jme3.material.Material;
import com.jme3.material.MaterialDef;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/ScreenPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/ScreenPass.java
similarity index 98%
rename from jme3-core/src/main/java/com/jme3/renderer/renderPass/ScreenPass.java
rename to jme3-core/src/main/java/com/jme3/renderer/pass/ScreenPass.java
index fc943a2a45..d6c4745d53 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/ScreenPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/ScreenPass.java
@@ -29,7 +29,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package com.jme3.renderer.renderPass;
+package com.jme3.renderer.pass;
import com.jme3.asset.AssetManager;
import com.jme3.asset.plugins.ClasspathLocator;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/ScreenSpaceSubsurfaceScatteringPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/ScreenSpaceSubsurfaceScatteringPass.java
similarity index 87%
rename from jme3-core/src/main/java/com/jme3/renderer/renderPass/ScreenSpaceSubsurfaceScatteringPass.java
rename to jme3-core/src/main/java/com/jme3/renderer/pass/ScreenSpaceSubsurfaceScatteringPass.java
index 6e7134f84a..99583579bd 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/ScreenSpaceSubsurfaceScatteringPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/ScreenSpaceSubsurfaceScatteringPass.java
@@ -1,4 +1,4 @@
-package com.jme3.renderer.renderPass;
+package com.jme3.renderer.pass;
/**
* Subsurface Scattering.
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/SkyPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/SkyPass.java
similarity index 98%
rename from jme3-core/src/main/java/com/jme3/renderer/renderPass/SkyPass.java
rename to jme3-core/src/main/java/com/jme3/renderer/pass/SkyPass.java
index a78b78c55a..17f0dda921 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/SkyPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/SkyPass.java
@@ -29,7 +29,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package com.jme3.renderer.renderPass;
+package com.jme3.renderer.pass;
import com.jme3.renderer.framegraph.FGRenderContext;
import com.jme3.renderer.queue.RenderQueue;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/TileDeferredShadingPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingPass.java
similarity index 98%
rename from jme3-core/src/main/java/com/jme3/renderer/renderPass/TileDeferredShadingPass.java
rename to jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingPass.java
index 5ed0492a04..399cd10529 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/TileDeferredShadingPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingPass.java
@@ -29,7 +29,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package com.jme3.renderer.renderPass;
+package com.jme3.renderer.pass;
import com.jme3.light.LightList;
import com.jme3.material.Material;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/TranslucentPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/TranslucentPass.java
similarity index 98%
rename from jme3-core/src/main/java/com/jme3/renderer/renderPass/TranslucentPass.java
rename to jme3-core/src/main/java/com/jme3/renderer/pass/TranslucentPass.java
index 8f798cfafc..67a2f1e9c1 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/TranslucentPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/TranslucentPass.java
@@ -29,7 +29,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package com.jme3.renderer.renderPass;
+package com.jme3.renderer.pass;
import com.jme3.renderer.framegraph.FGRenderContext;
import com.jme3.renderer.queue.RenderQueue;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/renderPass/TransparentPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/TransparentPass.java
similarity index 98%
rename from jme3-core/src/main/java/com/jme3/renderer/renderPass/TransparentPass.java
rename to jme3-core/src/main/java/com/jme3/renderer/pass/TransparentPass.java
index fb81c4c55d..5496bdebb5 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/renderPass/TransparentPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/TransparentPass.java
@@ -29,7 +29,7 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package com.jme3.renderer.renderPass;
+package com.jme3.renderer.pass;
import com.jme3.renderer.framegraph.FGRenderContext;
import com.jme3.renderer.queue.RenderQueue;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java b/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java
index 326c52da91..f9754864db 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/queue/RenderQueue.java
@@ -34,7 +34,7 @@
import com.jme3.post.SceneProcessor;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
-import com.jme3.renderer.renderPass.IRenderGeometry;
+import com.jme3.renderer.pass.RenderGeometry;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
@@ -268,7 +268,7 @@ public void addToQueue(Geometry g, Bucket bucket) {
}
private void renderGeometryList(GeometryList list, RenderManager rm, Camera cam, boolean clear) {
- IRenderGeometry renderGeometryHandler = rm.getRenderGeometryHandler();
+ RenderGeometry renderGeometryHandler = rm.getRenderGeometryHandler();
if(renderGeometryHandler != null){
list.setCamera(cam); // select camera for sorting
list.sort();
From 224eecdf9980049ee9c491ea76ade23ca8772433 Mon Sep 17 00:00:00 2001
From: John_R_Kkk <18402012144@163.com>
Date: Sun, 22 Oct 2023 10:52:53 +0800
Subject: [PATCH 026/111] jme3-core:use g_ViewProjectionMatrixInverse
---
.../Common/MatDefs/ShadingCommon/DeferredShading.j3md | 1 +
.../MatDefs/ShadingCommon/TileBasedDeferredShading.j3md | 1 +
.../main/resources/Common/ShaderLib/Instancing.glsllib | 9 ++++-----
3 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md
index 202deba7bd..265bab64b9 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/DeferredShading.j3md
@@ -29,6 +29,7 @@ MaterialDef DeferredShading {
WorldParameters {
CameraPosition
+ ViewProjectionMatrixInverse
WorldViewProjectionMatrix
ViewProjectionMatrix
ResolutionInverse
diff --git a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md
index 1d73635a52..98a0b58a98 100644
--- a/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md
+++ b/jme3-core/src/main/resources/Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md
@@ -33,6 +33,7 @@ MaterialDef DeferredShading {
WorldParameters {
CameraPosition
+ ViewProjectionMatrixInverse
WorldViewProjectionMatrix
ViewProjectionMatrix
ResolutionInverse
diff --git a/jme3-core/src/main/resources/Common/ShaderLib/Instancing.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/Instancing.glsllib
index bf3f6e2e3f..d5d750a35b 100644
--- a/jme3-core/src/main/resources/Common/ShaderLib/Instancing.glsllib
+++ b/jme3-core/src/main/resources/Common/ShaderLib/Instancing.glsllib
@@ -26,12 +26,11 @@ uniform mat4 g_WorldViewProjectionMatrix;
uniform mat4 g_ViewProjectionMatrix;
uniform mat3 g_NormalMatrix;
uniform mat3 g_WorldNormalMatrix;
-mat4 GetViewProjectionMatrixInverse(){
- return inverse(g_ViewProjectionMatrix);
-}
+uniform mat4 g_ViewProjectionMatrixInverse;
-mat4 GetProjectionMatrixInverse(){
- return inverse(g_ProjectionMatrix);
+
+mat4 GetViewProjectionMatrixInverse(){
+ return g_ViewProjectionMatrixInverse;
}
#if defined INSTANCING
From db4f0ac59d06f23972cbdf37b755c342b1ce9e69 Mon Sep 17 00:00:00 2001
From: John_R_Kkk <18402012144@163.com>
Date: Sun, 22 Oct 2023 16:23:37 +0800
Subject: [PATCH 027/111] jme3-core:use logger
---
.../jme3/renderer/framegraph/FrameGraph.java | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
index 10009a8514..0f3db8e0df 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
@@ -32,6 +32,8 @@
package com.jme3.renderer.framegraph;
import java.util.ArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
* The FrameGraph system is used to manage render passes and the dependencies between them in a declarative way. Some key aspects:
@@ -50,6 +52,7 @@
* @author JohnKkk
*/
public class FrameGraph {
+ private static final Logger logger = Logger.getLogger(FrameGraph.class.getName());
private ArrayList passes;
private ArrayList globalSources;
private ArrayList globalSinks;
@@ -93,7 +96,9 @@ protected void linkSinks(FGPass pass){
if((linkPassName == null || linkPassName.isEmpty())){
if(sink.isRequired()){
- System.err.println("In pass named [" + pass.getName() + "] sink named [" + sink.getRegisteredName() + "] has no target source set.");
+ logger.throwing(FrameGraph.class.toString(), "", new NullPointerException("In pass named [" + pass.getName() + "] sink named [" + sink.getRegisteredName() + "] has no target source set."));
+// logger.log(Level.WARNING, "In pass named [" + pass.getName() + "] sink named [" + sink.getRegisteredName() + "] has no target source set.");
+// System.err.println("In pass named [" + pass.getName() + "] sink named [" + sink.getRegisteredName() + "] has no target source set.");
return;
}
else{
@@ -114,7 +119,8 @@ protected void linkSinks(FGPass pass){
if(!bound){
bound = FGGlobal.linkSink(sink);
if(!bound && sink.isRequired()){
- System.err.println("Pass named [" + linkPassName + "] not found");
+ logger.throwing(FrameGraph.class.toString(), "", new NullPointerException("Pass named [" + linkPassName + "] not found"));
+// System.err.println("Pass named [" + linkPassName + "] not found");
return;
}
}
@@ -133,7 +139,8 @@ protected void linkSinks(FGPass pass){
if(!bound){
bound = FGGlobal.linkSink(sink);
if(!bound && sink.isRequired()){
- System.err.println("Pass named [" + linkPassName + "] not found");
+ logger.throwing(FrameGraph.class.toString(), "", new NullPointerException("Pass named [" + linkPassName + "] not found"));
+// System.err.println("Pass named [" + linkPassName + "] not found");
return;
}
}
@@ -229,7 +236,8 @@ public final void addPass(FGPass pass){
// validate name uniqueness
for(FGPass nextPass : passes){
if(nextPass.getName().equals(pass.getName())){
- System.err.println("Pass name already exists: " + pass.getName());
+ logger.throwing(FrameGraph.class.toString(), "", new NullPointerException("Pass name already exists: " + pass.getName()));
+// System.err.println("Pass name already exists: " + pass.getName());
return;
}
}
@@ -249,7 +257,8 @@ public final FGPass findPassByName(String name){
return nextPass;
}
}
- System.err.println("Failed to find pass name");
+ logger.throwing(FrameGraph.class.toString(), "", new NullPointerException("Failed to find pass name"));
+// System.err.println("Failed to find pass name");
return null;
}
From dc3a50b47de07aabb8f8d0abb804760d5dda8878 Mon Sep 17 00:00:00 2001
From: JohnKkk <18402012144@163.com>
Date: Fri, 27 Oct 2023 17:30:40 +0800
Subject: [PATCH 028/111] jme3-core:update javadoc(FastMath.nextRandomFlot)
---
jme3-core/src/main/java/com/jme3/math/FastMath.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/jme3-core/src/main/java/com/jme3/math/FastMath.java b/jme3-core/src/main/java/com/jme3/math/FastMath.java
index 1a65918fb9..66bd1d6da4 100644
--- a/jme3-core/src/main/java/com/jme3/math/FastMath.java
+++ b/jme3-core/src/main/java/com/jme3/math/FastMath.java
@@ -848,7 +848,7 @@ public static float determinant(double m00, double m01, double m02,
*
* @param min the desired minimum value
* @param max the desired maximum value
- * @return A random int between min (inclusive) to
+ * @return A random float between min (inclusive) to
* max (inclusive).
*/
public static float nextRandomFloat(float min, float max) {
From 6fdeb355855d13970c746d1e3e7095b8aefdd1af Mon Sep 17 00:00:00 2001
From: codex <103840984+codex128@users.noreply.github.com>
Date: Thu, 18 Apr 2024 09:21:29 -0400
Subject: [PATCH 029/111] refactor FGPass, FGSink, and FGSource to interfaces
---
.../renderer/framegraph/AbstractFGPass.java | 150 ++++++++++++++++++
.../renderer/framegraph/AbstractFGSink.java | 82 ++++++++++
.../renderer/framegraph/AbstractFGSource.java | 51 ++++++
.../jme3/renderer/framegraph/FGBindable.java | 10 +-
.../renderer/framegraph/FGBindingPass.java | 11 +-
.../framegraph/FGContainerBindableSink.java | 12 +-
.../FGFramebufferCopyBindableSink.java | 6 +-
.../framegraph/FGFramebufferSource.java | 12 +-
.../jme3/renderer/framegraph/FGGlobal.java | 9 +-
.../com/jme3/renderer/framegraph/FGPass.java | 144 +++--------------
.../framegraph/FGRenderTargetSource.java | 11 +-
.../com/jme3/renderer/framegraph/FGSink.java | 81 +++-------
.../jme3/renderer/framegraph/FGSource.java | 48 ++----
.../framegraph/FGTextureBindableSink.java | 3 +-
.../jme3/renderer/framegraph/FGVarSource.java | 16 +-
.../jme3/renderer/framegraph/FrameGraph.java | 22 +--
.../renderer/pass/DeferredLightDataProxy.java | 4 +
.../pass/DeferredLightDataSource.java | 10 +-
.../jme3/renderer/pass/PostProcessorPass.java | 9 +-
19 files changed, 427 insertions(+), 264 deletions(-)
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGSink.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGSource.java
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java
new file mode 100644
index 0000000000..fd61b9092c
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
+
+import java.util.ArrayList;
+
+/**
+ * FGPass.
+ * @author JohnKkk
+ */
+public abstract class AbstractFGPass implements FGPass {
+
+ private final String name;
+ private final ArrayList sinks;
+ private final ArrayList sources;
+ protected boolean resetResources = false;
+
+ public AbstractFGPass(String name){
+ this.name = name;
+ this.sinks = new ArrayList<>();
+ this.sources = new ArrayList<>();
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public ArrayList getSinks() {
+ return sinks;
+ }
+
+ @Override
+ public ArrayList getSources() {
+ return sources;
+ }
+
+ @Override
+ public boolean isResetResources() {
+ return resetResources;
+ }
+
+ @Override
+ public FGSource getSource(String name){
+ for(FGSource src : getSources()){
+ if(src.getName().equals(name)){
+ return src;
+ }
+ }
+
+ System.err.println("Output name [" + name + "] not fount in pass:" + getName());
+ return null;
+ }
+
+ @Override
+ public FGSink getSink(String registeredName) {
+ for(FGSink sink : sinks){
+ if(sink.getRegisteredName().equals(registeredName)){
+ return sink;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void setSinkLinkage(String registeredName, String target){
+ FGSink sink = getSink(registeredName);
+ String targetSplit[] = target.split("\\.");
+ if(targetSplit.length != 2){
+ System.err.println("Input target has incorrect format");
+ }
+ sink.setTarget(targetSplit[0], targetSplit[1]);
+ }
+
+ @Override
+ public void registerSink(AbstractFGSink sink){
+ // check for overlap of input names
+ for(FGSink si : sinks){
+ if(si.getRegisteredName().equals(sink.getRegisteredName())){
+ System.err.println("Registered input overlaps with existing: " + sink.getRegisteredName());
+ return;
+ }
+ }
+ getSinks().add(sink);
+ }
+
+ @Override
+ public void registerSource(FGSource source) {
+ // check for overlap of output names
+ for(FGSource src : sources){
+ if(src.getName().equals(source.getName())){
+ System.err.println("Registered input overlaps with existing: " + source.getName());
+ return;
+ }
+ }
+ getSources().add(source);
+ }
+
+ @Override
+ public void reset() {
+ if(isResetResources()){
+ getSources().clear();
+ getSinks().clear();
+ }
+ }
+
+ @Override
+ public void finalize() {
+ // WARNING:
+ // This method's name conflicts with Object.finalize. I am not sure if
+ // that is on purpose, so I will not attempt to change it.
+ for(FGSink sink : sinks){
+ sink.postLinkValidate();
+ }
+ for(FGSource src : sources){
+ src.postLinkValidate();
+ }
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGSink.java
new file mode 100644
index 0000000000..49fb641e05
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGSink.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
+
+/**
+ *
+ * @author JohnKkk
+ */
+public abstract class AbstractFGSink implements FGSink {
+
+ private String registeredName;
+ private String linkPassName;
+ private String linkPassResName;
+ protected boolean bIsRequired = false;
+ // Always validate?
+ protected boolean bLinkValidate = false;
+
+ protected AbstractFGSink(String registeredName) {
+ this.registeredName = registeredName;
+ }
+
+ @Override
+ public boolean isRequired() {
+ return bIsRequired;
+ }
+
+ @Override
+ public String getRegisteredName() {
+ return registeredName;
+ }
+
+ @Override
+ public String getLinkPassName() {
+ return linkPassName;
+ }
+
+ @Override
+ public String getLinkPassResName() {
+ return linkPassResName;
+ }
+
+ @Override
+ public void setTarget(String inPassName, String inPassResName){
+ linkPassName = inPassName;
+ linkPassResName = inPassResName;
+ }
+
+ @Override
+ public boolean isLinkValidate() {
+ return bLinkValidate;
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGSource.java
new file mode 100644
index 0000000000..d6280054a6
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGSource.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
+
+/**
+ *
+ * @author JohnKkk
+ */
+public abstract class AbstractFGSource implements FGSource {
+
+ private String name;
+
+ public AbstractFGSource(String name){
+ this.name = name;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java
index 60e84b6f03..488010b07d 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java
@@ -35,14 +35,14 @@
* FGBindable can be any resource that needs binding (such as state machine, FBO, Texture, Paramater...)
* @author JohnKkk
*/
-public abstract class FGBindable {
+public interface FGBindable {
- private final static String _S_DEFAULT_BINDABLE_UID = "";
+ public final static String DEFAULT_BINDABLE_UID = "";
- public void bind(FGRenderContext renderContext){}
+ public void bind(FGRenderContext renderContext);
- public String getUID() {
- return _S_DEFAULT_BINDABLE_UID;
+ public default String getUID() {
+ return DEFAULT_BINDABLE_UID;
}
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java
index 0288e38216..ce1f377480 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java
@@ -37,8 +37,10 @@
*A FGBindingPass represents a Pass that needs to perform state machine binding, ShaderResource binding, FrameBuffer binding and other operations.
* @author JohnKkk
*/
-public class FGBindingPass extends FGPass{
+public class FGBindingPass extends AbstractFGPass {
+
protected ArrayList binds;
+
protected FGBindingPass(String name){
this(name, new ArrayList());
}
@@ -64,6 +66,9 @@ public void bindAll(FGRenderContext renderContext){
}
@Override
- public void execute(FGRenderContext renderContext) {
- }
+ public void prepare(FGRenderContext renderContext) {}
+
+ @Override
+ public void execute(FGRenderContext renderContext) {}
+
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java
index 25c7eb70f8..a097a51a42 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java
@@ -34,16 +34,21 @@
import java.util.ArrayList;
/**
- *FGContainerBindableSink is used to proxy a FGSink, and also has the role of FGBindable. Typically, a Sink needed by a Pass may be a Bindable object.
+ * FGContainerBindableSink is used to proxy a FGSink, and also has the role of FGBindable.
+ *
+ * Typically, a Sink needed by a Pass may be a Bindable object.
+ *
* @author JohnKkk
+ * @param
*/
-public class FGContainerBindableSink extends FGSink{
+public class FGContainerBindableSink extends AbstractFGSink {
protected boolean linked = false;
protected ArrayList container;
protected int index;
protected FGBindableProxy bindableProxy;
- public final static class FGBindableProxy extends FGBindable{
+ public final static class FGBindableProxy implements FGBindable {
+
public FGBindable targetBindable;
public FGBindableProxy(FGBindable targetBindable) {
@@ -56,6 +61,7 @@ public void bind(FGRenderContext renderContext) {
targetBindable.bind(renderContext);
}
}
+
}
public FGContainerBindableSink(String registeredName, ArrayList container, int index) {
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java
index ef6d86945d..f0e10daba3 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java
@@ -39,7 +39,7 @@
* @author JohnKkk
* @param
*/
-public class FGFramebufferCopyBindableSink extends FGContainerBindableSink{
+public class FGFramebufferCopyBindableSink extends FGContainerBindableSink {
FramebufferCopyBindableProxy framebufferCopyBindableProxy;
public final void setDistFrameBuffer(FrameBuffer distFrameBuffer){
framebufferCopyBindableProxy.distFramebuffer = distFrameBuffer;
@@ -49,7 +49,7 @@ public FGFramebufferCopyBindableSink(String registeredName, FrameBuffer distFram
framebufferCopyBindableProxy = new FramebufferCopyBindableProxy(distFrameBuffer, copyColor, copyDepth, copyStencil);
}
- private final static class FramebufferCopyBindableProxy extends FGBindable{
+ private final static class FramebufferCopyBindableProxy implements FGBindable {
FrameBuffer sourceFramebuffer;
FrameBuffer distFramebuffer;
boolean bCopyColor;
@@ -78,7 +78,7 @@ public void bind(FGRenderContext renderContext) {
@Override
public void bind(FGSource fgSource) {
T p = (T)fgSource.yieldBindable();
- if(p == null){
+ if (p == null) {
System.err.println("Binding input [" + getRegisteredName() + "] to output [" + getLinkPassName() + "." + getLinkPassResName() + "] " + " { " + fgSource.getName() + " } ");
return;
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferSource.java
index 876b42ba4d..bbfbd91fa3 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferSource.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferSource.java
@@ -36,9 +36,12 @@
/**
* @author JohnKkk
*/
-public class FGFramebufferSource extends FGSource{
- private FrameBufferSourceProxy frameBufferSourceProxy;
- public final static class FrameBufferSourceProxy extends FGBindable{
+public class FGFramebufferSource extends AbstractFGSource {
+
+ private final FrameBufferSourceProxy frameBufferSourceProxy;
+
+ public final static class FrameBufferSourceProxy implements FGBindable {
+
private FrameBuffer frameBuffer;
public FrameBufferSourceProxy(FrameBuffer frameBuffer) {
@@ -48,6 +51,9 @@ public FrameBufferSourceProxy(FrameBuffer frameBuffer) {
public FrameBuffer getFrameBuffer() {
return frameBuffer;
}
+ @Override
+ public void bind(FGRenderContext renderContext) {}
+
}
public FGFramebufferSource(String name, FrameBuffer frameBuffer) {
super(name);
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGGlobal.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGGlobal.java
index 40332f6af3..d448f80370 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGGlobal.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGGlobal.java
@@ -38,6 +38,7 @@
* @author JohnKkk
*/
public class FGGlobal {
+
public final static String S_GLOABLE_PASS_SOURCE_NAME = "$";
public final static String S_SCENE_COLOR_FB = "sceneColorFramebuffer";
public final static String S_SCENE_COLOR_RT = "sceneColorRT";
@@ -45,15 +46,17 @@ public class FGGlobal {
public final static String S_DEFAULT_FB = "defaultFramebuffer";
private final static ArrayList g_Sinks = new ArrayList<>();
private final static ArrayList g_Sources = new ArrayList<>();
+
public final static boolean linkSink(FGSink outSink){
boolean bound = false;
- for(FGSource soucre : g_Sources){
- if(soucre.getName().equals(outSink.getLinkPassResName())){
- outSink.bind(soucre);
+ for(FGSource src : g_Sources){
+ if(src.getName().equals(outSink.getLinkPassResName())){
+ outSink.bind(src);
bound = true;
break;
}
}
return bound;
}
+
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
index f4075bf630..b0ef96cb49 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
@@ -1,140 +1,44 @@
/*
- * Copyright (c) 2009-2023 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.
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Interface.java to edit this template
*/
package com.jme3.renderer.framegraph;
import java.util.ArrayList;
/**
- * FGPass.
- * @author JohnKkk
+ *
+ * @author codex
*/
-public abstract class FGPass {
- private String name;
- private ArrayList sinks;
- private ArrayList sources;
- protected boolean resetClearSinksAndSources = false;
- public FGPass(String name){
- this.name = name;
- this.sinks = new ArrayList<>();
- this.sources = new ArrayList<>();
- }
- public void prepare(FGRenderContext renderContext){}
- public abstract void execute(FGRenderContext renderContext);
+public interface FGPass {
- public String getName() {
- return name;
- }
+ public String getName();
- public ArrayList getSinks() {
- return sinks;
- }
+ public ArrayList getSinks();
- public ArrayList getSources() {
- return sources;
- }
+ public ArrayList getSources();
+
+ public boolean isResetResources();
+
+ public void prepare(FGRenderContext renderContext);
+
+ public void execute(FGRenderContext renderContext);
- public FGSource getSource(String name){
- for(FGSource src : sources){
- if(src.getName().equals(name)){
- return src;
- }
- }
-
- System.err.println("Output name [" + name + "] not fount in pass:" + getName());
- return null;
- }
+ public FGSource getSource(String name);
- public FGSink getSink(String registeredName){
- for(FGSink sink : sinks){
- if(sink.getRegisteredName().equals(registeredName)){
- return sink;
- }
- }
- return null;
- }
+ public FGSink getSink(String registeredName);
- public void setSinkLinkage(String registeredName, String target){
- FGSink sink = getSink(registeredName);
-
- String targetSplit[] = target.split("\\.");
- if(targetSplit.length != 2){
- System.err.println("Input target has incorrect format");
- }
- sink.setTarget(targetSplit[0], targetSplit[1]);
- }
+ public void setSinkLinkage(String registeredName, String target);
- protected void registerSink(FGSink sink){
- // check for overlap of input names
- for(FGSink si : sinks){
- if(si.getRegisteredName().equals(sink.getRegisteredName())){
- System.err.println("Registered input overlaps with existing: " + sink.getRegisteredName());
- return;
- }
- }
-
- sinks.add(sink);
- }
+ public void registerSink(AbstractFGSink sink);
- public void registerSource(FGSource source){
- // check for overlap of output names
- for(FGSource src : sources){
- if(src.getName().equals(source.getName())){
- System.err.println("Registered input overlaps with existing: " + source.getName());
- return;
- }
- }
-
- sources.add(source);
- }
+ public void registerSource(FGSource source);
- public void reset(){
- if(resetClearSinksAndSources){
- this.sources.clear();
- this.sinks.clear();
- }
- }
+ public void reset();
- public void finalize(){
- if(sinks != null && sinks.size() > 0){
- for(FGSink sink : sinks){
- sink.postLinkValidate();
- }
- }
-
- if(sources != null && sources.size() > 0){
- for(FGSource src : sources){
- src.postLinkValidate();
- }
- }
- }
+ // WARNING:
+ // This method's name conflicts with Object.finalize. I am not sure if
+ // that is on purpose, so I will not attempt to change it.
+ public void finalize();
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderTargetSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderTargetSource.java
index 645651061a..e558d8ff50 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderTargetSource.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderTargetSource.java
@@ -34,9 +34,11 @@
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Texture;
-public class FGRenderTargetSource extends FGSource{
+public class FGRenderTargetSource extends AbstractFGSource {
+
RenderTargetSourceProxy renderTargetSourceProxy;
- public final static class RenderTargetSourceProxy extends FGBindable{
+
+ public final static class RenderTargetSourceProxy implements FGBindable {
FrameBuffer.FrameBufferTextureTarget renderTarget;
public RenderTargetSourceProxy(FrameBuffer.FrameBufferTextureTarget renderTarget) {
@@ -58,6 +60,10 @@ public FrameBuffer.FrameBufferTextureTarget getRenderTarget() {
public Texture getShaderResource(){
return renderTarget.getTexture();
}
+
+ @Override
+ public void bind(FGRenderContext renderContext) {}
+
}
public FGRenderTargetSource(String name, FrameBuffer.FrameBufferTextureTarget renderTarget) {
super(name);
@@ -73,4 +79,5 @@ public void postLinkValidate() {
public FGBindable yieldBindable() {
return renderTargetSourceProxy;
}
+
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSink.java
index c073ce04b8..13fcf40f89 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSink.java
@@ -1,76 +1,33 @@
/*
- * Copyright (c) 2009-2023 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.
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Interface.java to edit this template
*/
package com.jme3.renderer.framegraph;
/**
*
- * @author JohnKkk
+ * @author codex
*/
-public abstract class FGSink {
- private String registeredName;
- private String linkPassName;
- private String linkPassResName;
- protected boolean bIsRequired = false;
- // Always validate?
- protected boolean bLinkValidate = false;
- protected FGSink(String registeredName){
- this.registeredName = registeredName;
- }
+public interface FGSink {
+
+ public boolean isRequired();
- public boolean isRequired() {
- return bIsRequired;
- }
+ public String getRegisteredName();
- public String getRegisteredName() {
- return registeredName;
- }
+ public String getLinkPassName();
- public String getLinkPassName() {
- return linkPassName;
- }
-
- public String getLinkPassResName() {
- return linkPassResName;
- }
+ public String getLinkPassResName();
- public void setTarget(String inPassName, String inPassResName){
- linkPassName = inPassName;
- linkPassResName = inPassResName;
- }
- public abstract void bind(FGSource fgSource);
- public abstract void postLinkValidate();
+ public void setTarget(String inPassName, String inPassResName);
+
+ public void bind(FGSource fgSource);
+
+ public void postLinkValidate();
- public boolean isLinkValidate() {
- return bLinkValidate;
+ public boolean isLinkValidate();
+
+ public default FGBindable getBind() {
+ return null;
}
- public FGBindable getBind(){return null;}
+
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSource.java
index cdf9ad3c19..a8d51dc68c 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSource.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGSource.java
@@ -1,49 +1,19 @@
/*
- * Copyright (c) 2009-2023 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.
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package com.jme3.renderer.framegraph;
/**
*
- * @author JohnKkk
+ * @author codex
*/
-public abstract class FGSource {
- private String name;
- public FGSource(String name){
- this.name = name;
- }
-
- public String getName() {
- return name;
- }
+public interface FGSource {
+
+ public String getName();
+
public abstract void postLinkValidate();
+
public abstract FGBindable yieldBindable();
+
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java
index 798aab91d8..5d56d47a03 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java
@@ -39,7 +39,7 @@
public class FGTextureBindableSink extends FGContainerBindableSink{
private Material material;
private TextureBindableProxy textureBindableProxy;
- private static class TextureBindableProxy extends FGBindable{
+ private static class TextureBindableProxy implements FGBindable{
Material material;
VarType bindTextureType;
Object bindValue;
@@ -57,7 +57,6 @@ public final void setValue(Object value){
@Override
public void bind(FGRenderContext renderContext) {
- super.bind(renderContext);
if(material != null && bindName != null){
this.material.setParam(bindName, bindTextureType, bindValue);
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java
index 5ee2d24575..51eabbd709 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java
@@ -35,8 +35,10 @@
* @author JohnKkk
* @param
*/
-public class FGVarSource extends FGSource{
- public static class FGVarBindableProxy extends FGBindable{
+public class FGVarSource extends AbstractFGSource {
+
+ public static class FGVarBindableProxy implements FGBindable {
+
T value;
public FGVarBindableProxy(T value) {
@@ -46,11 +48,17 @@ public FGVarBindableProxy(T value) {
public T getValue() {
return value;
}
+
+ @Override
+ public void bind(FGRenderContext renderContext) {}
+
}
- private FGVarBindableProxy varBindableProxy;
+
+ private final FGVarBindableProxy varBindableProxy;
+
public FGVarSource(String name, T value) {
super(name);
- varBindableProxy = new FGVarBindableProxy(value);
+ varBindableProxy = new FGVarBindableProxy<>(value);
}
public void setValue(T t){
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
index 0f3db8e0df..9a4f738467 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
@@ -52,6 +52,7 @@
* @author JohnKkk
*/
public class FrameGraph {
+
private static final Logger logger = Logger.getLogger(FrameGraph.class.getName());
private ArrayList passes;
private ArrayList globalSources;
@@ -60,9 +61,9 @@ public class FrameGraph {
private FGRenderContext renderContext;
public FrameGraph(FGRenderContext renderContext){
- passes = new ArrayList();
- globalSinks = new ArrayList();
- globalSources = new ArrayList();
+ passes = new ArrayList<>();
+ globalSinks = new ArrayList<>();
+ globalSources = new ArrayList<>();
this.renderContext = renderContext;
}
@@ -151,13 +152,14 @@ protected void linkSinks(FGPass pass){
/**
* Execute frameGraph
*
- * example:
- * FrameGraph fg = new FrameGraph();
- * fg.addPass(pass1);
- * fg.addPass(pass2);
- * fg.finalize();
- * fg.execute();
- *
+ * example:
+ *
+ * FrameGraph fg = new FrameGraph();
+ * fg.addPass(pass1);
+ * fg.addPass(pass2);
+ * fg.finalize();
+ * fg.execute();
+ *
*/
public void execute(){
assert finalized;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataProxy.java b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataProxy.java
index 3aa114a24c..813b09a920 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataProxy.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataProxy.java
@@ -6,6 +6,7 @@
import com.jme3.light.LightList;
import com.jme3.renderer.framegraph.FGBindable;
+import com.jme3.renderer.framegraph.FGRenderContext;
/**
*
@@ -22,5 +23,8 @@ public DeferredLightDataProxy(LightList lightData) {
public LightList getLightData() {
return lightData;
}
+
+ @Override
+ public void bind(FGRenderContext renderContext) {}
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataSource.java b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataSource.java
index ed678d5382..cb20f8573a 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataSource.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataSource.java
@@ -33,9 +33,10 @@
import com.jme3.light.LightList;
import com.jme3.renderer.framegraph.FGBindable;
-import com.jme3.renderer.framegraph.FGSource;
+import com.jme3.renderer.framegraph.FGRenderContext;
+import com.jme3.renderer.framegraph.AbstractFGSource;
-public class DeferredLightDataSource extends FGSource {
+public class DeferredLightDataSource extends AbstractFGSource {
DeferredLightDataProxy deferredLightDataProxy;
@@ -54,7 +55,7 @@ public FGBindable yieldBindable() {
return deferredLightDataProxy;
}
- public static class DeferredLightDataProxy extends FGBindable {
+ public static class DeferredLightDataProxy implements FGBindable {
private LightList lightData;
@@ -66,6 +67,9 @@ public LightList getLightData() {
return lightData;
}
+ @Override
+ public void bind(FGRenderContext renderContext) {}
+
}
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessorPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessorPass.java
index e218b14998..3ff7c5d536 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessorPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessorPass.java
@@ -33,14 +33,15 @@
import com.jme3.post.SceneProcessor;
import com.jme3.renderer.ViewPort;
-import com.jme3.renderer.framegraph.FGPass;
+import com.jme3.renderer.framegraph.AbstractFGPass;
import com.jme3.renderer.framegraph.FGRenderContext;
import com.jme3.util.SafeArrayList;
/**
* @author JohnKkk
*/
-public class PostProcessorPass extends FGPass {
+public class PostProcessorPass extends AbstractFGPass {
+
public PostProcessorPass(String name) {
super(name);
}
@@ -59,4 +60,8 @@ public void execute(FGRenderContext renderContext) {
// if (prof != null) prof.vpStep(VpStep.ProcEndRender, vp, null);
}
}
+
+ @Override
+ public void prepare(FGRenderContext renderContext) {}
+
}
From 1be8dabfc81a9153305b348ffd12e1617e98ce67 Mon Sep 17 00:00:00 2001
From: codex <103840984+codex128@users.noreply.github.com>
Date: Thu, 18 Apr 2024 09:24:08 -0400
Subject: [PATCH 030/111] fix method name collision for FGPass
---
.../java/com/jme3/renderer/framegraph/AbstractFGPass.java | 5 +----
.../src/main/java/com/jme3/renderer/framegraph/FGPass.java | 5 +----
.../main/java/com/jme3/renderer/framegraph/FrameGraph.java | 2 +-
3 files changed, 3 insertions(+), 9 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java
index fd61b9092c..55acdbdc22 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java
@@ -135,10 +135,7 @@ public void reset() {
}
@Override
- public void finalize() {
- // WARNING:
- // This method's name conflicts with Object.finalize. I am not sure if
- // that is on purpose, so I will not attempt to change it.
+ public void finalizePass() {
for(FGSink sink : sinks){
sink.postLinkValidate();
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
index b0ef96cb49..4e3271d2c4 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
@@ -36,9 +36,6 @@ public interface FGPass {
public void reset();
- // WARNING:
- // This method's name conflicts with Object.finalize. I am not sure if
- // that is on purpose, so I will not attempt to change it.
- public void finalize();
+ public void finalizePass();
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
index 9a4f738467..ccfcb973d8 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
@@ -270,7 +270,7 @@ public final FGPass findPassByName(String name){
public final void finalize(){
assert !finalized;
for(FGPass nextPass : passes){
- nextPass.finalize();
+ nextPass.finalizePass();
}
linkGlobalSinks();
finalized = true;
From 6247f73ac6f2539d5959d9fc0b63ab6a69a05c97 Mon Sep 17 00:00:00 2001
From: codex <103840984+codex128@users.noreply.github.com>
Date: Thu, 18 Apr 2024 09:28:54 -0400
Subject: [PATCH 031/111] renamed FGPass reset method
---
.../java/com/jme3/renderer/framegraph/AbstractFGPass.java | 2 +-
.../java/com/jme3/renderer/framegraph/FGBindingPass.java | 6 ++++--
.../src/main/java/com/jme3/renderer/framegraph/FGPass.java | 5 +++--
.../com/jme3/renderer/framegraph/FGRenderQueuePass.java | 4 ++--
.../main/java/com/jme3/renderer/framegraph/FrameGraph.java | 2 +-
.../src/main/java/com/jme3/renderer/pass/GBufferPass.java | 4 ++--
.../renderpath/TestPBRTerrainAdvancedRenderPath.java | 4 ++--
7 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java
index 55acdbdc22..bdee9ce1f9 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java
@@ -127,7 +127,7 @@ public void registerSource(FGSource source) {
}
@Override
- public void reset() {
+ public void resetPass() {
if(isResetResources()){
getSources().clear();
getSinks().clear();
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java
index ce1f377480..0eea3a33be 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java
@@ -34,7 +34,9 @@
import java.util.ArrayList;
/**
- *A FGBindingPass represents a Pass that needs to perform state machine binding, ShaderResource binding, FrameBuffer binding and other operations.
+ * A FGBindingPass represents a Pass that needs to perform state machine binding,
+ * ShaderResource binding, FrameBuffer binding or similar operations.
+ *
* @author JohnKkk
*/
public class FGBindingPass extends AbstractFGPass {
@@ -53,7 +55,7 @@ public void addBind(FGBindable bind){
binds.add(bind);
}
- public void addBindSink(String name){
+ public void addBindSink(String name){
int index = binds.size() - 1;
registerSink(new FGContainerBindableSink(name, binds, index));
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
index 4e3271d2c4..617bc64226 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
@@ -7,7 +7,8 @@
import java.util.ArrayList;
/**
- *
+ * Defines a rendering pass made by the framegraph.
+ *
* @author codex
*/
public interface FGPass {
@@ -34,7 +35,7 @@ public interface FGPass {
public void registerSource(FGSource source);
- public void reset();
+ public void resetPass();
public void finalizePass();
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java
index dbd5ad6916..59ba0dd876 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java
@@ -90,8 +90,8 @@ public void execute(FGRenderContext renderContext) {
public abstract void executeDrawCommandList(FGRenderContext renderContext);
@Override
- public void reset() {
- super.reset();
+ public void resetPass() {
+ super.resetPass();
if(passMeshDrawCommandList != null && passMeshDrawCommandList.size() > 0){
passMeshDrawCommandList.clear();
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
index ccfcb973d8..d61f9cd25e 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
@@ -176,7 +176,7 @@ public void execute(){
public void reset(){
assert !finalized;
for(FGPass nextPass : passes){
- nextPass.reset();
+ nextPass.resetPass();
}
passes.clear();
if(renderContext != null && renderContext.renderManager != null){
diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferPass.java
index 9344fec975..3e086d6fa7 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferPass.java
@@ -121,8 +121,8 @@ public void executeDrawCommandList(FGRenderContext renderContext) {
}
@Override
- public void reset() {
- super.reset();
+ public void resetPass() {
+ super.resetPass();
tempLights.clear();
lightData.clear();
bHasDraw = false;
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java
index 9167e4685d..cb9403624c 100644
--- a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java
@@ -449,8 +449,8 @@ private void setUpLights() {
directionalLight.setColor(ColorRGBA.White);
rootNode.addLight(directionalLight);
- for (int i = 0; i < 40; i++) {
- for (int j = 0; j < 40; j++) {
+ for (int i = 0; i < 30; i++) {
+ for (int j = 0; j < 30; j++) {
PointLight p = new PointLight();
p.setPosition(new Vector3f(-50+i*10, -60, -50+j*10));
p.setRadius(50);
From df9c4b93124f4158f339b68f8d2d1bf99c7a92ff Mon Sep 17 00:00:00 2001
From: codex <103840984+codex128@users.noreply.github.com>
Date: Thu, 18 Apr 2024 12:57:20 -0400
Subject: [PATCH 032/111] changes
---
CodexChangeLog.txt | 4 +
.../java/com/jme3/renderer/RenderManager.java | 159 ++++++++----------
.../renderer/framegraph/AbstractFGPass.java | 9 +-
.../renderer/framegraph/AbstractFGSink.java | 2 +-
.../framegraph/DeferredFrameGraph.java | 13 ++
.../framegraph/FGContainerBindableSink.java | 1 +
.../FGFramebufferCopyBindableSink.java | 23 ++-
.../com/jme3/renderer/framegraph/FGPass.java | 2 +-
.../renderer/framegraph/FGRenderContext.java | 52 ++++--
.../framegraph/FGRenderQueuePass.java | 8 +-
.../framegraph/FGTextureBindableSink.java | 10 +-
.../jme3/renderer/framegraph/FrameGraph.java | 86 ++++++----
...fferSource.java => FramebufferSource.java} | 4 +-
.../renderer/framegraph/GraphBuilder.java | 15 ++
.../renderer/pass/DeferredLightDataSink.java | 3 +-
.../renderer/pass/DeferredShadingPass.java | 22 +--
.../com/jme3/renderer/pass/ForwardPass.java | 15 +-
.../com/jme3/renderer/pass/GBufferPass.java | 129 ++++++--------
.../java/com/jme3/renderer/pass/GuiPass.java | 6 +-
.../jme3/renderer/pass/PostProcessorPass.java | 8 +-
.../renderer/pass/ResolveSceneColorPass.java | 7 +-
.../pass/TileDeferredShadingPass.java | 11 +-
.../TestPBRTerrainAdvancedRenderPath.java | 2 +
.../renderpath/sandbox/CustomPass.java | 32 ++++
.../renderpath/sandbox/FrameGraphSandbox.java | 20 +++
25 files changed, 368 insertions(+), 275 deletions(-)
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredFrameGraph.java
rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{FGFramebufferSource.java => FramebufferSource.java} (94%)
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphBuilder.java
create mode 100644 jme3-examples/src/main/java/jme3test/renderpath/sandbox/CustomPass.java
create mode 100644 jme3-examples/src/main/java/jme3test/renderpath/sandbox/FrameGraphSandbox.java
diff --git a/CodexChangeLog.txt b/CodexChangeLog.txt
index b28b04f643..6084df7ae7 100644
--- a/CodexChangeLog.txt
+++ b/CodexChangeLog.txt
@@ -1,3 +1,7 @@
+TileBasedDeferredSinglePassLightingLogic.java:
+* Fixed syntax error.
+* Added exception when accumulated light sources exceeds maximum.
+* Fixed check for tile demension changes so that demensions are not reset every frame.
diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
index 25d8b4f2c6..2c4ebb2397 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
@@ -85,6 +85,7 @@
* @see Spatial
*/
public class RenderManager {
+
// Maximum total number of light sources for deferred rendering
private int maxDeferredLights = 1024;
// TileInfo
@@ -170,7 +171,7 @@ public RenderManager(Renderer renderer) {
this.renderer = renderer;
this.forcedOverrides.add(boundDrawBufferId);
if(useFramegraph){
- frameGraph = new FrameGraph(new FGRenderContext(null, null, null));
+ frameGraph = new FrameGraph(new FGRenderContext(this, null));
gBufferPass = new GBufferPass();
deferredShadingPass = new DeferredShadingPass();
tileDeferredShadingPass = new TileDeferredShadingPass();
@@ -1339,85 +1340,92 @@ public void renderViewPort(ViewPort vp, float tpf) {
if (!vp.isEnabled()) {
return;
}
+
+ if (prof != null) {
+ prof.vpStep(VpStep.BeginRender, vp, null);
+ }
- if(useFramegraph){
- RenderPath curRenderPath = vp.getRenderPath() == RenderPath.None ? renderPath : vp.getRenderPath();
-
- if (prof!=null) prof.vpStep(VpStep.BeginRender, vp, null);
+ SafeArrayList processors = vp.getProcessors();
+ if (processors.isEmpty()) {
+ processors = null;
+ }
- SafeArrayList processors = vp.getProcessors();
- if (processors.isEmpty()) {
- processors = null;
+ if (processors != null) {
+ if (prof != null) {
+ prof.vpStep(VpStep.PreFrame, vp, null);
}
-
- if (processors != null) {
- if (prof != null) prof.vpStep(VpStep.PreFrame, vp, null);
- for (SceneProcessor proc : processors.getArray()) {
- if (!proc.isInitialized()) {
- proc.initialize(this, vp);
- }
- proc.setProfiler(this.prof);
- if (prof != null) prof.spStep(SpStep.ProcPreFrame, proc.getClass().getSimpleName());
- proc.preFrame(tpf);
+ for (SceneProcessor proc : processors.getArray()) {
+ if (!proc.isInitialized()) {
+ proc.initialize(this, vp);
+ }
+ proc.setProfiler(this.prof);
+ if (prof != null) {
+ prof.spStep(SpStep.ProcPreFrame, proc.getClass().getSimpleName());
}
+ proc.preFrame(tpf);
}
+ }
- renderer.setFrameBuffer(vp.getOutputFrameBuffer());
- setCamera(vp.getCamera(), false);
- if (vp.isClearDepth() || vp.isClearColor() || vp.isClearStencil()) {
- if (vp.isClearColor()) {
- renderer.setBackgroundColor(vp.getBackgroundColor());
- }
- renderer.clearBuffers(vp.isClearColor(),
- vp.isClearDepth(),
- vp.isClearStencil());
+ renderer.setFrameBuffer(vp.getOutputFrameBuffer());
+ setCamera(vp.getCamera(), false);
+ if (vp.isClearDepth() || vp.isClearColor() || vp.isClearStencil()) {
+ if (vp.isClearColor()) {
+ renderer.setBackgroundColor(vp.getBackgroundColor());
}
+ renderer.clearBuffers(vp.isClearColor(), vp.isClearDepth(), vp.isClearStencil());
+ }
+
+ if(useFramegraph){
+ RenderPath curRenderPath = vp.getRenderPath() == RenderPath.None ? renderPath : vp.getRenderPath();
- if (prof!=null) prof.vpStep(VpStep.RenderScene, vp, null);
+ if (prof != null) {
+ prof.vpStep(VpStep.RenderScene, vp, null);
+ }
List scenes = vp.getScenes();
for (int i = scenes.size() - 1; i >= 0; i--) {
renderScene(scenes.get(i), vp);
}
if (processors != null) {
- if (prof!=null) prof.vpStep(VpStep.PostQueue, vp, null);
- for (SceneProcessor proc : processors.getArray()) {
- if (prof != null) prof.spStep(SpStep.ProcPostQueue, proc.getClass().getSimpleName());
- proc.postQueue(vp.getQueue());
+ if (prof != null) {
+ prof.vpStep(VpStep.PostQueue, vp, null);
+ }
+ for (SceneProcessor p : processors.getArray()) {
+ if (prof != null) {
+ prof.spStep(SpStep.ProcPostQueue, p.getClass().getSimpleName());
+ }
+ p.postQueue(vp.getQueue());
}
}
frameGraph.reset();
- frameGraph.getRenderContext().renderManager = this;
- frameGraph.getRenderContext().renderQueue = vp.getQueue();
- frameGraph.getRenderContext().viewPort = vp;
-
- if(curRenderPath == RenderPath.Deferred){
+ frameGraph.getRenderContext().setViewPort(vp);
+
+ if (curRenderPath == RenderPath.Deferred) {
frameGraph.addPass(gBufferPass);
- deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_0, gBufferPass.getName() + "." + GBufferPass.S_RT_0);
- deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_1, gBufferPass.getName() + "." + GBufferPass.S_RT_1);
- deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_2, gBufferPass.getName() + "." + GBufferPass.S_RT_2);
- deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_3, gBufferPass.getName() + "." + GBufferPass.S_RT_3);
- deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_4, gBufferPass.getName() + "." + GBufferPass.S_RT_4);
- deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_LIGHT_DATA, gBufferPass.getName() + "." + GBufferPass.S_LIGHT_DATA);
- deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_EXECUTE_STATE, gBufferPass.getName() + "." + GBufferPass.S_EXECUTE_STATE);
- deferredShadingPass.setSinkLinkage(FGGlobal.S_DEFAULT_FB, gBufferPass.getName() + "." + GBufferPass.S_FB);
+ deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_0, gBufferPass.getName(), GBufferPass.RENDER_TARGETS[0]);
+ deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_1, gBufferPass.getName(), GBufferPass.RENDER_TARGETS[1]);
+ deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_2, gBufferPass.getName(), GBufferPass.RENDER_TARGETS[2]);
+ deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_3, gBufferPass.getName(), GBufferPass.RENDER_TARGETS[3]);
+ deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_4, gBufferPass.getName(), GBufferPass.RENDER_TARGETS[4]);
+ deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_LIGHT_DATA, gBufferPass.getName(), GBufferPass.LIGHT_DATA);
+ deferredShadingPass.setSinkLinkage(DeferredShadingPass.S_EXECUTE_STATE, gBufferPass.getName(), GBufferPass.EXECUTE_STATE);
+ deferredShadingPass.setSinkLinkage(FGGlobal.S_DEFAULT_FB, gBufferPass.getName(), GBufferPass.G_FRAME_BUFFER);
frameGraph.addPass(deferredShadingPass);
- }
- else if(curRenderPath == RenderPath.TiledDeferred){
+ } else if (curRenderPath == RenderPath.TiledDeferred) {
curTileSize = forceTileSize > 0 ? forceTileSize : (getCurrentCamera().getWidth() / numberTileDivisions);
int tileWidth = (int)(viewWidth / curTileSize);
int tileHeight = (int)(viewHeight / curTileSize);
setTileInfo(curTileSize, tileWidth, tileHeight, tileWidth * tileHeight);
frameGraph.addPass(gBufferPass);
- tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_0, gBufferPass.getName() + "." + GBufferPass.S_RT_0);
- tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_1, gBufferPass.getName() + "." + GBufferPass.S_RT_1);
- tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_2, gBufferPass.getName() + "." + GBufferPass.S_RT_2);
- tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_3, gBufferPass.getName() + "." + GBufferPass.S_RT_3);
- tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_4, gBufferPass.getName() + "." + GBufferPass.S_RT_4);
- tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_LIGHT_DATA, gBufferPass.getName() + "." + GBufferPass.S_LIGHT_DATA);
- tileDeferredShadingPass.setSinkLinkage(FGGlobal.S_DEFAULT_FB, gBufferPass.getName() + "." + GBufferPass.S_FB);
- tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_EXECUTE_STATE, gBufferPass.getName() + "." + GBufferPass.S_EXECUTE_STATE);
+ tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_0, gBufferPass.getName(), GBufferPass.RENDER_TARGETS[0]);
+ tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_1, gBufferPass.getName(), GBufferPass.RENDER_TARGETS[1]);
+ tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_2, gBufferPass.getName(), GBufferPass.RENDER_TARGETS[2]);
+ tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_3, gBufferPass.getName(), GBufferPass.RENDER_TARGETS[3]);
+ tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_RT_4, gBufferPass.getName(), GBufferPass.RENDER_TARGETS[4]);
+ tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_LIGHT_DATA, gBufferPass.getName(), GBufferPass.LIGHT_DATA);
+ tileDeferredShadingPass.setSinkLinkage(FGGlobal.S_DEFAULT_FB, gBufferPass.getName(), GBufferPass.G_FRAME_BUFFER);
+ tileDeferredShadingPass.setSinkLinkage(DeferredShadingPass.S_EXECUTE_STATE, gBufferPass.getName(), GBufferPass.EXECUTE_STATE);
frameGraph.addPass(tileDeferredShadingPass);
}
frameGraph.addPass(opaquePass);
@@ -1438,49 +1446,14 @@ else if(curRenderPath == RenderPath.TiledDeferred){
//renders the translucent objects queue after processors have been rendered
frameGraph.addPass(translucentPass);
- frameGraph.finalize();
+ frameGraph.finalizePasses();
frameGraph.execute();
// clear any remaining spatials that were not rendered.
clearQueue(vp);
if (prof!=null) prof.vpStep(VpStep.EndRender, vp, null);
- }
- else{
- if (prof != null) {
- prof.vpStep(VpStep.BeginRender, vp, null);
- }
-
- SafeArrayList processors = vp.getProcessors();
- if (processors.isEmpty()) {
- processors = null;
- }
-
- if (processors != null) {
- if (prof != null) {
- prof.vpStep(VpStep.PreFrame, vp, null);
- }
- for (SceneProcessor proc : processors.getArray()) {
- if (!proc.isInitialized()) {
- proc.initialize(this, vp);
- }
- proc.setProfiler(this.prof);
- if (prof != null) {
- prof.spStep(SpStep.ProcPreFrame, proc.getClass().getSimpleName());
- }
- proc.preFrame(tpf);
- }
- }
-
- renderer.setFrameBuffer(vp.getOutputFrameBuffer());
- setCamera(vp.getCamera(), false);
- if (vp.isClearDepth() || vp.isClearColor() || vp.isClearStencil()) {
- if (vp.isClearColor()) {
- renderer.setBackgroundColor(vp.getBackgroundColor());
- }
- renderer.clearBuffers(vp.isClearColor(),
- vp.isClearDepth(),
- vp.isClearStencil());
- }
+
+ } else {
if (prof != null) {
prof.vpStep(VpStep.RenderScene, vp, null);
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java
index bdee9ce1f9..2e0b75b74b 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java
@@ -93,13 +93,8 @@ public FGSink getSink(String registeredName) {
}
@Override
- public void setSinkLinkage(String registeredName, String target){
- FGSink sink = getSink(registeredName);
- String targetSplit[] = target.split("\\.");
- if(targetSplit.length != 2){
- System.err.println("Input target has incorrect format");
- }
- sink.setTarget(targetSplit[0], targetSplit[1]);
+ public void setSinkLinkage(String registeredName, String targetPass, String targetResource) {
+ getSink(registeredName).setTarget(targetPass, targetResource);
}
@Override
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGSink.java
index 49fb641e05..f3d0bd18ea 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGSink.java
@@ -37,7 +37,7 @@
*/
public abstract class AbstractFGSink implements FGSink {
- private String registeredName;
+ private final String registeredName;
private String linkPassName;
private String linkPassResName;
protected boolean bIsRequired = false;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredFrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredFrameGraph.java
new file mode 100644
index 0000000000..13729029fe
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredFrameGraph.java
@@ -0,0 +1,13 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package com.jme3.renderer.framegraph;
+
+/**
+ *
+ * @author codex
+ */
+public class DeferredFrameGraph {
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java
index a097a51a42..5134ad7295 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java
@@ -42,6 +42,7 @@
* @param
*/
public class FGContainerBindableSink extends AbstractFGSink {
+
protected boolean linked = false;
protected ArrayList container;
protected int index;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java
index f0e10daba3..15535224f9 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java
@@ -39,11 +39,10 @@
* @author JohnKkk
* @param
*/
-public class FGFramebufferCopyBindableSink extends FGContainerBindableSink {
- FramebufferCopyBindableProxy framebufferCopyBindableProxy;
- public final void setDistFrameBuffer(FrameBuffer distFrameBuffer){
- framebufferCopyBindableProxy.distFramebuffer = distFrameBuffer;
- }
+public class FGFramebufferCopyBindableSink extends FGContainerBindableSink {
+
+ private FramebufferCopyBindableProxy framebufferCopyBindableProxy;
+
public FGFramebufferCopyBindableSink(String registeredName, FrameBuffer distFrameBuffer, boolean copyColor, boolean copyDepth, boolean copyStencil, ArrayList container, int index) {
super(registeredName, container, index);
framebufferCopyBindableProxy = new FramebufferCopyBindableProxy(distFrameBuffer, copyColor, copyDepth, copyStencil);
@@ -70,10 +69,16 @@ public void setSourceFramebuffer(FrameBuffer sourceFramebuffer) {
@Override
public void bind(FGRenderContext renderContext) {
if(this.distFramebuffer != null || this.sourceFramebuffer != null){
- renderContext.renderManager.getRenderer().copyFrameBuffer(this.sourceFramebuffer, this.distFramebuffer != null ? this.distFramebuffer : renderContext.viewPort.getOutputFrameBuffer(), bCopyColor, bCopyDepth || bCopyStencil);
+ renderContext.getRenderer().copyFrameBuffer(this.sourceFramebuffer,
+ (this.distFramebuffer != null ? this.distFramebuffer : renderContext.getViewPort().getOutputFrameBuffer()),
+ bCopyColor, bCopyDepth || bCopyStencil);
}
}
}
+
+ public final void setDistFrameBuffer(FrameBuffer distFrameBuffer){
+ framebufferCopyBindableProxy.distFramebuffer = distFrameBuffer;
+ }
@Override
public void bind(FGSource fgSource) {
@@ -82,10 +87,10 @@ public void bind(FGSource fgSource) {
System.err.println("Binding input [" + getRegisteredName() + "] to output [" + getLinkPassName() + "." + getLinkPassResName() + "] " + " { " + fgSource.getName() + " } ");
return;
}
- if(fgSource instanceof FGFramebufferSource){
+ if(fgSource instanceof FramebufferSource){
linked = true;
- FGFramebufferSource framebufferSource = (FGFramebufferSource)fgSource;
- framebufferCopyBindableProxy.setSourceFramebuffer(((FGFramebufferSource.FrameBufferSourceProxy)framebufferSource.yieldBindable()).getFrameBuffer());
+ FramebufferSource framebufferSource = (FramebufferSource)fgSource;
+ framebufferCopyBindableProxy.setSourceFramebuffer(((FramebufferSource.FrameBufferSourceProxy)framebufferSource.yieldBindable()).getFrameBuffer());
bindableProxy.targetBindable = framebufferCopyBindableProxy;
}
else{
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
index 617bc64226..7fe5c90d7b 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
@@ -29,7 +29,7 @@ public interface FGPass {
public FGSink getSink(String registeredName);
- public void setSinkLinkage(String registeredName, String target);
+ public void setSinkLinkage(String registeredName, String targetPass, String targetResource);
public void registerSink(AbstractFGSink sink);
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java
index 57821553db..cc0bf5ce6e 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderContext.java
@@ -32,6 +32,7 @@
package com.jme3.renderer.framegraph;
import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue;
@@ -40,30 +41,59 @@
* @author JohnKkk
*/
public class FGRenderContext {
- // PSO
- public static class FGPipelineObjectState{
+
+ protected static class FGPipelineObjectState {
+
public float startDepth;
public float endDepth;
+
+ public FGPipelineObjectState(float startDepth, float endDepth) {
+ this.startDepth = startDepth;
+ this.endDepth = endDepth;
+ }
+
}
- public RenderManager renderManager;
- public RenderQueue renderQueue;
- public ViewPort viewPort;
+ private final RenderManager renderManager;
+ private ViewPort viewPort;
protected FGPipelineObjectState currentPSO;
- public FGRenderContext(RenderManager renderManager, RenderQueue renderQueue, ViewPort viewPort) {
+ public FGRenderContext(RenderManager renderManager, ViewPort viewPort) {
this.renderManager = renderManager;
- this.renderQueue = renderQueue;
this.viewPort = viewPort;
- currentPSO = new FGPipelineObjectState();
- currentPSO.startDepth = 0;
- currentPSO.endDepth = 1;
+ currentPSO = new FGPipelineObjectState(0, 1);
}
- public final void setDepthRange(float start, float end){
+
+ public void setDepthRange(float start, float end){
if(currentPSO.startDepth != start || currentPSO.endDepth != end){
renderManager.getRenderer().setDepthRange(start, end);
currentPSO.startDepth = start;
currentPSO.endDepth = end;
}
}
+
+ public void setViewPort(ViewPort viewPort) {
+ this.viewPort = viewPort;
+ }
+
+ public RenderManager getRenderManager() {
+ return renderManager;
+ }
+
+ public ViewPort getViewPort() {
+ return viewPort;
+ }
+
+ public Renderer getRenderer() {
+ return renderManager.getRenderer();
+ }
+
+ public RenderQueue getRenderQueue() {
+ if (viewPort != null) {
+ return viewPort.getQueue();
+ } else {
+ return null;
+ }
+ }
+
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java
index 59ba0dd876..c632b8aff1 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java
@@ -67,10 +67,10 @@ public void setForceViewPort(ViewPort forceViewPort) {
@Override
public void execute(FGRenderContext renderContext) {
- renderContext.renderManager.setRenderGeometryHandler(this);
- dispatchPassSetup(renderContext.renderQueue);
+ renderContext.getRenderManager().setRenderGeometryHandler(this);
+ dispatchPassSetup(renderContext.getRenderQueue());
if(!canExecute){
- renderContext.renderManager.setRenderGeometryHandler(null);
+ renderContext.getRenderManager().setRenderGeometryHandler(null);
return;
}
bindAll(renderContext);
@@ -80,7 +80,7 @@ public void execute(FGRenderContext renderContext) {
// drawcall
}
executeDrawCommandList(renderContext);
- renderContext.renderManager.setRenderGeometryHandler(null);
+ renderContext.getRenderManager().setRenderGeometryHandler(null);
}
/**
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java
index 5d56d47a03..be07de4a4b 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java
@@ -33,13 +33,15 @@
import com.jme3.material.Material;
import com.jme3.shader.VarType;
-
import java.util.ArrayList;
-public class FGTextureBindableSink extends FGContainerBindableSink{
+public class FGTextureBindableSink extends FGContainerBindableSink {
+
private Material material;
private TextureBindableProxy textureBindableProxy;
- private static class TextureBindableProxy implements FGBindable{
+
+ private static class TextureBindableProxy implements FGBindable {
+
Material material;
VarType bindTextureType;
Object bindValue;
@@ -61,7 +63,9 @@ public void bind(FGRenderContext renderContext) {
this.material.setParam(bindName, bindTextureType, bindValue);
}
}
+
}
+
public FGTextureBindableSink(String registeredName, ArrayList container, int index, Material material, VarType bindTextureType) {
super(registeredName, container, index);
this.material = material;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
index d61f9cd25e..2dbed3a29d 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
@@ -36,31 +36,43 @@
import java.util.logging.Logger;
/**
- * The FrameGraph system is used to manage render passes and the dependencies between them in a declarative way. Some key aspects:
- * - It represents the rendering pipeline as a directed acyclic graph of passes and their inputs/outputs.
- * - Passes can be things like shadow map creation, geometry passes, post-processing etc.
- * - Outputs from one pass can be reused as inputs to others, avoiding redundant work.
- * - The FrameGraph handles synchronization, pass scheduling and resource transitions automatically based on dependencies.
- * - Developers define passes and connect inputs/outputs, while the system handles execution.
- * - Passes can have arbitrary Java logic, shaders, and framebuffer configurations.
- * - Framebuffers are created on demand based on pass requirements.
- * - FrameGraphRecursion queues allow recursive pass execution (e.g. for nested realtime reflections).
- * - The system optimizes what needs to run each frame based on dirty state.
- * In summary, FrameGraph enables declaring a rendering pipeline at a high level while handling all the underlying complexity of synchronization, resource management, and efficient execution. This simplifies the developer's job and avoids boilerplate code.
- * The key advantages are automatic input/output reuse, efficient scheduling and batching, simplified boilerplate, and handling advanced cases like recursions. Overall it provides a clean abstraction for building complex, efficient rendering pipelines.
- * https://www.gdcvault.com/play/1024612/FrameGraph-Extensible-Rendering-Architecture-in.
+ * The FrameGraph system is used to manage render passes and the dependencies between them in a declarative way.
+ *
+ * Some key aspects:
+ *
+ * - It represents the rendering pipeline as a directed acyclic graph of passes and their inputs/outputs.
+ *
- Passes can be things like shadow map creation, geometry passes, post-processing etc.
+ *
- Outputs from one pass can be reused as inputs to others, avoiding redundant work.
+ *
- The FrameGraph handles synchronization, pass scheduling and resource transitions automatically based on dependencies.
+ *
- Developers define passes and connect inputs/outputs, while the system handles execution.
+ *
- Passes can have arbitrary Java logic, shaders, and framebuffer configurations.
+ *
- Framebuffers are created on demand based on pass requirements.
+ *
- FrameGraphRecursion queues allow recursive pass execution (e.g. for nested realtime reflections).
+ *
- The system optimizes what needs to run each frame based on dirty state.
+ *
+ * In summary, FrameGraph enables declaring a rendering pipeline at a high level while handling all the
+ * underlying complexity of synchronization, resource management, and efficient execution. This simplifies
+ * the developer's job and avoids boilerplate code.
+ *
+ * The key advantages are automatic input/output reuse, efficient scheduling and batching, simplified boilerplate,
+ * and handling advanced cases like recursions. Overall it provides a clean abstraction for building complex,
+ * efficient rendering pipelines.
+ *
+ * https://www.gdcvault.com/play/1024612/FrameGraph-Extensible-Rendering-Architecture-in.>For more information
+ *
* @author JohnKkk
*/
public class FrameGraph {
private static final Logger logger = Logger.getLogger(FrameGraph.class.getName());
- private ArrayList passes;
- private ArrayList globalSources;
- private ArrayList globalSinks;
+
+ private final FGRenderContext renderContext;
+ private final ArrayList passes;
+ private final ArrayList globalSources;
+ private final ArrayList globalSinks;
private boolean finalized = false;
- private FGRenderContext renderContext;
- public FrameGraph(FGRenderContext renderContext){
+ public FrameGraph(FGRenderContext renderContext) {
passes = new ArrayList<>();
globalSinks = new ArrayList<>();
globalSources = new ArrayList<>();
@@ -74,12 +86,12 @@ public FGRenderContext getRenderContext() {
/**
* Binding input resources to the global sink in a FrameGraph refers to making certain resources available globally to all passes.
*/
- protected void linkGlobalSinks(){
+ protected void linkGlobalSinks() {
for(FGSink sink : globalSinks){
String linkPassName = sink.getLinkPassName();
- for(FGPass nextPass : passes){
- if(nextPass.getName().equals(linkPassName)){
- FGSource source = nextPass.getSource(sink.getLinkPassResName());
+ for(FGPass p : passes){
+ if(p.getName().equals(linkPassName)){
+ FGSource source = p.getSource(sink.getLinkPassResName());
sink.bind(source);
break;
}
@@ -91,7 +103,7 @@ protected void linkGlobalSinks(){
* Binding input resources to a specific pass in a FrameGraph refers to connecting the necessary resources that pass requires as inputs.
* @param pass targetPass
*/
- protected void linkSinks(FGPass pass){
+ protected void linkSinks(FGPass pass) {
for(FGSink sink : pass.getSinks()){
String linkPassName = sink.getLinkPassName();
@@ -161,7 +173,7 @@ protected void linkSinks(FGPass pass){
* fg.execute();
*
*/
- public void execute(){
+ public void execute() {
assert finalized;
for(FGPass nextPass : passes){
nextPass.execute(renderContext);
@@ -170,8 +182,14 @@ public void execute(){
}
/**
- * The FrameGraph can be reused by just calling reset() to clear the current graph, then re-adding the required passes and binding the necessary resources again, before calling execute() once more.
- * This allows reusing the same FrameGraph instance to construct different render pipelines, avoiding repeated resource creation. Just update the passes and connections as needed. This improves code reuse and simplifies render pipeline adjustments.
+ * The FrameGraph can be reused by just calling reset() to clear the current graph,
+ * then re-adding the required passes and binding the necessary resources again,
+ * before calling execute() once more.
+ *
+ * This allows reusing the same FrameGraph instance to construct different render
+ * pipelines, avoiding repeated resource creation. Just update the passes and
+ * connections as needed. This improves code reuse and simplifies render pipeline
+ * adjustments.
*/
public void reset(){
assert !finalized;
@@ -179,8 +197,8 @@ public void reset(){
nextPass.resetPass();
}
passes.clear();
- if(renderContext != null && renderContext.renderManager != null){
- renderContext.renderManager.setRenderGeometryHandler(null);
+ if(renderContext != null) {
+ renderContext.getRenderManager().setRenderGeometryHandler(null);
}
}
@@ -211,7 +229,7 @@ public void replaceOrAddGlobalSource(FGSource source){
}
/**
- * A FrameGraph may contain global sinks, such as a backBuffer.
+ * A FrameGraph may contain global sinks, such as a backBuffer.
* @param sink targetFGSink
*/
public void addGlobalSink(FGSink sink){
@@ -233,20 +251,20 @@ public void addGlobalSink(FGSink sink){
* So in summary, add Passes in the desired execution order to the FrameGraph. The FrameGraph system will then handle scheduling them based on resource availability while respecting the original adding order.
* @param pass targetPass
*/
- public final void addPass(FGPass pass){
+ public void addPass(FGPass pass){
assert !finalized;
// validate name uniqueness
for(FGPass nextPass : passes){
if(nextPass.getName().equals(pass.getName())){
- logger.throwing(FrameGraph.class.toString(), "", new NullPointerException("Pass name already exists: " + pass.getName()));
-// System.err.println("Pass name already exists: " + pass.getName());
+ logger.log(Level.WARNING, "Pass name already exists: {0}", pass.getName());
return;
}
}
// link outputs from passes (and global outputs) to pass inputs
- if(pass.getSinks() != null && pass.getSinks().size() > 0)
+ if(pass.getSinks() != null && !pass.getSinks().isEmpty()) {
linkSinks(pass);
+ }
// add to container of passes
pass.prepare(renderContext);
@@ -267,7 +285,7 @@ public final FGPass findPassByName(String name){
/**
* Prepare all passes to get ready for execution of the frameGraph, by calling this function before executing the frameGraph.
*/
- public final void finalize(){
+ public final void finalizePasses(){
assert !finalized;
for(FGPass nextPass : passes){
nextPass.finalizePass();
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FramebufferSource.java
similarity index 94%
rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferSource.java
rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/FramebufferSource.java
index bbfbd91fa3..6a70fa6965 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferSource.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FramebufferSource.java
@@ -36,7 +36,7 @@
/**
* @author JohnKkk
*/
-public class FGFramebufferSource extends AbstractFGSource {
+public class FramebufferSource extends AbstractFGSource {
private final FrameBufferSourceProxy frameBufferSourceProxy;
@@ -55,7 +55,7 @@ public FrameBuffer getFrameBuffer() {
public void bind(FGRenderContext renderContext) {}
}
- public FGFramebufferSource(String name, FrameBuffer frameBuffer) {
+ public FramebufferSource(String name, FrameBuffer frameBuffer) {
super(name);
frameBufferSourceProxy = new FrameBufferSourceProxy(frameBuffer);
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphBuilder.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphBuilder.java
new file mode 100644
index 0000000000..a1d1b97468
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/GraphBuilder.java
@@ -0,0 +1,15 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package com.jme3.renderer.framegraph;
+
+/**
+ *
+ * @author codex
+ */
+public class GraphBuilder {
+
+
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataSink.java b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataSink.java
index 903826b53f..682b40d337 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredLightDataSink.java
@@ -33,10 +33,9 @@
import com.jme3.renderer.framegraph.FGBindable;
import com.jme3.renderer.framegraph.FGContainerBindableSink;
-
import java.util.ArrayList;
-public class DeferredLightDataSink extends FGContainerBindableSink {
+public class DeferredLightDataSink extends FGContainerBindableSink {
public DeferredLightDataSink(String registeredName, ArrayList container, int index) {
super(registeredName, container, index);
diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingPass.java
index ff8724a6d6..b01ff7c1fa 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingPass.java
@@ -67,7 +67,7 @@ public DeferredShadingPass(String name) {
@Override
public void prepare(FGRenderContext renderContext) {
super.prepare(renderContext);
- ViewPort vp = renderContext.viewPort;
+ ViewPort vp = renderContext.getViewPort();
if(forceViewPort != null){
vp = forceViewPort;
}
@@ -89,19 +89,19 @@ public void init() {
screenRect.setMaterial(getMaterial());
// register Sinks
- registerSink(new FGTextureBindableSink(S_RT_0, binds, binds.size(), screenMat, VarType.Texture2D));
- registerSink(new FGTextureBindableSink(S_RT_1, binds, binds.size(), screenMat, VarType.Texture2D));
- registerSink(new FGTextureBindableSink(S_RT_2, binds, binds.size(), screenMat, VarType.Texture2D));
- registerSink(new FGTextureBindableSink(S_RT_3, binds, binds.size(), screenMat, VarType.Texture2D));
- registerSink(new FGTextureBindableSink(S_RT_4, binds, binds.size(), screenMat, VarType.Texture2D));
- registerSink(new DeferredLightDataSink(S_LIGHT_DATA, binds, binds.size()));
- registerSink(new FGVarBindableSink(S_EXECUTE_STATE, binds, binds.size()));
- registerSink(new FGFramebufferCopyBindableSink(FGGlobal.S_DEFAULT_FB, null, false, true, true, binds, binds.size()));
+ registerSink(new FGTextureBindableSink<>(S_RT_0, binds, binds.size(), screenMat, VarType.Texture2D));
+ registerSink(new FGTextureBindableSink<>(S_RT_1, binds, binds.size(), screenMat, VarType.Texture2D));
+ registerSink(new FGTextureBindableSink<>(S_RT_2, binds, binds.size(), screenMat, VarType.Texture2D));
+ registerSink(new FGTextureBindableSink<>(S_RT_3, binds, binds.size(), screenMat, VarType.Texture2D));
+ registerSink(new FGTextureBindableSink<>(S_RT_4, binds, binds.size(), screenMat, VarType.Texture2D));
+ registerSink(new DeferredLightDataSink<>(S_LIGHT_DATA, binds, binds.size()));
+ registerSink(new FGVarBindableSink<>(S_EXECUTE_STATE, binds, binds.size()));
+ registerSink(new FGFramebufferCopyBindableSink<>(FGGlobal.S_DEFAULT_FB, null, false, true, true, binds, binds.size()));
}
@Override
public void executeDrawCommandList(FGRenderContext renderContext) {
- screenMat.selectTechnique(_S_DEFERRED_PASS, renderContext.renderManager);
+ screenMat.selectTechnique(_S_DEFERRED_PASS, renderContext.getRenderManager());
DeferredLightDataSink deferredLightDataSink = (DeferredLightDataSink) getSink(S_LIGHT_DATA);
DeferredLightDataSource.DeferredLightDataProxy deferredLightDataProxy = (DeferredLightDataSource.DeferredLightDataProxy) deferredLightDataSink.getBind();
LightList lights = deferredLightDataProxy.getLightData();
@@ -111,7 +111,7 @@ public void executeDrawCommandList(FGRenderContext renderContext) {
screenMat.getAdditionalRenderState().setDepthTest(false);
screenMat.setBoolean("UseLightsCullMode", false);
screenRect.updateGeometricState();
- screenMat.render(screenRect, lights, renderContext.renderManager);
+ screenMat.render(screenRect, lights, renderContext.getRenderManager());
screenMat.getAdditionalRenderState().setDepthWrite(depthWrite);
screenMat.getAdditionalRenderState().setDepthTest(depthTest);
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardPass.java
index 658862ff3d..c094857e9d 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/ForwardPass.java
@@ -50,16 +50,17 @@ public ForwardPass(String name, RenderQueue.Bucket bucket) {
@Override
public void executeDrawCommandList(FGRenderContext renderContext) {
- if(!canExecute)return;
- Camera cam = null;
+ if (!canExecute) {
+ return;
+ }
+ Camera cam;
if(forceViewPort != null){
cam = forceViewPort.getCamera();
+ } else {
+ cam = renderContext.getViewPort().getCamera();
}
- else{
- cam = renderContext.viewPort.getCamera();
- }
- RenderManager rm = renderContext.renderManager;
- renderContext.renderQueue.renderQueue(this.bucket, rm, cam, true);
+ RenderManager rm = renderContext.getRenderManager();
+ renderContext.getRenderQueue().renderQueue(this.bucket, rm, cam, true);
}
@Override
diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferPass.java
index 3e086d6fa7..8bfe8e2364 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/GBufferPass.java
@@ -38,7 +38,7 @@
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.Renderer;
import com.jme3.renderer.ViewPort;
-import com.jme3.renderer.framegraph.FGFramebufferSource;
+import com.jme3.renderer.framegraph.FramebufferSource;
import com.jme3.renderer.framegraph.FGRenderContext;
import com.jme3.renderer.framegraph.FGRenderTargetSource;
import com.jme3.renderer.framegraph.FGVarSource;
@@ -53,28 +53,21 @@
/**
* @author JohnKkk
*/
-public class GBufferPass extends OpaquePass{
- private final static String S_GBUFFER_PASS = "GBufferPass";
- public final static String S_RT_0 = "RT_0";
- public final static String S_RT_1 = "RT_1";
- public final static String S_RT_2 = "RT_2";
- public final static String S_RT_3 = "RT_3";
- public final static String S_RT_4 = "RT_4";
- public final static String S_FB = "GBufferFramebuffer";
- public final static String S_LIGHT_DATA = "LIGHT_DATA";
- public final static String S_EXECUTE_STATE = "EXECUTE_STATE";
+public class GBufferPass extends OpaquePass {
+
+ private final static String GBUFFER_PASS = "GBufferPass";
+ public final static String[] RENDER_TARGETS = {"RT_0", "RT_1", "RT_2", "RT_3", "RT_4"};
+ public final static String G_FRAME_BUFFER = "GBufferFramebuffer";
+ public final static String LIGHT_DATA = "LIGHT_DATA";
+ public final static String EXECUTE_STATE = "EXECUTE_STATE";
+
private final LightList lightData = new LightList(null);
- private final List tempLights = new ArrayList();
- private Boolean bHasDraw = new Boolean(false);
- private FGVarSource bHasDrawVarSource = null;
- // gBuffer
+ private final List tempLights = new ArrayList<>();
+ private boolean bHasDraw = false;
+ private FGVarSource bHasDrawVarSource;
private FrameBuffer gBuffer;
- private Texture2D gBufferData0 = null;
- private Texture2D gBufferData1 = null;
- private Texture2D gBufferData2 = null;
- private Texture2D gBufferData3 = null;
- private Texture2D gBufferData4 = null;
- private ColorRGBA gBufferMask = new ColorRGBA(0, 0, 0, 0);
+ private final Texture2D[] gBufferData = new Texture2D[5];
+ private final ColorRGBA gBufferMask = new ColorRGBA(0, 0, 0, 0);
private int frameBufferWidth, frameBufferHeight;
public GBufferPass() {
@@ -87,35 +80,34 @@ public void executeDrawCommandList(FGRenderContext renderContext) {
bHasDraw = false;
tempLights.clear();
lightData.clear();
- ViewPort vp = null;
- if(forceViewPort != null){
+ ViewPort vp;
+ if (forceViewPort != null) {
vp = forceViewPort;
+ } else {
+ vp = renderContext.getViewPort();
}
- else{
- vp = renderContext.viewPort;
- }
- reshape(renderContext.renderManager.getRenderer(), vp, vp.getCamera().getWidth(), vp.getCamera().getHeight());
+ reshape(renderContext.getRenderer(), vp, vp.getCamera().getWidth(), vp.getCamera().getHeight());
FrameBuffer opfb = vp.getOutputFrameBuffer();
vp.setOutputFrameBuffer(gBuffer);
ColorRGBA opClearColor = vp.getBackgroundColor();
gBufferMask.set(opClearColor);
gBufferMask.a = 0.0f;
- renderContext.renderManager.getRenderer().setFrameBuffer(gBuffer);
- renderContext.renderManager.getRenderer().setBackgroundColor(gBufferMask);
- renderContext.renderManager.getRenderer().clearBuffers(vp.isClearColor(), vp.isClearDepth(), vp.isClearStencil());
- String techOrig = renderContext.renderManager.getForcedTechnique();
- renderContext.renderManager.setForcedTechnique(S_GBUFFER_PASS);
+ renderContext.getRenderer().setFrameBuffer(gBuffer);
+ renderContext.getRenderer().setBackgroundColor(gBufferMask);
+ renderContext.getRenderer().clearBuffers(vp.isClearColor(), vp.isClearDepth(), vp.isClearStencil());
+ String techOrig = renderContext.getRenderManager().getForcedTechnique();
+ renderContext.getRenderManager().setForcedTechnique(GBUFFER_PASS);
super.executeDrawCommandList(renderContext);
- renderContext.renderManager.setForcedTechnique(techOrig);
+ renderContext.getRenderManager().setForcedTechnique(techOrig);
vp.setOutputFrameBuffer(opfb);
- renderContext.renderManager.getRenderer().setBackgroundColor(opClearColor);
- renderContext.renderManager.getRenderer().setFrameBuffer(vp.getOutputFrameBuffer());
+ renderContext.getRenderer().setBackgroundColor(opClearColor);
+ renderContext.getRenderer().setFrameBuffer(vp.getOutputFrameBuffer());
bHasDrawVarSource.setValue(bHasDraw);
- if(bHasDraw){
+ if (bHasDraw) {
for(Light light : tempLights){
lightData.add(light);
}
-// renderContext.renderManager.getRenderer().copyFrameBuffer(gBuffer, vp.getOutputFrameBuffer(), false, true);
+ //renderContext.renderManager.getRenderer().copyFrameBuffer(gBuffer, vp.getOutputFrameBuffer(), false, true);
}
}
}
@@ -131,54 +123,42 @@ public void resetPass() {
public void reshape(Renderer renderer, ViewPort vp, int w, int h){
boolean recreate = false;
- if(gBuffer != null){
+ if (gBuffer != null) {
if(frameBufferWidth != w || frameBufferHeight != h){
gBuffer.dispose();
gBuffer.deleteObject(renderer);
-
frameBufferWidth = w;
frameBufferHeight = h;
-
recreate = true;
}
- }
- else{
+ } else {
recreate = true;
frameBufferWidth = w;
frameBufferHeight = h;
}
- if(recreate){
- // recreate
+ if (recreate) {
// To ensure accurate results, 32bit is used here for generalization.
- gBufferData0 = new Texture2D(w, h, Image.Format.RGBA16F);
- gBufferData1 = new Texture2D(w, h, Image.Format.RGBA16F);
- gBufferData2 = new Texture2D(w, h, Image.Format.RGBA16F);
- gBufferData3 = new Texture2D(w, h, Image.Format.RGBA32F); // The third buffer provides 32-bit floating point to store high-precision information, such as normals
- this.getSinks().clear();
- // Depth16/Depth32/Depth32F provide higher precision to prevent clipping when camera gets close, but it seems some devices do not support copying Depth16/Depth32/Depth32F to default FrameBuffer.
- gBufferData4 = new Texture2D(w, h, Image.Format.Depth);
+ gBufferData[0] = new Texture2D(w, h, Image.Format.RGBA16F);
+ gBufferData[1] = new Texture2D(w, h, Image.Format.RGBA16F);
+ gBufferData[2] = new Texture2D(w, h, Image.Format.RGBA16F);
+ // The third buffer provides 32-bit floating point to store high-precision information, such as normals
+ gBufferData[3] = new Texture2D(w, h, Image.Format.RGBA32F);
+ getSinks().clear();
+ // Depth16/Depth32/Depth32F provide higher precision to prevent clipping when camera gets close,
+ // but it seems some devices do not support copying Depth16/Depth32/Depth32F to default FrameBuffer.
+ gBufferData[4] = new Texture2D(w, h, Image.Format.Depth);
gBuffer = new FrameBuffer(w, h, 1);
- FrameBuffer.FrameBufferTextureTarget rt0 = FrameBuffer.FrameBufferTarget.newTarget(gBufferData0);
- FrameBuffer.FrameBufferTextureTarget rt1 = FrameBuffer.FrameBufferTarget.newTarget(gBufferData1);
- FrameBuffer.FrameBufferTextureTarget rt2 = FrameBuffer.FrameBufferTarget.newTarget(gBufferData2);
- FrameBuffer.FrameBufferTextureTarget rt3 = FrameBuffer.FrameBufferTarget.newTarget(gBufferData3);
- FrameBuffer.FrameBufferTextureTarget rt4 = FrameBuffer.FrameBufferTarget.newTarget(gBufferData4);
- gBuffer.addColorTarget(rt0);
- gBuffer.addColorTarget(rt1);
- gBuffer.addColorTarget(rt2);
- gBuffer.addColorTarget(rt3);
- gBuffer.setDepthTarget(rt4);
+ for (int i = 0; i < gBufferData.length; i++) {
+ FrameBuffer.FrameBufferTextureTarget target = FrameBuffer.FrameBufferTarget.newTarget(gBufferData[i]);
+ gBuffer.addColorTarget(target);
+ registerSource(new FGRenderTargetSource(RENDER_TARGETS[i], target));
+ }
gBuffer.setMultiTarget(true);
- registerSource(new FGRenderTargetSource(S_RT_0, rt0));
- registerSource(new FGRenderTargetSource(S_RT_1, rt1));
- registerSource(new FGRenderTargetSource(S_RT_2, rt2));
- registerSource(new FGRenderTargetSource(S_RT_3, rt3));
- registerSource(new FGRenderTargetSource(S_RT_4, rt4));
- registerSource(new DeferredLightDataSource(S_LIGHT_DATA, lightData));
- bHasDrawVarSource = new FGVarSource(S_EXECUTE_STATE, bHasDraw);
+ registerSource(new DeferredLightDataSource(LIGHT_DATA, lightData));
+ bHasDrawVarSource = new FGVarSource<>(EXECUTE_STATE, bHasDraw);
registerSource(bHasDrawVarSource);
- registerSource(new FGFramebufferSource(S_FB, gBuffer));
+ registerSource(new FramebufferSource(G_FRAME_BUFFER, gBuffer));
}
}
@@ -188,7 +168,7 @@ public boolean drawGeometry(RenderManager rm, Geometry geom) {
if(material.getMaterialDef().getTechniqueDefs(rm.getForcedTechnique()) == null)return false;
rm.renderGeometry(geom);
if(material.getActiveTechnique() != null){
- if(material.getMaterialDef().getTechniqueDefs(S_GBUFFER_PASS) != null){
+ if(material.getMaterialDef().getTechniqueDefs(GBUFFER_PASS) != null){
LightList lights = geom.getFilterWorldLights();
for(Light light : lights){
if(!tempLights.contains(light)){
@@ -206,13 +186,12 @@ public boolean drawGeometry(RenderManager rm, Geometry geom) {
@Override
public void prepare(FGRenderContext renderContext) {
super.prepare(renderContext);
- ViewPort vp = null;
+ ViewPort vp;
if(forceViewPort != null){
vp = forceViewPort;
+ } else {
+ vp = renderContext.getViewPort();
}
- else{
- vp = renderContext.viewPort;
- }
- reshape(renderContext.renderManager.getRenderer(), vp, vp.getCamera().getWidth(), vp.getCamera().getHeight());
+ reshape(renderContext.getRenderer(), vp, vp.getCamera().getWidth(), vp.getCamera().getHeight());
}
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/GuiPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/GuiPass.java
index 540aaa7dc2..eeca3c4f42 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/pass/GuiPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/GuiPass.java
@@ -46,15 +46,15 @@ public void executeDrawCommandList(FGRenderContext renderContext) {
cam = forceViewPort.getCamera();
}
else{
- cam = renderContext.viewPort.getCamera();
+ cam = renderContext.getViewPort().getCamera();
}
if(canExecute){
renderContext.setDepthRange(0, 0);
- renderContext.renderManager.setCamera(cam, true);
+ renderContext.getRenderManager().setCamera(cam, true);
}
super.executeDrawCommandList(renderContext);
if(canExecute){
- renderContext.renderManager.setCamera(cam, false);
+ renderContext.getRenderManager().setCamera(cam, false);
}
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessorPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessorPass.java
index 3ff7c5d536..2604f72f9d 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessorPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessorPass.java
@@ -49,15 +49,15 @@ public PostProcessorPass(String name) {
@Override
public void execute(FGRenderContext renderContext) {
renderContext.setDepthRange(0, 1);
- ViewPort vp = renderContext.viewPort;
+ ViewPort vp = renderContext.getViewPort();
SafeArrayList processors = vp.getProcessors();
if (processors != null) {
-// if (prof!=null) prof.vpStep(VpStep.PostFrame, vp, null);
+ //if (prof!=null) prof.vpStep(VpStep.PostFrame, vp, null);
for (SceneProcessor proc : processors.getArray()) {
-// if (prof != null) prof.spStep(SpStep.ProcPostFrame, proc.getClass().getSimpleName());
+ //if (prof != null) prof.spStep(SpStep.ProcPostFrame, proc.getClass().getSimpleName());
proc.postFrame(vp.getOutputFrameBuffer());
}
-// if (prof != null) prof.vpStep(VpStep.ProcEndRender, vp, null);
+ //if (prof != null) prof.vpStep(VpStep.ProcEndRender, vp, null);
}
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/ResolveSceneColorPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/ResolveSceneColorPass.java
index 51b9b39488..ad2c2d9c3d 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/pass/ResolveSceneColorPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/ResolveSceneColorPass.java
@@ -44,6 +44,7 @@
* @author JohnKkk
*/
public class ResolveSceneColorPass extends ScreenPass {
+
public final static String S_SCENE_COLOR_RT = "SceneColorRT";
public final static String S_SCENE_DEPTH = "SceneDepth";
private static final String _S_RESOLVE_SCENE_COLOR_MAT_DEF = "Common/MatDefs/Misc/ResolveSceneColor.j3md";
@@ -59,13 +60,13 @@ public void dispatchPassSetup(RenderQueue renderQueue) {
@Override
public void executeDrawCommandList(FGRenderContext renderContext) {
- renderContext.renderManager.getRenderer().setFrameBuffer(null);
+ renderContext.getRenderer().setFrameBuffer(null);
boolean depthWrite = screenMat.getAdditionalRenderState().isDepthWrite();
boolean depthTest = screenMat.getAdditionalRenderState().isDepthTest();
screenMat.getAdditionalRenderState().setDepthWrite(false);
screenMat.getAdditionalRenderState().setDepthTest(false);
screenRect.updateGeometricState();
- screenMat.render(screenRect, renderContext.renderManager);
+ screenMat.render(screenRect, renderContext.getRenderManager());
screenMat.getAdditionalRenderState().setDepthWrite(depthWrite);
screenMat.getAdditionalRenderState().setDepthTest(depthTest);
}
@@ -89,6 +90,6 @@ public void init() {
// register Sinks
registerSink(new FGTextureBindableSink(S_SCENE_COLOR_RT, binds, binds.size(), screenMat, VarType.Texture2D));
- registerSink(new FGFramebufferCopyBindableSink(FGGlobal.S_DEFAULT_FB, null, false, true, true, binds, binds.size()));
+ registerSink(new FGFramebufferCopyBindableSink(FGGlobal.S_DEFAULT_FB, null, false, true, true, binds, binds.size()));
}
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingPass.java b/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingPass.java
index 399cd10529..20e2fcc4cd 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingPass.java
@@ -37,8 +37,9 @@
import com.jme3.renderer.framegraph.FGRenderContext;
public class TileDeferredShadingPass extends DeferredShadingPass{
- private static final String _S_TILE_BASED_DEFERRED_SHADING_PASS_MAT_DEF = "Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md";
- protected final static String _S_TILE_BASED_DEFERRED_PASS = "TileBasedDeferredPass";
+
+ private static final String MAT_DEF = "Common/MatDefs/ShadingCommon/TileBasedDeferredShading.j3md";
+ protected final static String PASS = "TileBasedDeferredPass";
public TileDeferredShadingPass() {
super("TileDeferredShadingPass");
@@ -46,7 +47,7 @@ public TileDeferredShadingPass() {
@Override
protected Material getMaterial() {
- MaterialDef def = (MaterialDef) assetManager.loadAsset(_S_TILE_BASED_DEFERRED_SHADING_PASS_MAT_DEF);
+ MaterialDef def = (MaterialDef) assetManager.loadAsset(MAT_DEF);
screenMat = new Material(def);
return screenMat;
}
@@ -58,14 +59,14 @@ public void executeDrawCommandList(FGRenderContext renderContext) {
LightList lights = deferredLightDataProxy.getLightData();
// Handle FullScreenLights
- screenMat.selectTechnique(_S_TILE_BASED_DEFERRED_PASS, renderContext.renderManager);
+ screenMat.selectTechnique(PASS, renderContext.getRenderManager());
boolean depthWrite = screenMat.getAdditionalRenderState().isDepthWrite();
boolean depthTest = screenMat.getAdditionalRenderState().isDepthTest();
screenMat.getAdditionalRenderState().setDepthTest(false);
screenMat.getAdditionalRenderState().setDepthWrite(false);
screenMat.setBoolean("UseLightsCullMode", false);
screenRect.updateGeometricState();
- screenMat.render(screenRect, lights, renderContext.renderManager);
+ screenMat.render(screenRect, lights, renderContext.getRenderManager());
screenMat.getAdditionalRenderState().setDepthTest(depthTest);
screenMat.getAdditionalRenderState().setDepthWrite(depthWrite);
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java
index cb9403624c..450feb0384 100644
--- a/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java
+++ b/jme3-examples/src/main/java/jme3test/renderpath/TestPBRTerrainAdvancedRenderPath.java
@@ -469,5 +469,7 @@ private void setUpCamera() {
cam.lookAtDirection(new Vector3f(0, -1.5f, -1).normalizeLocal(), Vector3f.UNIT_Y);
getFlyByCamera().setMoveSpeed(camMoveSpeed);
+ flyCam.setEnabled(false);
+ inputManager.setCursorVisible(true);
}
}
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/sandbox/CustomPass.java b/jme3-examples/src/main/java/jme3test/renderpath/sandbox/CustomPass.java
new file mode 100644
index 0000000000..44a352e59f
--- /dev/null
+++ b/jme3-examples/src/main/java/jme3test/renderpath/sandbox/CustomPass.java
@@ -0,0 +1,32 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package jme3test.renderpath.sandbox;
+
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.framegraph.FGRenderContext;
+import com.jme3.renderer.framegraph.FGRenderQueuePass;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Geometry;
+
+/**
+ *
+ * @author codex
+ */
+public class CustomPass extends FGRenderQueuePass {
+
+ public CustomPass() {
+ super("MyCustomPass");
+ }
+
+ @Override
+ public void dispatchPassSetup(RenderQueue renderQueue) {
+
+ }
+ @Override
+ public void executeDrawCommandList(FGRenderContext renderContext) {}
+ @Override
+ public boolean drawGeometry(RenderManager rm, Geometry geom) {}
+
+}
diff --git a/jme3-examples/src/main/java/jme3test/renderpath/sandbox/FrameGraphSandbox.java b/jme3-examples/src/main/java/jme3test/renderpath/sandbox/FrameGraphSandbox.java
new file mode 100644
index 0000000000..7f47aef17f
--- /dev/null
+++ b/jme3-examples/src/main/java/jme3test/renderpath/sandbox/FrameGraphSandbox.java
@@ -0,0 +1,20 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package jme3test.renderpath.sandbox;
+
+import com.jme3.app.SimpleApplication;
+
+/**
+ *
+ * @author codex
+ */
+public class FrameGraphSandbox extends SimpleApplication {
+
+ @Override
+ public void simpleInitApp() {
+
+ }
+
+}
From 79d9426cf232c73ec0b24db0affde4bfea8c9f98 Mon Sep 17 00:00:00 2001
From: codex <103840984+codex128@users.noreply.github.com>
Date: Fri, 19 Apr 2024 10:46:11 -0400
Subject: [PATCH 033/111] rebuilt API
---
.../java/com/jme3/renderer/RenderManager.java | 83 ++++-----
.../main/java/com/jme3/renderer/Renderer.java | 11 ++
.../renderer/framegraph/AbstractFGPass.java | 4 +-
.../renderer/framegraph/AbstractModule.java | 28 +++
...nerBindableSink.java => BindableSink.java} | 55 ++----
.../jme3/renderer/framegraph/DepthRange.java | 83 +++++++++
.../jme3/renderer/framegraph/FGBindable.java | 3 +-
.../renderer/framegraph/FGBindingPass.java | 18 +-
.../renderer/framegraph/FGCallbackPass.java | 2 +-
.../FGFramebufferCopyBindableSink.java | 20 +--
.../jme3/renderer/framegraph/FGModule.java | 22 +++
...FrameGraph.java => FGParameterSource.java} | 6 +-
.../com/jme3/renderer/framegraph/FGPass.java | 4 +-
.../framegraph/FGRenderQueuePass.java | 38 ++--
.../renderer/framegraph/FGShaderResource.java | 58 +++++++
.../framegraph/FGTextureBindableSink.java | 92 ----------
.../framegraph/FGVarBindableSink.java | 15 +-
.../jme3/renderer/framegraph/FGVarSource.java | 2 +-
.../renderer/framegraph/FrameBufferParam.java | 40 +++++
.../jme3/renderer/framegraph/FrameGraph.java | 18 +-
.../framegraph/FramebufferSource.java | 2 +-
...derTargetSource.java => MatParamSink.java} | 61 +++----
.../renderer/framegraph/MatRenderParam.java | 46 +++++
.../renderer/framegraph/MyFrameGraph.java | 85 +++++++++
.../renderer/framegraph/ParameterBinding.java | 43 +++++
.../renderer/framegraph/ParameterManager.java | 124 +++++++++++++
...GRenderContext.java => RenderContext.java} | 37 ++--
.../renderer/framegraph/RenderParameter.java | 66 +++++++
.../framegraph/RenderParameterGroup.java | 17 ++
.../framegraph/RenderQueueModule.java | 51 ++++++
.../framegraph/TextureTargetParam.java | 54 ++++++
.../renderer/framegraph/ValueRenderParam.java | 38 ++++
.../renderer/pass/DeferredLightDataProxy.java | 4 +-
.../renderer/pass/DeferredLightDataSink.java | 12 +-
.../pass/DeferredLightDataSource.java | 4 +-
.../renderer/pass/DeferredShadingModule.java | 121 +++++++++++++
.../renderer/pass/DeferredShadingPass.java | 20 +--
.../com/jme3/renderer/pass/ForwardModule.java | 66 +++++++
.../com/jme3/renderer/pass/ForwardPass.java | 4 +-
.../com/jme3/renderer/pass/GBufferModule.java | 164 ++++++++++++++++++
.../com/jme3/renderer/pass/GBufferPass.java | 15 +-
.../com/jme3/renderer/pass/GuiModule.java | 39 +++++
.../java/com/jme3/renderer/pass/GuiPass.java | 14 +-
.../com/jme3/renderer/pass/OpaqueModule.java | 28 +++
.../com/jme3/renderer/pass/OpaquePass.java | 6 +-
.../renderer/pass/PostProcessingModule.java | 68 ++++++++
.../jme3/renderer/pass/PostProcessorPass.java | 6 +-
.../renderer/pass/ResolveSceneColorPass.java | 6 +-
.../com/jme3/renderer/pass/ScreenModule.java | 31 ++++
.../java/com/jme3/renderer/pass/SkyPass.java | 8 +-
.../pass/TileDeferredShadingModule.java | 47 +++++
.../pass/TileDeferredShadingPass.java | 8 +-
.../jme3/renderer/pass/TranslucentPass.java | 6 +-
.../jme3/renderer/pass/TransparentPass.java | 6 +-
.../TestPBRTerrainAdvancedRenderPath.java | 18 +-
.../renderpath/sandbox/CustomPass.java | 32 ----
.../renderpath/sandbox/FrameGraphSandbox.java | 2 +
57 files changed, 1560 insertions(+), 401 deletions(-)
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractModule.java
rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{FGContainerBindableSink.java => BindableSink.java} (63%)
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/DepthRange.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGModule.java
rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{DeferredFrameGraph.java => FGParameterSource.java} (56%)
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGShaderResource.java
delete mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferParam.java
rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{FGRenderTargetSource.java => MatParamSink.java} (59%)
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/MatRenderParam.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/MyFrameGraph.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ParameterBinding.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ParameterManager.java
rename jme3-core/src/main/java/com/jme3/renderer/framegraph/{FGRenderContext.java => RenderContext.java} (77%)
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderParameter.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderParameterGroup.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/RenderQueueModule.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/TextureTargetParam.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/framegraph/ValueRenderParam.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/DeferredShadingModule.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/ForwardModule.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/GBufferModule.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/GuiModule.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/OpaqueModule.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/PostProcessingModule.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/ScreenModule.java
create mode 100644 jme3-core/src/main/java/com/jme3/renderer/pass/TileDeferredShadingModule.java
delete mode 100644 jme3-examples/src/main/java/jme3test/renderpath/sandbox/CustomPass.java
diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
index 2c4ebb2397..7e064b7e47 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
@@ -48,7 +48,7 @@
import com.jme3.profile.SpStep;
import com.jme3.profile.VpStep;
import com.jme3.renderer.framegraph.FGGlobal;
-import com.jme3.renderer.framegraph.FGRenderContext;
+import com.jme3.renderer.framegraph.RenderContext;
import com.jme3.renderer.framegraph.FrameGraph;
import com.jme3.renderer.queue.GeometryList;
import com.jme3.renderer.queue.RenderQueue;
@@ -111,7 +111,7 @@ public class RenderManager {
// frameGraph=============================================================================↑
// RenderPath
- public enum RenderPath{
+ public enum RenderPath {
None(-1, "None"),
Forward(0, "Forward"),
ForwardPlus(1, "ForwardPlus"),
@@ -157,7 +157,7 @@ public String getInfo(){
private LightFilter lightFilter = new DefaultLightFilter();
private TechniqueDef.LightMode preferredLightMode = TechniqueDef.LightMode.MultiPass;
private int singlePassLightBatchSize = 1;
- private MatParamOverride boundDrawBufferId=new MatParamOverride(VarType.Int,"BoundDrawBuffer",0);
+ private MatParamOverride boundDrawBufferId = new MatParamOverride(VarType.Int, "BoundDrawBuffer", 0);
private Predicate renderFilter;
@@ -171,7 +171,7 @@ public RenderManager(Renderer renderer) {
this.renderer = renderer;
this.forcedOverrides.add(boundDrawBufferId);
if(useFramegraph){
- frameGraph = new FrameGraph(new FGRenderContext(this, null));
+ frameGraph = new FrameGraph(new RenderContext(this, null));
gBufferPass = new GBufferPass();
deferredShadingPass = new DeferredShadingPass();
tileDeferredShadingPass = new TileDeferredShadingPass();
@@ -257,9 +257,9 @@ public TileBasedDeferredSinglePassLightingLogic.TileInfo getTileInfo() {
}
/**
- * Set an IRenderGeometry for executing drawing call interfaces for the specified FGPass.
+ * Set an IRenderGeometry for executing drawing call interfaces for the specified FGPass.
+ *
* @param renderGeometry
- *
* @see RenderGeometry
*/
public final void setRenderGeometryHandler(RenderGeometry renderGeometry){
@@ -1374,29 +1374,29 @@ public void renderViewPort(ViewPort vp, float tpf) {
}
renderer.clearBuffers(vp.isClearColor(), vp.isClearDepth(), vp.isClearStencil());
}
+
+ if (prof != null) {
+ prof.vpStep(VpStep.RenderScene, vp, null);
+ }
+ List scenes = vp.getScenes();
+ for (int i = scenes.size() - 1; i >= 0; i--) {
+ renderScene(scenes.get(i), vp);
+ }
- if(useFramegraph){
- RenderPath curRenderPath = vp.getRenderPath() == RenderPath.None ? renderPath : vp.getRenderPath();
-
+ if (processors != null) {
if (prof != null) {
- prof.vpStep(VpStep.RenderScene, vp, null);
- }
- List scenes = vp.getScenes();
- for (int i = scenes.size() - 1; i >= 0; i--) {
- renderScene(scenes.get(i), vp);
+ prof.vpStep(VpStep.PostQueue, vp, null);
}
-
- if (processors != null) {
+ for (SceneProcessor p : processors.getArray()) {
if (prof != null) {
- prof.vpStep(VpStep.PostQueue, vp, null);
- }
- for (SceneProcessor p : processors.getArray()) {
- if (prof != null) {
- prof.spStep(SpStep.ProcPostQueue, p.getClass().getSimpleName());
- }
- p.postQueue(vp.getQueue());
+ prof.spStep(SpStep.ProcPostQueue, p.getClass().getSimpleName());
}
+ p.postQueue(vp.getQueue());
}
+ }
+
+ if(useFramegraph){
+ RenderPath curRenderPath = vp.getRenderPath() == RenderPath.None ? renderPath : vp.getRenderPath();
frameGraph.reset();
frameGraph.getRenderContext().setViewPort(vp);
@@ -1448,33 +1448,9 @@ public void renderViewPort(ViewPort vp, float tpf) {
frameGraph.finalizePasses();
frameGraph.execute();
- // clear any remaining spatials that were not rendered.
- clearQueue(vp);
-
- if (prof!=null) prof.vpStep(VpStep.EndRender, vp, null);
} else {
- if (prof != null) {
- prof.vpStep(VpStep.RenderScene, vp, null);
- }
- List scenes = vp.getScenes();
- for (int i = scenes.size() - 1; i >= 0; i--) {
- renderScene(scenes.get(i), vp);
- }
-
- if (processors != null) {
- if (prof != null) {
- prof.vpStep(VpStep.PostQueue, vp, null);
- }
- for (SceneProcessor proc : processors.getArray()) {
- if (prof != null) {
- prof.spStep(SpStep.ProcPostQueue, proc.getClass().getSimpleName());
- }
- proc.postQueue(vp.getQueue());
- }
- }
-
if (prof != null) {
prof.vpStep(VpStep.FlushQueue, vp, null);
}
@@ -1496,13 +1472,16 @@ public void renderViewPort(ViewPort vp, float tpf) {
}
//renders the translucent objects queue after processors have been rendered
renderTranslucentQueue(vp);
- // clear any remaining spatials that were not rendered.
- clearQueue(vp);
+
+ }
+
+ // clear any remaining spatials that were not rendered.
+ clearQueue(vp);
- if (prof != null) {
- prof.vpStep(VpStep.EndRender, vp, null);
- }
+ if (prof != null) {
+ prof.vpStep(VpStep.EndRender, vp, null);
}
+
}
/**
diff --git a/jme3-core/src/main/java/com/jme3/renderer/Renderer.java b/jme3-core/src/main/java/com/jme3/renderer/Renderer.java
index c92de923ae..530fb87f68 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/Renderer.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/Renderer.java
@@ -33,6 +33,7 @@
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
+import com.jme3.renderer.framegraph.DepthRange;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer;
import com.jme3.shader.bufferobject.BufferObject;
@@ -128,6 +129,16 @@ public interface Renderer {
* @param end The range end
*/
public void setDepthRange(float start, float end);
+
+ /**
+ * Sets the range of depth values for objects.
+ *
+ * @param range
+ * @see #setDepthRange(float, float)
+ */
+ public default void setDepthRange(DepthRange range) {
+ setDepthRange(range.getStart(), range.getEnd());
+ }
/**
* Called when a new frame has been rendered.
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java
index 2e0b75b74b..6cfb98c06f 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractFGPass.java
@@ -93,8 +93,8 @@ public FGSink getSink(String registeredName) {
}
@Override
- public void setSinkLinkage(String registeredName, String targetPass, String targetResource) {
- getSink(registeredName).setTarget(targetPass, targetResource);
+ public void setSinkLinkage(String sinkName, String targetPass, String targetResource) {
+ getSink(sinkName).setTarget(targetPass, targetResource);
}
@Override
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractModule.java
new file mode 100644
index 0000000000..33a456e408
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/AbstractModule.java
@@ -0,0 +1,28 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package com.jme3.renderer.framegraph;
+
+import java.util.Collection;
+import java.util.LinkedList;
+
+/**
+ *
+ * @author codex
+ */
+public abstract class AbstractModule implements FGModule {
+
+ private final LinkedList parameters = new LinkedList<>();
+
+ @Override
+ public Collection getRenderParameters() {
+ return parameters;
+ }
+
+ protected final T addParameter(T p) {
+ parameters.add(p);
+ return p;
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/BindableSink.java
similarity index 63%
rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java
rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/BindableSink.java
index 5134ad7295..a3516b7fd4 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGContainerBindableSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/BindableSink.java
@@ -31,63 +31,38 @@
*/
package com.jme3.renderer.framegraph;
-import java.util.ArrayList;
-
/**
* FGContainerBindableSink is used to proxy a FGSink, and also has the role of FGBindable.
*
* Typically, a Sink needed by a Pass may be a Bindable object.
*
* @author JohnKkk
- * @param
*/
-public class FGContainerBindableSink extends AbstractFGSink {
+public class BindableSink extends AbstractFGSink implements FGBindable {
+ protected FGBindable target;
protected boolean linked = false;
- protected ArrayList container;
- protected int index;
- protected FGBindableProxy bindableProxy;
-
- public final static class FGBindableProxy implements FGBindable {
-
- public FGBindable targetBindable;
-
- public FGBindableProxy(FGBindable targetBindable) {
- this.targetBindable = targetBindable;
- }
- @Override
- public void bind(FGRenderContext renderContext) {
- if(targetBindable != null){
- targetBindable.bind(renderContext);
- }
- }
-
+ public BindableSink(String registeredName) {
+ super(registeredName);
}
- public FGContainerBindableSink(String registeredName, ArrayList container, int index) {
- super(registeredName);
- this.container = container;
- this.index = index;
- bindableProxy = new FGBindableProxy(null);
- if(index < this.container.size()){
- this.container.set(index, bindableProxy);
- }
- else{
- this.container.add(bindableProxy);
- this.index = this.container.size() - 1;
+ @Override
+ public void bind(RenderContext renderContext) {
+ if (target != null) {
+ target.bind(renderContext);
}
}
-
+
@Override
- public void bind(FGSource fgSource) {
- T p = (T)fgSource.yieldBindable();
+ public void bind(FGSource src) {
+ FGBindable p = src.yieldBindable();
if(p == null){
- System.err.println("Binding input [" + getRegisteredName() + "] to output [" + getLinkPassName() + "." + getLinkPassResName() + "] " + " { " + fgSource.getName() + " } ");
+ System.err.println("Binding input [" + getRegisteredName() + "] to output [" + getLinkPassName() + "." + getLinkPassResName() + "] " + " { " + src.getName() + " } ");
return;
}
- bindableProxy.targetBindable = p;
-// container.set(index, p);
+ target = p;
+ //container.set(index, p);
linked = true;
}
@@ -104,6 +79,6 @@ public void postLinkValidate() {
@Override
public FGBindable getBind() {
- return bindableProxy.targetBindable;
+ return target;
}
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DepthRange.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DepthRange.java
new file mode 100644
index 0000000000..2dc85fd3d5
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/DepthRange.java
@@ -0,0 +1,83 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package com.jme3.renderer.framegraph;
+
+/**
+ *
+ * @author codex
+ */
+public class DepthRange {
+
+ public static final DepthRange IDENTITY = new DepthRange();
+
+ private float start, end;
+
+ public DepthRange() {
+ set(0, 1);
+ }
+ public DepthRange(float start, float end) {
+ set(start, end);
+ }
+ public DepthRange(DepthRange range) {
+ set(range);
+ }
+
+ public final DepthRange set(float start, float end) {
+ validateRange(start, end);
+ this.start = start;
+ this.end = end;
+ return this;
+ }
+
+ public final DepthRange set(DepthRange range) {
+ // no need to validate range here
+ start = range.start;
+ end = range.end;
+ return this;
+ }
+
+ public float getStart() {
+ return start;
+ }
+
+ public float getEnd() {
+ return end;
+ }
+
+ private void validateRange(float start, float end) {
+ if (start > end) {
+ throw new IllegalStateException("Depth start cannot be beyond depth end.");
+ }
+ if (start > 1 || start < 0 || end > 1 || end < 0) {
+ throw new IllegalStateException("Depth parameters must be between 0 and 1 (inclusive).");
+ }
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object == null || !(object instanceof DepthRange)) {
+ return false;
+ }
+ DepthRange obj = (DepthRange)object;
+ return start == obj.start && end == obj.end;
+ }
+
+ public boolean equals(DepthRange range) {
+ return range != null && start == range.start && end == range.end;
+ }
+
+ public boolean equals(float start, float end) {
+ return this.start != start && this.end != end;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 79 * hash + Float.floatToIntBits(this.start);
+ hash = 79 * hash + Float.floatToIntBits(this.end);
+ return hash;
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java
index 488010b07d..b11bece28c 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindable.java
@@ -33,13 +33,14 @@
/**
* FGBindable can be any resource that needs binding (such as state machine, FBO, Texture, Paramater...)
+ *
* @author JohnKkk
*/
public interface FGBindable {
public final static String DEFAULT_BINDABLE_UID = "";
- public void bind(FGRenderContext renderContext);
+ public void bind(RenderContext renderContext);
public default String getUID() {
return DEFAULT_BINDABLE_UID;
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java
index 0eea3a33be..a17be1a3f2 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGBindingPass.java
@@ -51,16 +51,22 @@ protected FGBindingPass(String name, ArrayList binds){
this.binds = binds;
}
+ public void registerBindableSink(BindableSink sink) {
+ registerSink(sink);
+ binds.add(sink);
+ }
+
public void addBind(FGBindable bind){
binds.add(bind);
}
- public void addBindSink(String name){
- int index = binds.size() - 1;
- registerSink(new FGContainerBindableSink(name, binds, index));
+ public void addBindSink(String name) {
+ BindableSink sink = new BindableSink(name);
+ binds.add(sink);
+ registerSink(sink);
}
- public void bindAll(FGRenderContext renderContext){
+ public void bindAll(RenderContext renderContext){
// Bind all objects
for(FGBindable bind : binds){
bind.bind(renderContext);
@@ -68,9 +74,9 @@ public void bindAll(FGRenderContext renderContext){
}
@Override
- public void prepare(FGRenderContext renderContext) {}
+ public void prepare(RenderContext renderContext) {}
@Override
- public void execute(FGRenderContext renderContext) {}
+ public void execute(RenderContext renderContext) {}
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGCallbackPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGCallbackPass.java
index 2b5dd005db..afaab3f107 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGCallbackPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGCallbackPass.java
@@ -47,7 +47,7 @@ private FGCallbackPass(String name, IFGCallbackInterface ifgci) {
}
@Override
- public void execute(FGRenderContext renderContext) {
+ public void execute(RenderContext renderContext) {
bindAll(renderContext);
if(iFGCallbackInterface != null){
iFGCallbackInterface.callbackPass();
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java
index 15535224f9..67351928d0 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGFramebufferCopyBindableSink.java
@@ -39,13 +39,13 @@
* @author JohnKkk
* @param
*/
-public class FGFramebufferCopyBindableSink extends FGContainerBindableSink {
+public class FGFramebufferCopyBindableSink extends BindableSink {
- private FramebufferCopyBindableProxy framebufferCopyBindableProxy;
+ private FramebufferCopyBindableProxy proxy;
- public FGFramebufferCopyBindableSink(String registeredName, FrameBuffer distFrameBuffer, boolean copyColor, boolean copyDepth, boolean copyStencil, ArrayList container, int index) {
- super(registeredName, container, index);
- framebufferCopyBindableProxy = new FramebufferCopyBindableProxy(distFrameBuffer, copyColor, copyDepth, copyStencil);
+ public FGFramebufferCopyBindableSink(String registeredName, FrameBuffer distFrameBuffer, boolean copyColor, boolean copyDepth, boolean copyStencil) {
+ super(registeredName);
+ proxy = new FramebufferCopyBindableProxy(distFrameBuffer, copyColor, copyDepth, copyStencil);
}
private final static class FramebufferCopyBindableProxy implements FGBindable {
@@ -67,7 +67,7 @@ public void setSourceFramebuffer(FrameBuffer sourceFramebuffer) {
}
@Override
- public void bind(FGRenderContext renderContext) {
+ public void bind(RenderContext renderContext) {
if(this.distFramebuffer != null || this.sourceFramebuffer != null){
renderContext.getRenderer().copyFrameBuffer(this.sourceFramebuffer,
(this.distFramebuffer != null ? this.distFramebuffer : renderContext.getViewPort().getOutputFrameBuffer()),
@@ -77,12 +77,12 @@ public void bind(FGRenderContext renderContext) {
}
public final void setDistFrameBuffer(FrameBuffer distFrameBuffer){
- framebufferCopyBindableProxy.distFramebuffer = distFrameBuffer;
+ proxy.distFramebuffer = distFrameBuffer;
}
@Override
public void bind(FGSource fgSource) {
- T p = (T)fgSource.yieldBindable();
+ FGBindable p = fgSource.yieldBindable();
if (p == null) {
System.err.println("Binding input [" + getRegisteredName() + "] to output [" + getLinkPassName() + "." + getLinkPassResName() + "] " + " { " + fgSource.getName() + " } ");
return;
@@ -90,8 +90,8 @@ public void bind(FGSource fgSource) {
if(fgSource instanceof FramebufferSource){
linked = true;
FramebufferSource framebufferSource = (FramebufferSource)fgSource;
- framebufferCopyBindableProxy.setSourceFramebuffer(((FramebufferSource.FrameBufferSourceProxy)framebufferSource.yieldBindable()).getFrameBuffer());
- bindableProxy.targetBindable = framebufferCopyBindableProxy;
+ proxy.setSourceFramebuffer(((FramebufferSource.FrameBufferSourceProxy)framebufferSource.yieldBindable()).getFrameBuffer());
+ target = proxy;
}
else{
System.err.println(getRegisteredName() + " needs a FGFramebufferSource");
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGModule.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGModule.java
new file mode 100644
index 0000000000..5ed5b64ddc
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGModule.java
@@ -0,0 +1,22 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package com.jme3.renderer.framegraph;
+
+/**
+ *
+ * @author codex
+ * @param
+ */
+public interface FGModule extends RenderParameterGroup {
+
+ public void initialize(T frameGraph);
+
+ public void prepare(RenderContext context);
+
+ public void execute(RenderContext context);
+
+ public void reset();
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredFrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGParameterSource.java
similarity index 56%
rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredFrameGraph.java
rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/FGParameterSource.java
index 13729029fe..702614ff94 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/DeferredFrameGraph.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGParameterSource.java
@@ -1,6 +1,6 @@
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
- * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Interface.java to edit this template
*/
package com.jme3.renderer.framegraph;
@@ -8,6 +8,8 @@
*
* @author codex
*/
-public class DeferredFrameGraph {
+public interface FGParameterSource {
+
+
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
index 7fe5c90d7b..2347c3aa2e 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGPass.java
@@ -21,9 +21,9 @@ public interface FGPass {
public boolean isResetResources();
- public void prepare(FGRenderContext renderContext);
+ public void prepare(RenderContext renderContext);
- public void execute(FGRenderContext renderContext);
+ public void execute(RenderContext renderContext);
public FGSource getSource(String name);
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java
index c632b8aff1..a2bdb7cf34 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderQueuePass.java
@@ -37,21 +37,24 @@
import com.jme3.renderer.pass.RenderGeometry;
/**
- * All passes that need to perform rendering must inherit from this class.
+ * All passes that need to perform rendering must inherit from this class..
+ *
* @author JohnKkk
*/
public abstract class FGRenderQueuePass extends FGBindingPass implements RenderGeometry {
+
protected ViewPort forceViewPort;
// It is just geometry data for now. If we extend the RHI interface in the future, it may be adjusted to MeshDrawCommand.
- protected GeometryList passMeshDrawCommandList;
- protected boolean canExecute;
+ protected GeometryList drawCommands;
+ protected boolean canExecute = false;
public FGRenderQueuePass(String name) {
super(name);
}
/**
- * A RenderPass may use a specified viewport. This can be set using this function.
+ * A RenderPass may use a specified viewport.
+ *
* @param forceViewPort targetViewPort
*/
public void setForceViewPort(ViewPort forceViewPort) {
@@ -59,14 +62,16 @@ public void setForceViewPort(ViewPort forceViewPort) {
}
/**
- * Dispatch visible mesh draw commands to process task, to prepare for this pass.
- * todo:For the current GLRenderer, the MeshDrawCommand concept actually does not exist. So this is prepared for future Vulkan-like renderers
+ * Dispatch visible mesh draw commands to process task, to prepare for this pass.
+ *
+ * For the current GLRenderer, the MeshDrawCommand concept actually does not exist. So this is prepared for future Vulkan-like renderers.
+ *
* @param renderQueue targetRenderQueue
*/
public abstract void dispatchPassSetup(RenderQueue renderQueue);
@Override
- public void execute(FGRenderContext renderContext) {
+ public void execute(RenderContext renderContext) {
renderContext.getRenderManager().setRenderGeometryHandler(this);
dispatchPassSetup(renderContext.getRenderQueue());
if(!canExecute){
@@ -76,24 +81,27 @@ public void execute(FGRenderContext renderContext) {
bindAll(renderContext);
// todo:Use the default queue temporarily to avoid creating a temporary copy
- if(passMeshDrawCommandList != null && passMeshDrawCommandList.size() > 0){
+ //if(passMeshDrawCommandList != null && passMeshDrawCommandList.size() > 0){
// drawcall
- }
- executeDrawCommandList(renderContext);
+ //}
+ executeDrawCommands(renderContext);
renderContext.getRenderManager().setRenderGeometryHandler(null);
}
/**
- * todo:For the current GLRenderer, the MeshDrawCommand concept actually does not exist. So this is prepared for future Vulkan-like renderers
- * @param renderContext
+ * For the current GLRenderer, the MeshDrawCommand concept actually does not exist.
+ *
+ * This is prepared for future Vulkan-like renderers.
+ *
+ * @param context
*/
- public abstract void executeDrawCommandList(FGRenderContext renderContext);
+ public abstract void executeDrawCommands(RenderContext context);
@Override
public void resetPass() {
super.resetPass();
- if(passMeshDrawCommandList != null && passMeshDrawCommandList.size() > 0){
- passMeshDrawCommandList.clear();
+ if(drawCommands != null && drawCommands.size() > 0){
+ drawCommands.clear();
}
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGShaderResource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGShaderResource.java
new file mode 100644
index 0000000000..0c165de960
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGShaderResource.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
+
+public class FGShaderResource extends AbstractFGSource implements FGBindable {
+
+ private final T resource;
+
+ public FGShaderResource(String name, T resource) {
+ super(name);
+ this.resource = resource;
+ }
+
+ @Override
+ public void bind(RenderContext renderContext) {}
+
+ @Override
+ public void postLinkValidate() {}
+
+ @Override
+ public FGShaderResource yieldBindable() {
+ return this;
+ }
+
+ public T getResource() {
+ return resource;
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java
deleted file mode 100644
index be07de4a4b..0000000000
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGTextureBindableSink.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2009-2023 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 com.jme3.renderer.framegraph;
-
-import com.jme3.material.Material;
-import com.jme3.shader.VarType;
-import java.util.ArrayList;
-
-public class FGTextureBindableSink extends FGContainerBindableSink {
-
- private Material material;
- private TextureBindableProxy textureBindableProxy;
-
- private static class TextureBindableProxy implements FGBindable {
-
- Material material;
- VarType bindTextureType;
- Object bindValue;
- String bindName;
-
- public TextureBindableProxy(Material material, String bindName, VarType bindTextureType) {
- // check bindTextureType
- this.bindTextureType = bindTextureType;
- this.material = material;
- this.bindName = bindName;
- }
- public final void setValue(Object value){
- bindValue = value;
- }
-
- @Override
- public void bind(FGRenderContext renderContext) {
- if(material != null && bindName != null){
- this.material.setParam(bindName, bindTextureType, bindValue);
- }
- }
-
- }
-
- public FGTextureBindableSink(String registeredName, ArrayList container, int index, Material material, VarType bindTextureType) {
- super(registeredName, container, index);
- this.material = material;
- textureBindableProxy = new TextureBindableProxy(material, registeredName, bindTextureType);
- }
-
- @Override
- public void bind(FGSource fgSource) {
- T p = (T)fgSource.yieldBindable();
- if(p == null){
- System.err.println("Binding input [" + getRegisteredName() + "] to output [" + getLinkPassName() + "." + getLinkPassResName() + "] " + " { " + fgSource.getName() + " } ");
- return;
- }
- if(fgSource instanceof FGRenderTargetSource){
- linked = true;
- FGRenderTargetSource renderTargetSource = (FGRenderTargetSource)fgSource;
- textureBindableProxy.setValue(((FGRenderTargetSource.RenderTargetSourceProxy)renderTargetSource.yieldBindable()).getShaderResource());
- bindableProxy.targetBindable = textureBindableProxy;
- }
- else{
- System.err.println(getRegisteredName() + " needs a FGRenderTargetSource");
- }
- }
-}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarBindableSink.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarBindableSink.java
index e657912272..269635f1ef 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarBindableSink.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarBindableSink.java
@@ -31,19 +31,18 @@
*/
package com.jme3.renderer.framegraph;
-import java.util.ArrayList;
-
/**
* @author JohnKkk
- * @param
*/
-public class FGVarBindableSink extends FGContainerBindableSink{
- public FGVarBindableSink(String registeredName, ArrayList container, int index) {
- super(registeredName, container, index);
+public class FGVarBindableSink extends BindableSink {
+
+ public FGVarBindableSink(String registeredName) {
+ super(registeredName);
}
@Override
- public void bind(FGSource fgSource) {
- super.bind(fgSource);
+ public void bind(FGSource src) {
+ super.bind(src);
}
+
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java
index 51eabbd709..996fcaca3d 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGVarSource.java
@@ -50,7 +50,7 @@ public T getValue() {
}
@Override
- public void bind(FGRenderContext renderContext) {}
+ public void bind(RenderContext renderContext) {}
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferParam.java
new file mode 100644
index 0000000000..b16f1f3399
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameBufferParam.java
@@ -0,0 +1,40 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package com.jme3.renderer.framegraph;
+
+import com.jme3.texture.FrameBuffer;
+
+/**
+ *
+ * @author codex
+ */
+public class FrameBufferParam extends ValueRenderParam {
+
+ private boolean copyColor, copyDepth, copyStencil;
+
+ public FrameBufferParam(String name, boolean copyColor, boolean copyDepth, boolean copyStencil) {
+ super(name);
+ this.copyColor = copyColor;
+ this.copyDepth = copyDepth;
+ this.copyStencil = copyStencil;
+ }
+ public FrameBufferParam(String name, FrameBuffer value, boolean copyColor, boolean copyDepth, boolean copyStencil) {
+ super(name, value);
+ this.copyColor = copyColor;
+ this.copyDepth = copyDepth;
+ this.copyStencil = copyStencil;
+ }
+
+ public boolean isCopyColor() {
+ return copyColor;
+ }
+ public boolean isCopyDepth() {
+ return copyDepth;
+ }
+ public boolean isCopyStencil() {
+ return copyStencil;
+ }
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
index 2dbed3a29d..baf85f4893 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FrameGraph.java
@@ -66,20 +66,20 @@ public class FrameGraph {
private static final Logger logger = Logger.getLogger(FrameGraph.class.getName());
- private final FGRenderContext renderContext;
+ private final RenderContext renderContext;
private final ArrayList passes;
private final ArrayList globalSources;
private final ArrayList globalSinks;
private boolean finalized = false;
- public FrameGraph(FGRenderContext renderContext) {
+ public FrameGraph(RenderContext renderContext) {
passes = new ArrayList<>();
globalSinks = new ArrayList<>();
globalSources = new ArrayList<>();
this.renderContext = renderContext;
}
- public FGRenderContext getRenderContext() {
+ public RenderContext getRenderContext() {
return renderContext;
}
@@ -87,12 +87,12 @@ public FGRenderContext getRenderContext() {
* Binding input resources to the global sink in a FrameGraph refers to making certain resources available globally to all passes.
*/
protected void linkGlobalSinks() {
- for(FGSink sink : globalSinks){
- String linkPassName = sink.getLinkPassName();
+ for(FGSink s : globalSinks){
+ String linkPassName = s.getLinkPassName();
for(FGPass p : passes){
if(p.getName().equals(linkPassName)){
- FGSource source = p.getSource(sink.getLinkPassResName());
- sink.bind(source);
+ FGSource source = p.getSource(s.getLinkPassResName());
+ s.bind(source);
break;
}
}
@@ -175,8 +175,8 @@ protected void linkSinks(FGPass pass) {
*/
public void execute() {
assert finalized;
- for(FGPass nextPass : passes){
- nextPass.execute(renderContext);
+ for(FGPass p : passes){
+ p.execute(renderContext);
}
finalized = false;
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FramebufferSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FramebufferSource.java
index 6a70fa6965..5ce894fc5d 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FramebufferSource.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/FramebufferSource.java
@@ -52,7 +52,7 @@ public FrameBuffer getFrameBuffer() {
return frameBuffer;
}
@Override
- public void bind(FGRenderContext renderContext) {}
+ public void bind(RenderContext renderContext) {}
}
public FramebufferSource(String name, FrameBuffer frameBuffer) {
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderTargetSource.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MatParamSink.java
similarity index 59%
rename from jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderTargetSource.java
rename to jme3-core/src/main/java/com/jme3/renderer/framegraph/MatParamSink.java
index e558d8ff50..af8613ffa8 100644
--- a/jme3-core/src/main/java/com/jme3/renderer/framegraph/FGRenderTargetSource.java
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MatParamSink.java
@@ -31,53 +31,40 @@
*/
package com.jme3.renderer.framegraph;
+import com.jme3.material.Material;
+import com.jme3.shader.VarType;
import com.jme3.texture.FrameBuffer;
-import com.jme3.texture.Texture;
-public class FGRenderTargetSource extends AbstractFGSource {
+public class MatParamSink extends BindableSink {
- RenderTargetSourceProxy renderTargetSourceProxy;
+ private final Material material;
+ private final VarType type;
+ private Object value;
- public final static class RenderTargetSourceProxy implements FGBindable {
- FrameBuffer.FrameBufferTextureTarget renderTarget;
-
- public RenderTargetSourceProxy(FrameBuffer.FrameBufferTextureTarget renderTarget) {
- this.renderTarget = renderTarget;
- }
-
- /**
- * return RT.
- * @return
- */
- public FrameBuffer.FrameBufferTextureTarget getRenderTarget() {
- return renderTarget;
- }
-
- /**
- * return RT shaderResource.
- * @return
- */
- public Texture getShaderResource(){
- return renderTarget.getTexture();
- }
-
- @Override
- public void bind(FGRenderContext renderContext) {}
-
- }
- public FGRenderTargetSource(String name, FrameBuffer.FrameBufferTextureTarget renderTarget) {
+ public MatParamSink(String name, Material material, VarType type) {
super(name);
- renderTargetSourceProxy = new RenderTargetSourceProxy(renderTarget);
+ this.material = material;
+ this.type = type;
}
@Override
- public void postLinkValidate() {
-
+ public void bind(FGSource src) {
+ FGBindable p = src.yieldBindable();
+ if(p == null){
+ System.err.println("Binding input [" + getRegisteredName() + "] to output [" + getLinkPassName() + "." + getLinkPassResName() + "] " + " { " + src.getName() + " } ");
+ return;
+ }
+ linked = true;
+ value = ()((FGShaderResource)p).getResource();
+ //bindableProxy.targetBindable = proxy;
+ target = this;
}
-
+
@Override
- public FGBindable yieldBindable() {
- return renderTargetSourceProxy;
+ public void bind(RenderContext context) {
+ if (material != null && getRegisteredName() != null) {
+ material.setParam(getRegisteredName(), type, value);
+ }
}
}
diff --git a/jme3-core/src/main/java/com/jme3/renderer/framegraph/MatRenderParam.java b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MatRenderParam.java
new file mode 100644
index 0000000000..a63a13a169
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/renderer/framegraph/MatRenderParam.java
@@ -0,0 +1,46 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package com.jme3.renderer.framegraph;
+
+import com.jme3.material.Material;
+import com.jme3.shader.VarType;
+
+/**
+ *
+ * @author codex
+ * @param
+ */
+public class MatRenderParam